我最近开始学习除基本插入和选择之外的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语句时,我从查询一获得结果-没有更多的最大分数,只是学生,主题和每个主题的分数。
如果有人可以说出我的缺失,我将不胜感激:)
答案 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
它给出以下结果
这是我想要达到的目标,但有一个例外-如果学生在多个科目中获得相同的分数,它将显示所有科目-没关系,但我决定将其限制为每个学生的第一个成绩-我无法只是简单地把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
有结果