如何让查询返回行值的样本作为列?

dra*_*aca 5 sql sql-server

给出一个名为"grade"的表:

STUDENT  GRADE
john     94
john     76
john     83
john     87
john     90
Run Code Online (Sandbox Code Playgroud)

我想要一个查询来返回每个学生的几个成绩示例,例如:

STUDENT    GRADE1  GRADE2   GRADE3  GRADE4
John       94      76       83      87
Run Code Online (Sandbox Code Playgroud)

请注意,只返回了4个样本成绩列,但该学生的成绩超过4个.

我只知道如何使用GROUP BY子句中的min()和max()函数返回2个示例等级:

select student, min(grade), max(grade) 
from grades
group by student
Run Code Online (Sandbox Code Playgroud)

除了min/max之外,是否有任何技巧或功能可以使用GROUP BY子句显示超过2个等级?

除非它是查询的一部分而不是存储在数据库中,否则我宁愿不编写自己的存储函数来执行此操作.

我想更多的函数除了MIN和MAX之外还从记录集返回其他值(比如第二高,第三高等).

想法?

Tar*_*ryn 6

您可以通过应用row_number()函数然后应用PIVOT 来获得结果:

select student, 
  grade1 = [1], 
  grade2 = [2], 
  grade3 = [3], 
  grade4 = [4]
from
(
  select student, grade,
    row_number() over(partition by student
                      order by grade desc) seq
  from grades
) d
pivot
(
  max(grade)
  for seq in ([1], [2], [3], [4]) -- the # of grades you want returned
) piv;
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo.

PIVOT中使用的新列名称将是您想要返回的等级数.该ORDER BY分区中的使用感是grade desc的,但你也可以看看使用order by newid()即可返回随机结果.

这也可以使用带有CASE表达式的聚合函数来完成:

select student,
  max(case when seq = 1 then grade end) grade1,
  max(case when seq = 2 then grade end) grade2,
  max(case when seq = 3 then grade end) grade3,
  max(case when seq = 4 then grade end) grade4
from
(
  select student, grade,
    row_number() over(partition by student
                      order by newid()) seq
  from grades
) d
group by student;
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo


Fed*_*ico 0

我提出这样的建议。唯一的限制是您不能显示示例 1 到 n,您只能显示确定的数量。

SELECT DISTINCT student, 
(
    select top 1 grade from
    (select grade, ROW_NUMBER() OVER(ORDER BY grade DESC) AS Row from grades g2 where g.student = g2.student) a where a.Row = 1
) AS GRADE1  ,
(
    select top 1 grade from
    (select grade, ROW_NUMBER() OVER(ORDER BY grade DESC) AS Row from grades g2 where g.student = g2.student) a where a.Row = 2
) AS GRADE2,
(
    select top 1 grade from
    (select grade, ROW_NUMBER() OVER(ORDER BY grade DESC) AS Row from grades g2 where g.student = g2.student) a where a.Row = 3
) AS GRADE3,
(
    select top 1 grade from
    (select grade, ROW_NUMBER() OVER(ORDER BY grade DESC) AS Row from grades g2 where g.student = g2.student) a where a.Row = 4
) AS GRADE4
from grades g
Run Code Online (Sandbox Code Playgroud)

带光标。在此解决方案中,您将得到 1 到 n 个结果

DECLARE @grade int
DECLARE @n int

DECLARE @sql varchar(max)

DECLARE _cursor CURSOR FOR 
     SELECT grade
     FROM grade
     WHERE student like 'XXX'

OPEN _cursor
FETCH NEXT FROM _cursor INTO @grade
WHILE @@FETCH_STATUS = 0
BEGIN
    IF @sql like ''
    begin
         set @sql = 'SELECT ' + 'XXX' + ' AS Student '
    end
    set @sql = @sql + ',' + @grade ' as GRADE'+  @n
    set @n = @n + 1
END

CLOSE _cursor
DEALLOCATE _cursor

exec(@sql)
Run Code Online (Sandbox Code Playgroud)

这个输出将是

STUDENT    GRADE1  GRADE2   GRADE3  GRADE4
John       94      87       83      76
Run Code Online (Sandbox Code Playgroud)