计算每所学校的前三个最高GPA

时间:2019-04-11 11:57:20

标签: sql sql-server

我已经计算出每所学校的学生获得的最高GPA。但是,如何获得每所学校的学生为RANK 1, 2, and 3得分最高的3个GPA列表?

SELECT A.*
FROM (
    SELECT B.SCHOOL_NAME
        ,C.STUDENT_NAME
        ,A.SYMBOL_NO
        ,A.AVG_GPA
        ,MAX(A.AVG_GPA) OVER (PARTITION BY B.SCHOOL_NAME) AS MAX_GPA
    FROM TBL_STUDENT_MARKS A
    INNER JOIN TBL_SCHOOL B ON A.SCHOOL_ID = B.SCHOOL_ID
    INNER JOIN TBL_STUDENT_INFO C ON A.SYMBOL_NO = C.SYMBOL_NO
        AND B.SCHOOL_ID = C.SCHOOL_ID
    ) A
WHERE A.AVG_GPA = MAX_GPA
ORDER BY A.AVG_GPA DESC;

5 个答案:

答案 0 :(得分:1)

您可以结合使用DENSE_RANK()PARTITION BY

DENSE_RANK() OVER (
    PARTITION BY <expr1>[{,<expr2>...}]
    ORDER BY <expr1> [ASC|DESC], [{,<expr2>...}]
)

在这种情况下,类似

DENSE_RANK() OVER (PARTITION BY B.SCHOOL_NAME ORDER BY AVG_GPA desc) AS SCHOOL_RANK

,然后在外部查询中添加

WHERE SCHOOL_RANK in (1, 2, 3)

查看常用表表达式!我发现它通常比嵌套SELECT更好。

WITH ranked as (
    SELECT 
        SCHOOL_ID 
        , SYMBOL_NO
        , AVG_GPA
        , DENSE_RANK() OVER (PARTITION BY SCHOOL_ID ORDER BY AVG_GPA DESC) AS SCHOOL_RANK 
    FROM TBL_STUDENT_MARKS
)
SELECT 
    SC.SCHOOL_NAME
    , INFO.STUDENT_NAME
    , ST.SYMBOL_NO
    , ST.AVG_GPA
    , ST.SCHOOL_RANK 
FROM ranked ST
INNER JOIN TBL_SCHOOL SC ON R.SCHOOL_ID = SC.SCHOOL_ID
INNER JOIN TBL_STUDENT_INFO INFO ON ST.SYMBOL_NO = INFO.SYMBOL_NO AND SC.SCHOOL_ID = INFO.SCHOOL_ID
WHERE SCHOOL_RANK <= 3
ORDER BY SCHOOL_NAME, SCHOOL_RANK;

答案 1 :(得分:1)

您可以使用RANK()或DENSE_RANK()或ROW_NUMBER()来获得结果。 但是,在这种情况下,最好使用RANK()和DENSE_RANK()。

RANK():

SELECT A.*
FROM (
    SELECT B.SCHOOL_NAME
         ,C.STUDENT_NAME
         ,A.SYMBOL_NO
         ,A.AVG_GPA
         ,RANK() OVER (PARTITION BY B.SCHOOL_NAME ORDER BY A.AVG_GPA DESC) AS SCHOOL_RANK
    FROM TBL_STUDENT_MARKS A
    INNER JOIN TBL_SCHOOL B ON A.SCHOOL_ID = B.SCHOOL_ID
    INNER JOIN TBL_STUDENT_INFO C ON A.SYMBOL_NO = C.SYMBOL_NO AND B.SCHOOL_ID = C.SCHOOL_ID
) A
WHERE SCHOOL_RANK <= 3
ORDER BY SCHOOL_NAME, SCHOOL_RANK

DENSE_RANK():

SELECT A.*
FROM (
    SELECT B.SCHOOL_NAME
         ,C.STUDENT_NAME
         ,A.SYMBOL_NO
         ,A.AVG_GPA
         ,DENSE_RANK() OVER (PARTITION BY B.SCHOOL_NAME ORDER BY A.AVG_GPA DESC) AS SCHOOL_DENSE_RANK
    FROM TBL_STUDENT_MARKS A
    INNER JOIN TBL_SCHOOL B ON A.SCHOOL_ID = B.SCHOOL_ID
    INNER JOIN TBL_STUDENT_INFO C ON A.SYMBOL_NO = C.SYMBOL_NO AND B.SCHOOL_ID = C.SCHOOL_ID
) A
WHERE SCHOOL_DENSE_RANK<= 3
ORDER BY SCHOOL_NAME, SCHOOL_DENSE_RANK

ROW_NUMBER():

SELECT A.*
FROM (
    SELECT B.SCHOOL_NAME
         ,C.STUDENT_NAME
         ,A.SYMBOL_NO
         ,A.AVG_GPA
         ,ROW_NUMBER() OVER (PARTITION BY B.SCHOOL_NAME ORDER BY A.AVG_GPA DESC) AS SCHOOL_ROW_NUMBER
    FROM TBL_STUDENT_MARKS A
    INNER JOIN TBL_SCHOOL B ON A.SCHOOL_ID = B.SCHOOL_ID
    INNER JOIN TBL_STUDENT_INFO C ON A.SYMBOL_NO = C.SYMBOL_NO AND B.SCHOOL_ID = C.SCHOOL_ID
) A
WHERE SCHOOL_ROW_NUMBER <= 3
ORDER BY SCHOOL_NAME, SCHOOL_ROW_NUMBER

有关排名,DenseRank和行号之间的区别,请参考here

答案 2 :(得分:0)

MAX()窗口函数替换为DENSE_RANK()

SELECT A.*
FROM (
    SELECT B.SCHOOL_NAME
         , C.STUDENT_NAME
         , A.SYMBOL_NO
         , A.AVG_GPA
         , DENSE_RANK() OVER (PARTITION BY B.SCHOOL_NAME ORDER BY A.AVG_GPA DESC) AS RANK_BY_SCHOOL
    FROM TBL_STUDENT_MARKS A
    INNER JOIN TBL_SCHOOL B ON A.SCHOOL_ID = B.SCHOOL_ID
    INNER JOIN TBL_STUDENT_INFO C ON A.SYMBOL_NO = C.SYMBOL_NO AND B.SCHOOL_ID = C.SCHOOL_ID
) A
WHERE RANK_BY_SCHOOL <= 3
ORDER BY SCHOOL_NAME, RANK_BY_SCHOOL;

答案 3 :(得分:0)

您可以使用ROW_NUMBER() OVER (PARTITION BY B.SCHOOL_NAME ORDER BY A.AVG_GPA DESC)

SELECT A.*
FROM (
    SELECT B.SCHOOL_NAME
        ,C.STUDENT_NAME
        ,A.SYMBOL_NO
        ,A.AVG_GPA
        ,ROW_NUMBER() OVER (PARTITION BY B.SCHOOL_NAME ORDER BY A.AVG_GPA DESC) 
         AS HIGHEST_GPA
    FROM TBL_STUDENT_MARKS A
    INNER JOIN TBL_SCHOOL B ON A.SCHOOL_ID = B.SCHOOL_ID
    INNER JOIN TBL_STUDENT_INFO C ON A.SYMBOL_NO = C.SYMBOL_NO
        AND B.SCHOOL_ID = C.SCHOOL_ID
    ) A
WHERE HIGHEST_GPA <= 3
ORDER BY A.AVG_GPA DESC;

答案 4 :(得分:0)

使用Dense_rank窗口功能:

 select  * 
    from(SELECT A.*,DENSE_RANK()over(partition by school_name order by MAX_GPA 
 desc)as  rankno
FROM (
    SELECT B.SCHOOL_NAME
           ,C.STUDENT_NAME
           ,A.SYMBOL_NO
           ,A.AVG_GPA
           ,MAX(A.AVG_GPA) OVER (PARTITION BY B.SCHOOL_NAME) AS MAX_GPA
     FROM TBL_STUDENT_MARKS A
     INNER JOIN TBL_SCHOOL B ON A.SCHOOL_ID = B.SCHOOL_ID
     INNER JOIN TBL_STUDENT_INFO C ON A.SYMBOL_NO = C.SYMBOL_NO
     AND B.SCHOOL_ID = C.SCHOOL_ID
     ) A

A.AVG_GPA = MAX_GPA)B WHERE Rankno IN(1,2,3);