如何从 GROUPs COUNT 中获取 MAX 值

Posted

技术标签:

【中文标题】如何从 GROUPs COUNT 中获取 MAX 值【英文标题】:How to get MAX value out of the GROUPs COUNT 【发布时间】:2019-04-20 16:58:03 【问题描述】:

我最近开始学习基本插入和选择之外的 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

部分查询1结果

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

问题是,当我添加到 select 语句中的主题名称时,我得到了来自查询一的结果 - 没有更多的最大分数,只有学生、科目和每个科目的分数。

如果有人能说出我所缺少的,我将不胜感激:)

【问题讨论】:

如果您正在学习 SQL,请学习使用正确、明确、标准 JOIN 语法。 【参考方案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

等等

这也是你应该如何进行连接

它是如何工作的?好吧..它建立了一个递增计数器,每次 studentid 更改时都会重新启动(分区子句),并且 numberin 以 des 结束标记顺序(order by 子句)进行。外部查询只选择行号为 1 的行,即每个学生的最高分

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

您可以,但您必须编写一个查询,将分数表汇总为每个学生的最高分数(最大值),然后您必须将该数据连接回分数表以检索主题,并且其中的所有内容都很多更多faff,通常效率更低

如果有两个科目的分数相同怎么办?

如果您想同时查看两者,请使用 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

我们按学生/科目计算分数,然后按每个学生-科目对的计数降序排列它们,然后只选择第一行并加入其他想要的数据

【讨论】:

感谢您的回答,我学到了一点关于 over 和 partition by 的知识,但我实际上问的是稍微不同的事情,我想为每个学生,他从中获得最大 AMOUNT 的科目标记而不是最高标记,所以前。学生 A 从 subject1 获得 3、4、5,从 subject2 获得 5、2 - 所以结果表包含 (studentA | subject1 | 3) 在答案中添加了更多信息,见底部。【参考方案2】:

好的,感谢 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

它给出以下结果

这就是我想要实现的目标,但有一个例外 - 如果学生在多个科目中获得相同数量的分数,它会显示所有科目 - 很好,但我决定将此限制为每个学生的第一个结果 - 我不能只是简单地把 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

有结果

【讨论】:

这实际上是我们在 row_number 发明之前必须做的事情:对数据进行分组和计数,将其加入主数据,将其分组并最大化,将其重新加入等。使用窗口函数它变得更容易纯粹是因为“加入它”是隐式完成的 - 将其视为像 max(age) over(partition by class,school) 这样的窗口函数,相当于 (student join (select class max(age)from student group by class) a on student.class = a.class) - db 计算每个类的最大年龄并将结果放入每一行就像一张在这张桌子上加入到组的表格会

以上是关于如何从 GROUPs COUNT 中获取 MAX 值的主要内容,如果未能解决你的问题,请参考以下文章

JQuery 从 JSON 数组中获取数据

如何在 asdict 中获取@property 方法?

从 GROUP BY 中获取 MAX

如何在php中从数据库中的数组中添加多行

GROUPS 和 NULL 的 COUNT 不等于表中的总行数

如何在fuelPHP Orm模型中选择MAX或COUNT