首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL 排名函數實戰:用自我聯結實現銷售排序與 Top-N 查詢

     編輯:關於SqlServer

在早期不支援窗口函數的 SQL 版本中,利用「自我聯結 + 聚合計數」是實現排名的經典技巧。本文以銷售資料為例,示範如何撰寫排名查詢,並延伸至「查詢第 N 名」的進階寫法。

一、範例資料與需求

假設資料表 Total_Sales 包含兩欄:Name(業務員)、Sales(業績)。需求:依 Sales 降冪排序,產生 Sales_Rank 排名欄位。

二、核心邏輯:自我聯結計算「不小於自己的人數」

-- 寫法 A:允許同分同排名(密集排名 Dense Rank 效果)
SELECT a1.Name, a1.Sales, COUNT(a2.Sales) AS Sales_Rank
FROM Total_Sales a1
JOIN Total_Sales a2
  ON a1.Sales <= a2.Sales 
     OR (a1.Sales = a2.Sales AND a1.Name = a2.Name)  -- 同分時以 Name 破 tie
GROUP BY a1.Name, a1.Sales
ORDER BY a1.Sales DESC, a1.Name DESC;

原理說明:對每一筆 a1,去數有多少筆 a2 的業績「大於或等於」它。計數結果即為排名。若業績相同、名字也相同,視為同一筆資料,避免重複計數。

三、變體:跳過排名

-- 寫法 B:同分不佔排名(競爭排名 Rank 效果,如 1,2,2,4)
SELECT a1.Name, a1.Sales, COUNT(a2.Sales) AS Sales_Rank
FROM Total_Sales a1
JOIN Total_Sales a2
  ON a1.Sales < a2.Sales 
     OR (a1.Sales = a2.Sales AND a1.Name = a2.Name)
GROUP BY a1.Name, a1.Sales
ORDER BY a1.Sales DESC, a1.Name DESC;

差別在於 <= 改為 <,同分者不會互相計數,導致排名出現間隙。

四、進階應用:查詢第 5 名

SELECT * FROM (
    SELECT a1.Name, a1.Sales, COUNT(a2.Sales) AS Sales_Rank
    FROM Total_Sales a1
    JOIN Total_Sales a2
      ON a1.Sales < a2.Sales OR (a1.Sales = a2.Sales AND a1.Name = a2.Name)
    GROUP BY a1.Name, a1.Sales
) AS ranked
WHERE Sales_Rank = 5;

五、現代寫法建議(SQL Server 2012+ / PostgreSQL / MySQL 8.0+)

若資料庫支援窗口函數,請直接使用 RANK()、DENSE_RANK()、ROW_NUMBER(),語法更簡潔、效能更佳:

SELECT Name, Sales, 
       RANK() OVER (ORDER BY Sales DESC) AS Sales_Rank
FROM Total_Sales;

自我聯結排名雖屬經典技巧,但在大量資料下效能較差(O(N²)),實務上請優先考慮窗口函數或資料庫原生排名功能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved