如何从GROUPS COUNT中获得最大价值

时间:2018-11-17 21:53:09

标签: sql sql-server tsql aggregate-functions

我最近开始学习除基本插入和选择之外的tsql,我拥有要训练的测试数据库,并且有一个查询我无法真正使用。

该查询中使用了3个表,图中有简化的字段和关系

我有2个以下查询-第一个查询只是显示学生和每个学科的分数。其次,几乎是我想达到的目标-向学生展示他们所获得的最高分数,因此,例如。 subject1 -(标记)1、5、3、4个计数-4 subject2 -(标记)5、4、5-计数-3 查询显示4,根据我检查的结果返回正确的结果,但是我还想做一件事-仅显示最大标记数的主题名称,因此在示例情况下- subject1

--Query 1--
SELECT s.Surname, subj.SubjectName, COUNT(m.Mark) as Marks_count
FROM marks m, students s, subjects subj
WHERE m.StudentId = s.StudentNumber and subj.SubjectNumber = m.SubjectId
GROUP BY s.Surname, subj.SubjectName
ORDER BY s.Surname

--Query 2--

SELECT query.Surname, MAX(Marks_count) as Maximum_marks_count FROM (SELECT s.Surname, subj.SubjectNumber, COUNT(m.Mark) as Marks_count
                                    FROM marks m, students s, subjects subj
                                    WHERE marks.StudentId = s.StudentNumber and subj.SubjectNumber = m.SubjectId
                                    GROUP BY s.Surname, subj.SubjectName) as query
GROUP BY query.Surname
ORDER BY query.Surname


--Query 3 - not working as supposed--
SELECT query.Surname, query.SubjectName, MAX(Marks_count) as Maximum_marks_count FROM (SELECT s.Surname, subj.SubjectNumber, COUNT(m.Mark) as Marks_count
                                    FROM marks m, students s, subjects subj
                                    WHERE marks.StudentId = s.StudentNumber and subj.SubjectNumber = m.SubjectId
                                    GROUP BY s.Surname, subj.SubjectName) as query
GROUP BY query.Surname, query.SubjectName
ORDER BY query.Surname

Part of the query 1 result

部分查询1个结果

Part of the query 2 and unfortunately query 3 result

部分查询2,不幸的是查询3结果

问题是,当我将选择主题名称添加到select语句时,我从查询一获得结果-没有更多的最大分数,只是学生,主题和每个主题的分数。

如果有人可以说出我的缺失,我将不胜感激:)

2 个答案:

答案 0 :(得分:1)

这是一个查询,该查询在每个学生中得分最高,将其放在sql文件/批处理的顶部,它将创建另一个“表”,您可以将其连接到其他表以获取学生名和主题名:

WITH studentBest as 
SELECT * FROM(
  SELECT *, ROW_NUMBER() OVER(PARTITION BY studentid ORDER BY mark DESC) rown  
  FROM marks) a 
WHERE rown = 1)

您可以像这样使用它

--the WITH bit goes above this line
SELECT *
FROM
  studentBest sb 
  INNER JOIN
  subject s
  ON sb.subjectid = s.subjectnumber

这也是您应该进行加入的方式

它如何工作?嗯..它建立了一个递增计数器,每当学生ID更改时(分区子句),并且numberin按des结束标记顺序(order by子句)重新启动。外部查询仅选择行号为1的那些行,即每个学生的最高分

为什么不能使用分组依据?

您可以,但是您必须编写一个查询,将成绩表汇总为每个学生的最高成绩(最高),然后必须将该数据重新加入成绩表以检索主题,并且这很多人流量更多,效率通常更低

如果两个主题都具有相同的标记怎么办?

如果要同时查看两者,请使用RANK而不是ROW_NUMBER

根据您的评论进行编辑:

上述方法的扩展:

SELECT * FROM
(
  SELECT *, ROW_NUMBER() OVER(PARTITION BY su, st ORDER BY c DESC) rn FROM
  (
    SELECT studentid st, subjectid su, count(*) c
    FROM marks
    GROUP BY st, su
  ) a
) b
INNER JOIN student stu  on b.st = stu.studentnumber
INNER JOIN subject sub on b.su = sub.subjectnumber
WHERE
  b.rn = 1

我们按学生/科目计数分数,然后按学生/科目对计数的降序对行进行编号,然后仅选择第一行并加入其他所需数据

答案 1 :(得分:0)

好吧,感谢 Caius Jard ,其他一些Stack的问题以及我设法写出有效查询的一些实验,所以这就是我的方法。

首先,我从query1创建了视图,并在其中添加了另一列-studentId。 然后我写了几乎令我满意的查询。这个问题对我的工作很有帮助:Question

SELECT  marks.Surname,
    marks.SubjectName,
    marks.Marks_count,
    ROW_NUMBER() OVER(PARTITION BY marks.Surname ORDER BY marks.Surname) as RowNum
FROM MarksAmountPerStudentAndSubject marks
INNER JOIN (SELECT MarksAmountPerStudentAndSubject.Id, 
            MAX(MarksAmountPerStudentAndSubject.Marks_count) as MaxAmount
        FROM MarksAmountPerStudentAndSubject
        GROUP BY MarksAmountPerStudentAndSubject.Id) m
ON m.Id = marks.Id and marks.Marks_count = m.MaxAmount

它给出以下结果

enter image description here

这是我想要达到的目标,但有一个例外-如果学生在多个科目中获得相同的分数,它将显示所有科目-没关系,但我决定将其限制为每个学生的第一个成绩-我无法只是简单地把TOP(1) 因此,我使用了 Caius Jard 显示的类似解决方案-ROW_NUMBER和窗口函数-它使我有机会选择行号等于1的记录。 我从该查询创建了另一个视图,我可以简单地编写最后一个视图

SELECT marks.Surname, marks.SubjectName, marks.Marks_count
FROM StudentsMaxMarksAmount marks
WHERE marks.RowNum = 1
ORDER BY marks.Surname

有结果

enter image description here