學生表 Student、成績表 SC。查詢每位學生平均分並排名,處理同分同名次 (密集排名) 與同分留空名次 (競爭排名) 兩種業務規則。
Student (S#, Sname, Sage, Ssex)
SC (S#, C#, score)
SELECT t1.*,
px = (SELECT COUNT(1)
FROM (
SELECT m.S# AS 學生編號,
m.Sname AS 學生姓名,
ISNULL(CAST(AVG(score) AS DECIMAL(18,2)), 0) AS 平均成績
FROM Student m
LEFT JOIN SC n ON m.S# = n.S#
GROUP BY m.S#, m.Sname
) t2
WHERE 平均成績 > t1.平均成績) + 1
FROM (
SELECT m.S# AS 學生編號,
m.Sname AS 學生姓名,
ISNULL(CAST(AVG(score) AS DECIMAL(18,2)), 0) AS 平均成績
FROM Student m
LEFT JOIN SC n ON m.S# = n.S#
GROUP BY m.S#, m.Sname
) t1
ORDER BY px;
SELECT t1.*,
px = (SELECT COUNT(DISTINCT 平均成績)
FROM (
SELECT m.S# AS 學生編號,
m.Sname AS 學生姓名,
ISNULL(CAST(AVG(score) AS DECIMAL(18,2)), 0) AS 平均成績
FROM Student m
LEFT JOIN SC n ON m.S# = n.S#
GROUP BY m.S#, m.Sname
) t2
WHERE 平均成績 >= t1.平均成績)
FROM (
SELECT m.S# AS 學生編號,
m.Sname AS 學生姓名,
ISNULL(CAST(AVG(score) AS DECIMAL(18,2)), 0) AS 平均成績
FROM Student m
LEFT JOIN SC n ON m.S# = n.S#
GROUP BY m.S#, m.Sname
) t1
ORDER BY px;
SELECT S#, Sname,
AVG(CAST(score AS DECIMAL(18,2))) OVER (PARTITION BY S#) AS 平均成績,
RANK() OVER (ORDER BY AVG(score) DESC) AS 競爭排名, -- 1,2,2,4
DENSE_RANK() OVER (ORDER BY AVG(score) DESC) AS 密集排名 -- 1,2,2,3
FROM Student s
LEFT JOIN SC sc ON s.S# = sc.S#
GROUP BY S#, Sname;
優勢:可讀性高、效能優 (單掃描)、無需重複衍生表。
| 函數 | 行為 | 範例序列 |
|---|---|---|
ROW_NUMBER() | 嚴格遞增 1,2,3,4 (不處理同分) | 1,2,3,4 |
RANK() | 競爭排名 (同分留空) | 1,2,2,4 |
DENSE_RANK() | 密集排名 (同分不留空) | 1,2,2,3 |
NTILE(n) | 分桶 (如四分位數) | 1,1,2,2 |
SQL Server 2000/2005 專案維護期可用子查詢寫法;新專案請直接使用窗口函數,符合 ANSI SQL 標準且效能最佳。