一、窗口函數語法
窗口函數是整個SQL語句最后被執行的部分,這意味着窗口函數是在SQL查詢的結果集上進行的,因此不會受到Group By, Having,Where子句的影響。
窗口函數的典型范例是我們在SQL Server 2005之后用到的排序函數,比如代碼清單1所示。
Row_Number() OVER (partition by xx ORDER BY xxx desc) RowNumber
因此,我們可以把窗口函數的語法抽象出來,如代碼清單2所示。
函數() Over (PARTITION By 列1,列2,Order By 列3,列4) AS 列別名
二、常用的窗口函數
1、ROW_NUMBER() ----分區行內排序
返回結果集分區內行的序列號,每個分區的第一行從開始。 ORDER BY子句可確定在特定分區中為行分配唯一ROW_NUMBER的順序。
2、RANK() ----排名(間斷)
返回結果集的分區內每行的排名。行的排名是相關行之前的排名數加一。 如果某行與上一行的值一樣,則將得到與上行相同的排名。
3、DENSE_RANK() ----排名(不間斷) 返回結果集分區中行的排名,在排名中沒有任何間斷。行的排名等於所討論行之前的所有排名數加一。
如果有兩個或多個行受同一個分區中排名的約束,則每個約束行將接收相同的排名。
4、NTILE() ----平均分組 將有序分區中的行分發到指定數目的組中。
各個組有編號,編號從一開始。對於每一個行,NTILE 將返回此行所屬的組的編號。
5、LEAD()和LAG(),這是一對比較有趣的分析函數,這兩個分析函數經過Order By子句排序后,可以在當前行訪問上一行(LAG)或下一行(LEAD)的數據。
三、常用的窗口函數的實例
--1、創建測試數據表
CREATE TABLE #TMP_EMP_SALARY (DEPT VARCHAR(10),NAME VARCHAR(10), SALARY INT); INSERT INTO #TMP_EMP_SALARY SELECT '銷售一部','曹操', 10000 UNION ALL SELECT '銷售一部','曹仁', 9000 UNION ALL SELECT '銷售一部','曹洪', 9000 UNION ALL SELECT '銷售一部','許褚', 8000 UNION ALL SELECT '銷售二部','典韋', 8000 UNION ALL SELECT '銷售二部','徐晃', 7000 UNION ALL SELECT '銷售二部','龐德', 6000 ;
--2、查看數據
SELECT * FROM #TMP_EMP_SALARY;
--3、查看所有人的,四個排名函數結果
SELECT DEPT,NAME, SALARY, LAG(SALARY,1,0) OVER(ORDER BY SALARY DESC) AS 'LAG_SALARY(上一行的值)', LEAD(SALARY,1,-1) OVER(ORDER BY SALARY DESC) AS 'LEAD_SALARY(下一行的值)', ROW_NUMBER() OVER (ORDER BY SALARY DESC) AS [ROW_NUMBER(排序)], RANK() OVER (ORDER BY SALARY DESC) AS [RANK(排名(間斷))], DENSE_RANK() OVER (ORDER BY SALARY DESC) AS [DENSE_RANK(排名(不間斷))], NTILE(3) OVER (ORDER BY SALARY DESC) AS [NTILE(平均分組)], CAST(CAST(SALARY * 100.0 / SUM(SALARY) OVER () AS DECIMAL(18, 1)) AS VARCHAR(10)) + '%' AS 薪資占比, MAX(SALARY) OVER () AS 最高薪資, MAX(SALARY) OVER () - SALARY AS 最大差值, SALARY - MIN(SALARY) OVER () AS 最小差值, MIN(SALARY) OVER () AS 最低薪資, AVG(SALARY) OVER () AS 平均薪資 FROM #TMP_EMP_SALARY;
--4、查看各部門內,四個排名函數結果
SELECT DEPT,NAME, SALARY, LAG(SALARY,1,0) OVER(PARTITION BY DEPT ORDER BY SALARY DESC) AS 'LAG_SALARY(上一行的值)', LEAD(SALARY,1,-1) OVER(PARTITION BY DEPT ORDER BY SALARY DESC) AS 'LEAD_SALARY(下一行的值)', ROW_NUMBER() OVER (PARTITION BY DEPT ORDER BY SALARY DESC) AS [ROW_NUMBER(排序)], RANK() OVER (PARTITION BY DEPT ORDER BY SALARY DESC) AS [RANK(排名(間斷))], DENSE_RANK() OVER (PARTITION BY DEPT ORDER BY SALARY DESC) AS [DENSE_RANK(排名(不間斷))], NTILE(3) OVER (PARTITION BY DEPT ORDER BY SALARY DESC) AS [NTILE(平均分組)], CAST(CAST(SALARY * 100.0 / SUM(SALARY) OVER (PARTITION BY DEPT) AS DECIMAL(18, 1)) AS VARCHAR(10)) + '%'AS 薪資占比, MAX(SALARY) OVER (PARTITION BY DEPT) AS 最高薪資, MAX(SALARY) OVER (PARTITION BY DEPT) - SALARY AS 最大差值, SALARY - MIN(SALARY) OVER (PARTITION BY DEPT) AS 最小差值, MIN(SALARY) OVER (PARTITION BY DEPT) AS 最低薪資, AVG(SALARY) OVER (PARTITION BY DEPT) AS 平均薪資 FROM #TMP_EMP_SALARY ORDER BY DEPT DESC, ROW_NUMBER() OVER (PARTITION BY DEPT ORDER BY SALARY DESC);
--5、刪除臨時表數據
DROP TABLE #TMP_EMP_SALARY;