用于获取最高标记的SQL查询

时间:2018-05-12 12:53:41

标签: sql sql-server

表结构如下:

  • Student(StudentID int,StudentName varchar(20))
  • Subject(SubjectID int,SubjectName varchar(20))
  • Score(ScoreID int,StudentID int,SubjectID int,Score int)

这是数据

Student
| StudentID | StudentName |
|    1      |    John     |
|    2      |    Nash     |
|    3      |    Albert   |
---------------------------

Subject
| SubjectID | SubjectName |
|    1      |    Maths    |
|    2      |    Physics  |
|    3      |    Chemistry|
|    4      |    English  |
---------------------------

Score
| ScoreID | StudentID | SubjectID | Score |  
|     1   |     1     |     1     |   34  |
|     2   |     1     |     2     |   45  |
|     3   |     1     |     3     |   56  |
|     4   |     2     |     1     |   78  |
|     5   |     2     |     3     |   23  |
|     6   |     2     |     4     |   44  |
|     7   |     3     |     1     |   45  |
|     8   |     3     |     2     |   10  |
|     9   |     3     |     3     |   54  |
|    10   |     3     |     4     |   74  |
-------------------------------------------

Output:
|StudentName | Score | SubjectName |
|  John      |   45  |   Physics   |
|  John      |   56  |   Chemistry |
|  Nash      |   78  |   Maths     |
|  Albert    |   74  |   English   |
------------------------------------

我想写一个查询来获取每个主题的最佳得分手及其得分和主题名称,而不使用Row_Number(),Rank()和Dense_Rank()。

我写了这个查询,但我认为可以改进:

select
    st.StudentName, Score, B.SubjectID
from 
    (select
         StudentID, Sc.SubjectID, Sc.Score
     from 
         (select
              SubjectID, MAX(Score) as 'Score'
          from 
              Score Sc
          inner join 
              subject sb on sc.subjectid = sb.subjectid
          group by 
              SubjectID) A
     inner join
         score sc on sc.SubjectID = a.SubjectID and sc.Score = A.Score) B
inner join 
    Student st on st.studentID = B.StudentID

2 个答案:

答案 0 :(得分:1)

您将使用ANSI标准rank()row_number()函数。假设您想要所有重复项,请使用rank()

select StudentName, SubjectName, Score
from (select st.StudentName, su.SubjectName, s.Score,
             rank() over (partition by su.SubjectName order by s.Score desc) as seqnum
      from score s join
           student st
           on s.studentid = st.studentid join
           subject su
           on s.subjectid = su.subjectid 
     ) s
where seqnum = 1;

如果您希望每个主题只有一行,并且有一个任意的优秀学生,请使用row_number()

在SQL Server中,您也可以在没有子查询的情况下执行此操作:

select top (1) with ties st.StudentName, su.SubjectName, s.Score
from score s join
     student st
     on s.studentid = st.studentid join
     subject su
     on s.subjectid = su.subjectid 
order by rank() over (partition by su.SubjectName order by s.Score desc)

另一个有趣的选项是apply - 这不使用窗口函数,并且可以有相当不错的性能:

select ss.StudentName, su.SubjectName, ss.Score
from subject su cross apply
     (select top (1) with ties s.*
      from score s join
           student st
           on s.studentid = st.studentid join
      where s.subjectid = su.subjectid 
      order by su.score desc
     ) ss;

答案 1 :(得分:1)

这是一个不使用RANK或ROW_NUMBER的解决方案。这也是为了满足您的输出而大大简化的。希望它有所帮助

SELECT st.StudentName ,s.Score ,su.SubjectName  FROM (SELECT
SubjectID,MAX(Score) as Max   FROM Score GROUP BY SubjectID) a
INNER JOIN Score s  on a.SubjectID=s.SubjectID AND a.MAX=s.Score
INNER JOIN Student st on s.StudentID=st.StudentID 
INNER JOIN Subject su on s.SubjectID=su.SubjectID