How to find Average of student's grades using the last grade he got at a subject in case he got more

huangapple go评论58阅读模式
英文:

How to find Average of student's grades using the last grade he got at a subject in case he got more

问题

我有两张表,一张是Grades,一张是StudentsGrades表有一个Student列,它是一个外键,引用了Student.Id

学生在不同科目上有多个成绩,有些学生在某个科目上有多个成绩。如果一个学生在某个科目上有多个成绩,我该如何计算这些成绩的平均值,仅使用他在每个科目上获得的最后一个成绩,而不使用所有成绩?

例如,如果一个学生有Maths=3,History=5,Physics=4,History=7,我希望只使用Maths(3)、Physics(4)和最后一个History(7)来计算平均值,而不包括History(5)。

如图所示,我有一个包含姓名、组、位置的学生表和一个包含这些成绩的成绩表。我想计算这些成绩的平均值,但如果同一科目有多个成绩,应使用该科目的最后一个成绩。在这种情况下,平均值应为French(9) + Maths(10) + 物理学的最后一次成绩,即5的平均值。

对不起,我只是不知道该怎么做。我是新手,不熟悉关系数据库、外键等。

到目前为止,我考虑使用ID来区分成绩。因此,物理学4是该学生的第一个成绩,它的ID为1,而物理学5是他在物理学中获得的最后一个成绩,它的ID为7。因此,要获取该科目的最后一个成绩,应选择具有较高ID号的成绩,但我无法弄清楚如何做到这一点。

英文:

I have two tables, one for Grades and one for Students. The Grades table has a column Student which is a foreign key referencing to Student.Id.

Students have multiple grades at different subjects and some of the students have more than one grade at a subject. If a student has more than one grade at a subject, how can I do the general average of those grades using only the last grade he got at each subject, rather than all grades?

For example, if a student has Maths=3,History=5,Physics=4,History=7 I want to do the average using only Maths(3),Physics(4) and the last History(7), without the History(5).

How to find Average of student's grades using the last grade he got at a subject in case he got more

As you can see in that image, i have a Students table with Name, Group, Location and a Grades table that have those grades. I want to do the average of those grades but in case there are more than 1 grad at the same subject the last grade at that subject should be used. In this case the avg should be AVG of French(9) + Maths(10) + the last grade taken at physics which is 5.

I'm sorry i just cant figure out what to do in this case. I am new to using relational databases, foreign keys etc.

So far i thought about using de Id to differentiate the grades. So for Physics 4 which is the first grade of that student it has the id of 1 and the Physics 5 which is the last grade he got at Physics it has the id of 7. So to get the last grade of that subject it should take the one with the higher id number but i can't figure out how to do it.

答案1

得分: 0

使用MAX()函数获取每个科目的最新成绩。然后可以使用AVG()函数计算这些成绩的平均值。

以下是一个示例:

SELECT Students.Name, AVG(Grades.Grade)
FROM Students
JOIN (
    SELECT Student, Subject, MAX(Date) AS LatestDate
    FROM Grades
    GROUP BY Student, Subject
) AS LatestGrades ON Students.Id = LatestGrades.Student
JOIN Grades ON LatestGrades.Student = Grades.Student
    AND LatestGrades.Subject = Grades.Subject
    AND LatestGrades.LatestDate = Grades.Date
GROUP BY Students.Name

希望这对你有帮助。

英文:

use the MAX() function to get the most recent grade for each subject. You can then calculate the average of these grades using the AVG() function.

Here is an example:

    SELECT Students.Name, AVG(Grades.Grade)
FROM Students
JOIN (
    SELECT Student, Subject, MAX(Date) AS LatestDate
    FROM Grades
    GROUP BY Student, Subject
) AS LatestGrades ON Students.Id = LatestGrades.Student
JOIN Grades ON LatestGrades.Student = Grades.Student
    AND LatestGrades.Subject = Grades.Subject
    AND LatestGrades.LatestDate = Grades.Date
GROUP BY Students.Name

答案2

得分: 0

不翻译代码部分,以下是代码之外的内容的翻译:

在假设有一个合理的模式定义(_请在问题中分享包含列名和类型的实际模式定义,而且不要使用图像),您想要类似以下的东西:

这里使用了一个窗口函数来分区并对每个学生/科目的行进行编号,基于日期,这样您可以限制只选择每个分区内的第一行,然后从中取平均值。这应该比需要连接到选择MAX(date)的投影的解决方案性能更好。

请注意,我在回答的开头提到了“合理的模式”。根据图片中的情况(再次强调:图片在视图中被压缩,几乎无法阅读,不要以这种方式发布数据!),一个科目的多个成绩存储在同一列中作为逗号分隔的数据。这被称为不合理的模式设计。在单个列中存储逗号分隔的数据被认为是一种_不正确_的模式设计:需要修复的东西。

另一个重要的事情是理解Date列的使用,这在问题中没有显示。SQL数据库明确声明不对保留记录的任何自然顺序负责。没有插入顺序、表顺序或磁盘顺序这种东西,有很多因素可以导致数据库重新排列磁盘上的记录或以不同的顺序返回行,即使是对相同查询的连续运行也是如此

因此,您必须有一种方式来根据_实际行中的数据_定义“最后的成绩”。即使是按顺序分配的ID也足够了,但我们需要某种东西。否则,_您将无法编写此查询!_是什么使History(7)成为最后,而不是History(5)

英文:

Assuming a reasonable schema definition (please share the actual schema definition with column names and types in the question, and do not use an image to do it), you want something like this:

SELECT s.ID, s.Name, s.[Group], s.Location, AVG(g.Grade)
FROM 
( 
    SELECT Student, Subject, Grade
        ,row_number() over (partition by student, subject order by [ID] desc) rn
    FROM Grades
) g
INNER JOIN Students s ON s.Id = g.Student
WHERE rn = 1
GROUP BY s.ID, s.Name, s.[Group], s.Location

This uses a windowing function to partition and then number rows per student/subject based on the date, so you can then limit to only the first row within each partition and take the average from there. It should tend to perform better than solution which need to JOIN to a projection selecting by the MAX(date).

Note I said "reasonable schema" at the beginning of the answer. There is a concern based on the image (which again: it gets squished in the view and is nearly unreadable — don't post data that way!) that multiple grades for a subject are stored in the same column as comma-separated data. This is what we call an unreasonable schema. Storing comma-separated data in a single column is considered a BROKEN schema design: something that needs to be fixed.

Another important thing to understand is the use of the Date column, which was not shown in the question. SQL databases explicitly disclaim any responsibility for preserving any kind of natural order for your records. There is no such thing as insert order, table order, or disk order, and there are a number of things that can cause a database to reshuffle records on disk or return rows in a different order, even for consecutive runs of the same query.

Therefore, you MUST have a way to define "last grade" in terms of actual data in the rows. Even a sequentially assigned ID would be enough, but we need something. Otherwise, you will not be able to write this query! What is it that makes History(7) be last rather than History(5)?

答案3

得分: 0

I think you have to create a new table first that has the LatestGrades and then create the JOIN. Looks like You don’t even need the subj column in the final output, just an avg score across all subjects for every student.

WITH
Newtable AS 
(SELECT id, subject, grade, MAX(date) as LatestDate
FROM Grades
GROUP BY student, subject)
SELECT Students.id, students.name, AVG (newtable.grade) AS Avggrade
FROM (Newtable FULL JOIN Grades
ON Newtable.id=Grades.id) 
FULL JOIN Students ON students.id=grades.id
英文:

I think you have to create a new table first that has the LatestGrades and then create the JOIN. Looks like You don’t even need the subj column in the final output, just an avg score across all subjects for every student.

WITH
Newtable AS 
(SELECT id, subject,grade, MAX(date) as LatestDate
FROM Grades
GROUP BY student, subject)
SELECT Students.id, students.name, AVG (newtable.grade) AS Avggrade
FROM (Newtable FULLJOIN Grades
ON Newtable.id=Grades.id) 
FULL JOIN Students ON students.id=grades.id

huangapple
  • 本文由 发表于 2023年3月3日 20:24:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/75627045.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定