SQL?Server窗口函數(shù)詳細指南(函數(shù)用法與場景)
前言
SQL Server 中的窗口函數(shù)(Window Functions)是一種強大的查詢工具,它允許我們在查詢結(jié)果集中對數(shù)據(jù)進行分區(qū)、排序和計算,而不會改變結(jié)果集的行數(shù)。窗口函數(shù)通過 OVER 子句定義一個“窗口”,在該窗口內(nèi)對數(shù)據(jù)進行操作。這使得我們能夠輕松實現(xiàn)排名、聚合、移動平均等復雜計算,而無需使用子查詢或自連接。
窗口函數(shù)的基本語法是:
窗口函數(shù) OVER (
[PARTITION BY 分區(qū)列]
[ORDER BY 排序列 [ASC|DESC]]
[ROWS | RANGE BETWEEN 邊界1 AND 邊界2]
)
- PARTITION BY:將結(jié)果集分成多個分區(qū),每個分區(qū)獨立計算。
- ORDER BY:定義窗口內(nèi)的排序順序。
- ROWS/RANGE:可選,定義窗口幀(frame),指定計算的行范圍。
窗口函數(shù)主要分為三類:排名函數(shù)、聚合函數(shù)和分析函數(shù)。下面我們逐一介紹每個函數(shù)的具體用法和使用場景。為了說明,我們假設(shè)有一個名為 Sales 的表,結(jié)構(gòu)如下:
| OrderID | Product | Quantity | Price | OrderDate |
|---|---|---|---|---|
| 1 | A | 10 | 100 | 2023-01-01 |
| 2 | B | 20 | 200 | 2023-01-02 |
| 3 | A | 15 | 150 | 2023-01-03 |
| … | … | … | … | … |
窗口函數(shù)完整列表
排名函數(shù)(Ranking Functions)
- ROW_NUMBER() - 為每行分配唯一的連續(xù)整數(shù)
- RANK() - 分配排名,相同值相同排名,有間隙
- DENSE_RANK() - 分配排名,相同值相同排名,無間隙
- NTILE(n) - 將數(shù)據(jù)分成n個組
聚合函數(shù)(Aggregate Functions)
- SUM() - 計算窗口內(nèi)總和
- AVG() - 計算窗口內(nèi)平均值
- MIN() - 計算窗口內(nèi)最小值
- MAX() - 計算窗口內(nèi)最大值
- COUNT() - 計算窗口內(nèi)行數(shù)
- STDEV() - 計算窗口內(nèi)標準差
- STDEVP() - 計算窗口內(nèi)總體標準差
- VAR() - 計算窗口內(nèi)方差
- VARP() - 計算窗口內(nèi)總體方差
分析函數(shù)(Analytic Functions)
- LEAD() - 訪問后續(xù)行的值
- LAG() - 訪問前面行的值
- FIRST_VALUE() - 獲取窗口內(nèi)第一個值
- LAST_VALUE() - 獲取窗口內(nèi)最后一個值
- NTH_VALUE() - 獲取窗口內(nèi)第n個值
分布函數(shù)(Distribution Functions)
- PERCENT_RANK() - 計算相對排名(0-1)
- CUME_DIST() - 計算累計分布(0-1)
- PERCENTILE_CONT() - 連續(xù)百分位數(shù)
- PERCENTILE_DISC() - 離散百分位數(shù)
每個函數(shù)詳細介紹
1. ROW_NUMBER()
函數(shù)說明:為結(jié)果集中的每一行分配一個唯一的連續(xù)整數(shù),從1開始遞增。相同值的行會獲得不同的行號。
語法:
ROW_NUMBER() OVER (
[PARTITION BY 分區(qū)列1, 分區(qū)列2, ...]
ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC], ...
)
參數(shù)說明:
PARTITION BY:可選,將結(jié)果集分成多個分區(qū),每個分區(qū)獨立編號ORDER BY:必需,定義排序順序,決定行號的分配
示例:
-- 按產(chǎn)品分組,按數(shù)量降序編號
SELECT
Product,
Quantity,
ROW_NUMBER() OVER (PARTITION BY Product ORDER BY Quantity DESC) AS RowNum
FROM Sales;
-- 全局按價格降序編號
SELECT
Product,
Price,
ROW_NUMBER() OVER (ORDER BY Price DESC) AS GlobalRank
FROM Sales;
使用場景:
- 分頁查詢(LIMIT OFFSET)
- 刪除重復記錄
- 生成唯一標識符
- 數(shù)據(jù)抽樣
2. RANK()
函數(shù)說明:為行分配排名,相同值的行獲得相同排名,下一個排名會跳過(產(chǎn)生間隙)。
語法:
RANK() OVER (
[PARTITION BY 分區(qū)列1, 分區(qū)列2, ...]
ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC], ...
)
示例:
-- 按價格排名,相同價格相同排名
SELECT
Product,
Price,
RANK() OVER (ORDER BY Price DESC) AS PriceRank
FROM Sales;
結(jié)果示例:
Product | Price | PriceRank --------|-------|---------- A | 200 | 1 B | 200 | 1 C | 150 | 3 (跳過了2) D | 100 | 4
使用場景:
- 競賽排名
- 成績排名
- 銷售排行榜
3. DENSE_RANK()
函數(shù)說明:類似于RANK,但排名連續(xù),沒有間隙。相同值的行獲得相同排名,下一個排名連續(xù)。
語法:
DENSE_RANK() OVER (
[PARTITION BY 分區(qū)列1, 分區(qū)列2, ...]
ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC], ...
)
示例:
SELECT
Product,
Price,
DENSE_RANK() OVER (ORDER BY Price DESC) AS DenseRank
FROM Sales;
結(jié)果示例:
Product | Price | DenseRank --------|-------|---------- A | 200 | 1 B | 200 | 1 C | 150 | 2 (連續(xù),沒有跳躍) D | 100 | 3
使用場景:
- 獎牌排名(金銀銅)
- 等級評定
- 需要連續(xù)排名的場景
4. NTILE(n)
函數(shù)說明:將分區(qū)內(nèi)的行分成n個組,每組分配一個從1到n的數(shù)字。如果行數(shù)不能被n整除,前面的組會多一行。
語法:
NTILE(組數(shù)) OVER (
[PARTITION BY 分區(qū)列1, 分區(qū)列2, ...]
ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC], ...
)
示例:
-- 將數(shù)據(jù)分成4個四分位數(shù)
SELECT
Product,
Price,
NTILE(4) OVER (ORDER BY Price DESC) AS Quartile
FROM Sales;
使用場景:
- 分位數(shù)分析
- 數(shù)據(jù)分桶
- 等級劃分(如A、B、C、D級)
5. SUM()
函數(shù)說明:計算窗口內(nèi)列的總和,支持累計計算。
語法:
SUM(列) OVER (
[PARTITION BY 分區(qū)列1, 分區(qū)列2, ...]
[ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC], ...]
[ROWS | RANGE BETWEEN 邊界1 AND 邊界2]
)
窗口幀選項:
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW- 累計到當前行ROWS BETWEEN 3 PRECEDING AND CURRENT ROW- 當前行及前3行ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING- 當前行到末尾
示例:
-- 累計銷售總額
SELECT
OrderDate,
Price,
SUM(Price) OVER (ORDER BY OrderDate) AS RunningTotal
FROM Sales;
-- 按產(chǎn)品分組的累計銷售
SELECT
Product,
OrderDate,
Price,
SUM(Price) OVER (PARTITION BY Product ORDER BY OrderDate) AS ProductRunningTotal
FROM Sales;
-- 移動3天平均
SELECT
OrderDate,
Price,
AVG(Price) OVER (ORDER BY OrderDate ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS MovingAvg3
FROM Sales;
使用場景:
- 財務(wù)累計報表
- 銷售趨勢分析
- 移動平均計算
6. AVG()
函數(shù)說明:計算窗口內(nèi)列的平均值。
語法:
AVG(列) OVER (
[PARTITION BY 分區(qū)列1, 分區(qū)列2, ...]
[ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC], ...]
[ROWS | RANGE BETWEEN 邊界1 AND 邊界2]
)
示例:
-- 每個產(chǎn)品的平均價格
SELECT
Product,
Price,
AVG(Price) OVER (PARTITION BY Product) AS AvgPrice
FROM Sales;
-- 移動平均
SELECT
OrderDate,
Price,
AVG(Price) OVER (ORDER BY OrderDate ROWS BETWEEN 4 PRECEDING AND CURRENT ROW) AS MovingAvg5
FROM Sales;
使用場景:
- 趨勢分析
- 股票技術(shù)分析
- 性能基準
7. MIN() / MAX()
函數(shù)說明:計算窗口內(nèi)列的最小值/最大值。
語法:
MIN(列) OVER (
[PARTITION BY 分區(qū)列1, 分區(qū)列2, ...]
[ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC], ...]
[ROWS | RANGE BETWEEN 邊界1 AND 邊界2]
)
MAX(列) OVER (
[PARTITION BY 分區(qū)列1, 分區(qū)列2, ...]
[ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC], ...]
[ROWS | RANGE BETWEEN 邊界1 AND 邊界2]
)
示例:
-- 每個產(chǎn)品的歷史最高價和最低價
SELECT
Product,
Price,
MIN(Price) OVER (PARTITION BY Product) AS MinPrice,
MAX(Price) OVER (PARTITION BY Product) AS MaxPrice
FROM Sales;
使用場景:
- 價格監(jiān)控
- 極值分析
- 范圍計算
8. COUNT()
函數(shù)說明:計算窗口內(nèi)的行數(shù)。
語法:
COUNT(*) OVER (
[PARTITION BY 分區(qū)列1, 分區(qū)列2, ...]
[ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC], ...]
[ROWS | RANGE BETWEEN 邊界1 AND 邊界2]
)
示例:
-- 每個產(chǎn)品的訂單數(shù)量
SELECT
Product,
COUNT(*) OVER (PARTITION BY Product) AS ProductOrderCount
FROM Sales;
使用場景:
- 分組統(tǒng)計
- 數(shù)據(jù)驗證
- 頻率分析
9. LEAD()
函數(shù)說明:訪問當前行后n行的值。如果超出范圍,返回默認值。
語法:
LEAD(列, n, 默認值) OVER (
[PARTITION BY 分區(qū)列1, 分區(qū)列2, ...]
ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC], ...
)
參數(shù)說明:
列:要訪問的列n:向后偏移的行數(shù)(默認為1)默認值:當超出范圍時返回的值(默認為NULL)
示例:
-- 計算價格變化
SELECT
OrderDate,
Price,
LEAD(Price, 1, 0) OVER (ORDER BY OrderDate) AS NextPrice,
Price - LEAD(Price, 1, 0) OVER (ORDER BY OrderDate) AS PriceChange
FROM Sales;
使用場景:
- 時間序列分析
- 增長率計算
- 趨勢預(yù)測
10. LAG()
函數(shù)說明:訪問當前行前n行的值。如果超出范圍,返回默認值。
語法:
LAG(列, n, 默認值) OVER (
[PARTITION BY 分區(qū)列1, 分區(qū)列2, ...]
ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC], ...
)
示例:
-- 計算環(huán)比增長率
SELECT
OrderDate,
Price,
LAG(Price, 1, Price) OVER (ORDER BY OrderDate) AS PrevPrice,
(Price - LAG(Price, 1, Price) OVER (ORDER BY OrderDate)) /
LAG(Price, 1, Price) OVER (ORDER BY OrderDate) * 100 AS GrowthRate
FROM Sales;
使用場景:
- 環(huán)比分析
- 歷史比較
- 變化率計算
11. FIRST_VALUE()
函數(shù)說明:返回窗口幀中第一個值。
語法:
FIRST_VALUE(列) OVER (
[PARTITION BY 分區(qū)列1, 分區(qū)列2, ...]
ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC], ...
[ROWS | RANGE BETWEEN 邊界1 AND 邊界2]
)
示例:
-- 每個產(chǎn)品的首次銷售價格
SELECT
Product,
OrderDate,
Price,
FIRST_VALUE(Price) OVER (PARTITION BY Product ORDER BY OrderDate) AS FirstPrice
FROM Sales;
使用場景:
- 基準值比較
- 初始狀態(tài)記錄
- 歷史對比
12. LAST_VALUE()
函數(shù)說明:返回窗口幀中最后一個值。注意:默認窗口幀到當前行,通常需要調(diào)整。
語法:
LAST_VALUE(列) OVER (
[PARTITION BY 分區(qū)列1, 分區(qū)列2, ...]
ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC], ...
[ROWS | RANGE BETWEEN 邊界1 AND 邊界2]
)
示例:
-- 每個產(chǎn)品的最新價格(需要調(diào)整窗口幀)
SELECT
Product,
OrderDate,
Price,
LAST_VALUE(Price) OVER (
PARTITION BY Product
ORDER BY OrderDate
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS LastPrice
FROM Sales;
使用場景:
- 最新狀態(tài)獲取
- 最終值比較
- 狀態(tài)跟蹤
13. PERCENT_RANK()
函數(shù)說明:計算相對排名,返回0到1之間的值。第一名的值為0,最后一名的值為1。
語法:
PERCENT_RANK() OVER (
[PARTITION BY 分區(qū)列1, 分區(qū)列2, ...]
ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC], ...
)
示例:
-- 價格百分位排名
SELECT
Product,
Price,
PERCENT_RANK() OVER (ORDER BY Price DESC) AS PricePercentRank
FROM Sales;
使用場景:
- 統(tǒng)計分布分析
- 百分位計算
- 數(shù)據(jù)標準化
14. CUME_DIST()
函數(shù)說明:計算累計分布,返回0到1之間的值。表示小于等于當前值的行數(shù)占總行數(shù)的比例。
語法:
CUME_DIST() OVER (
[PARTITION BY 分區(qū)列1, 分區(qū)列2, ...]
ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC], ...
)
示例:
-- 價格累計分布
SELECT
Product,
Price,
CUME_DIST() OVER (ORDER BY Price) AS PriceCumeDist
FROM Sales;
使用場景:
- 分布分析
- 分位數(shù)計算
- 數(shù)據(jù)分布可視化
15. PERCENTILE_CONT()
函數(shù)說明:計算連續(xù)百分位數(shù),返回插值后的值。
語法:
PERCENTILE_CONT(百分位數(shù)) OVER (
[PARTITION BY 分區(qū)列1, 分區(qū)列2, ...]
ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC], ...
)
示例:
-- 計算中位數(shù)(50%分位數(shù))
SELECT
Product,
PERCENTILE_CONT(0.5) OVER (PARTITION BY Product ORDER BY Price) AS MedianPrice
FROM Sales;
使用場景:
- 統(tǒng)計分位數(shù)
- 數(shù)據(jù)分布分析
- 異常值檢測
16. PERCENTILE_DISC()
函數(shù)說明:計算離散百分位數(shù),返回實際存在的值。
語法:
PERCENTILE_DISC(百分位數(shù)) OVER (
[PARTITION BY 分區(qū)列1, 分區(qū)列2, ...]
ORDER BY 排序列1 [ASC|DESC], 排序列2 [ASC|DESC], ...
)
示例:
-- 計算離散中位數(shù)
SELECT
Product,
PERCENTILE_DISC(0.5) OVER (PARTITION BY Product ORDER BY Price) AS DiscreteMedian
FROM Sales;
使用場景:
- 離散分位數(shù)
- 實際值分析
- 數(shù)據(jù)驗證
排名函數(shù)
排名函數(shù)用于為行分配排名或分組。
1. ROW_NUMBER()
用法:為每個分區(qū)內(nèi)的行分配一個唯一的連續(xù)整數(shù),從1開始,按照 ORDER BY 排序。
語法:
ROW_NUMBER() OVER (PARTITION BY 分區(qū)列 ORDER BY 排序列)
例子:
SELECT
Product,
Quantity,
ROW_NUMBER() OVER (PARTITION BY Product ORDER BY Quantity DESC) AS RowNum
FROM Sales;
結(jié)果(假設(shè)數(shù)據(jù)):
- A, 15, 1
- A, 10, 2
- B, 20, 1
使用場景:分頁查詢、生成唯一行號、刪除重復記錄(結(jié)合 CTE)。
2. RANK()
用法:為行分配排名,如果值相同則排名相同,下一個排名會跳過(有間隙)。
語法:
RANK() OVER (PARTITION BY 分區(qū)列 ORDER BY 排序列)
例子:
SELECT
Product,
Quantity,
RANK() OVER (ORDER BY Quantity DESC) AS Rank
FROM Sales;
結(jié)果:
- B, 20, 1
- A, 15, 2
- A, 10, 3 (沒有跳躍,因為沒有并列)
如果有兩個15,則:15排2,下一個跳到4。
使用場景:排名競賽、識別前N名,但允許并列。
3. DENSE_RANK()
用法:類似于 RANK,但排名連續(xù),沒有間隙。
語法:
DENSE_RANK() OVER (PARTITION BY 分區(qū)列 ORDER BY 排序列)
例子:同上,如果有兩個15,則:15排2,下一個排3。
使用場景:需要連續(xù)排名的場景,如獎牌排名(金銀銅連續(xù))。
4. NTILE(n)
用法:將分區(qū)內(nèi)的行分成 n 個組,每組分配一個從1到n的數(shù)字。
語法:
NTILE(組數(shù)) OVER (PARTITION BY 分區(qū)列 ORDER BY 排序列)
例子:
SELECT
Product,
Quantity,
NTILE(2) OVER (ORDER BY Quantity DESC) AS Tile
FROM Sales;
結(jié)果:分成兩組,前半組1,后半組2。
使用場景:分桶分析、將數(shù)據(jù)分成等份(如分位數(shù))。
聚合函數(shù)
聚合函數(shù)如 SUM、AVG、MIN、MAX、COUNT 可以與 OVER 結(jié)合,在窗口內(nèi)計算。
1. SUM()
用法:計算窗口內(nèi)列的總和。
語法:
SUM(列) OVER (PARTITION BY 分區(qū)列 ORDER BY 排序列 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
例子(累計銷售):
SELECT
OrderDate,
Price,
SUM(Price) OVER (ORDER BY OrderDate) AS RunningTotal
FROM Sales;
結(jié)果:每行顯示到當前日期的累計總價。
使用場景:運行總計、累計求和、財務(wù)報告。
2. AVG()
用法:計算平均值。
語法:類似 SUM。
例子:計算移動平均。
使用場景:趨勢分析、股票移動平均。
3. MIN() / MAX()
用法:窗口內(nèi)最小/最大值。
例子:查找每個產(chǎn)品的歷史最低價。
使用場景:價格監(jiān)控、極值分析。
4. COUNT()
用法:計數(shù)。
例子:計算每個分區(qū)內(nèi)的行數(shù)。
使用場景:分組計數(shù)而不使用 GROUP BY。
分析函數(shù)
分析函數(shù)用于訪問窗口中其他行的數(shù)據(jù)。
1. LEAD(列, n, 默認值)
用法:返回當前行后 n 行的列值。
語法:
LEAD(列, n, 默認值) OVER (PARTITION BY 分區(qū)列 ORDER BY 排序列)
例子:
SELECT
OrderDate,
Price,
LEAD(Price, 1, 0) OVER (ORDER BY OrderDate) AS NextPrice
FROM Sales;
結(jié)果:顯示下一訂單的價格。
使用場景:比較前后行、計算增長率、時間序列分析。
2. LAG(列, n, 默認值)
用法:返回當前行前 n 行的列值。
語法:類似 LEAD。
例子:計算價格變化。
使用場景:與 LEAD 類似,用于歷史比較。
3. FIRST_VALUE(列)
用法:返回窗口幀中第一個值。
語法:
FIRST_VALUE(列) OVER (PARTITION BY 分區(qū)列 ORDER BY 排序列 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
例子:每個產(chǎn)品的首次銷售價格。
使用場景:基準值比較。
4. LAST_VALUE(列)
用法:返回窗口幀中最后一個值。注意:默認幀到當前行,需要調(diào)整。
例子:每個產(chǎn)品的最新價格。
使用場景:最新狀態(tài)獲取。
其他函數(shù)
1. PERCENT_RANK()
用法:計算相對排名(0到1)。
語法:OVER (ORDER BY 排序列)
例子:百分位排名。
使用場景:統(tǒng)計分布。
2. CUME_DIST()
用法:累計分布(0到1)。
使用場景:分布分析。
結(jié)論
SQL Server 窗口函數(shù)極大地簡化了復雜查詢,提高了效率。通過掌握這些函數(shù),你可以處理各種數(shù)據(jù)分析任務(wù)。建議在實際項目中練習,以加深理解。注意:窗口函數(shù)不支持在 WHERE 或 GROUP BY 中使用,通常在 SELECT 或 ORDER BY 中。
到此這篇關(guān)于SQL Server窗口函數(shù)的文章就介紹到這了,更多相關(guān)SQL Server窗口函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SQL Server誤區(qū)30日談 第12天 TempDB的文件數(shù)和需要和CPU數(shù)目保持一致
TempDB的文件沒有必要分布在多個存儲器之間。如果你看到PAGELATCH類型的等待,即使你進行了分布也不會改善性能,而如果PAGEIOLATCH型的等待,或許你需要多個存儲器,但這也不是必然-有可能你需要講整個TempDB遷移到另一個存儲系統(tǒng),而不是僅僅為TempDB增加一個文件2013-01-01
SQL Server 2005作業(yè)設(shè)置定時任務(wù)
這篇文章主要介紹了SQL Server 2005作業(yè)設(shè)置定時任務(wù)的相關(guān)詳細步驟,需要的朋友可以參考下2017-01-01
一文詳解如何遠程連接SQLServer數(shù)據(jù)庫
sql?server是一款數(shù)據(jù)庫管理工具,其中有非常多實用的功能可以幫助用戶完成數(shù)據(jù)庫的管理操作,也有一些用戶在操作這款軟件的時候會需要用到遠程連接功能,這篇文章主要給大家介紹了關(guān)于如何遠程連接SQLServer數(shù)據(jù)庫的相關(guān)資料,需要的朋友可以參考下2023-10-10
sql server 2008 壓縮備份數(shù)據(jù)庫(20g)
這篇文章主要介紹了針對20g數(shù)據(jù)庫的遷移問題,,需要的朋友可以參考下2018-03-03
SqlServer 英文單詞全字匹配詳解及實現(xiàn)代碼
這篇文章主要介紹了SqlServer 英文單詞全字匹配的相關(guān)資料,并附實例,有需要的小伙伴可以參考下2016-09-09

