幾乎每次我展示SQL Server里的窗口時,人們都非常有興趣知道,當你定義你的窗口(指定的一組行)時,ROWS與RANGE選項之間的區別。因此在今天的文章里我想給你展示下這些選項的區別,對於你的分析計算意味着什么。
ROWS與RANGE之間的區別
當你用OVER()子句進行你的分析計算來打開你的窗口,你也可以在窗口里看到的,通過ROWS與RANGE選項來限制你的行數。來看下面的T-SQL語句:
1 SELECT 2 t.OrderYear, 3 t.OrderMonth, 4 t.TotalDue, 5 SUM(t.TotalDue) OVER(ORDER BY t.OrderYear, t.OrderMonth ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS 'RunningTotal' 6 FROM 7 ( 8 SELECT 9 YEAR(OrderDate) AS 'OrderYear', 10 MONTH(OrderDate) AS 'OrderMonth', 11 SalesPersonID, 12 TotalDue 13 FROM Sales.SalesOrderHeader 14 ) AS t 15 WHERE 16 t.SalesPersonID = 274 17 AND t.OrderYear = 2005 18 GO
這個T-SQL語句用SUM()聚合函數進行匯總計算。窗口本身從第1行(UNBOUNDED PRECEDING)上至當前行(CURRENT ROW)。對於記錄級中的每1行,窗口變得越來越大,因此很容易進行匯總運算。下圖演示了這個概念。
從輸出你可以看到,結果是個自增長的匯總——運行合計匯總的結果。
現在假設你修改窗口為RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,會發生什么:
1 SELECT 2 t.OrderYear, 3 t.OrderMonth, 4 t.TotalDue, 5 SUM(t.TotalDue) OVER(ORDER BY t.OrderYear, t.OrderMonth RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS 'RunningTotal' 6 FROM 7 ( 8 SELECT 9 YEAR(OrderDate) AS 'OrderYear', 10 MONTH(OrderDate) AS 'OrderMonth', 11 SalesPersonID, 12 TotalDue 13 FROM Sales.SalesOrderHeader 14 ) AS t 15 WHERE 16 t.SalesPersonID = 274 17 AND t.OrderYear = 2005 18 GO
從下圖你可以看到,你得到了不同的結果,對於2005年11月的記錄顯示同樣的匯總。
我們來嘗試理解下為什么這里RANGE選項比ROWS選項給你不同的結果。使用ROWS選項你定義當前行的固定前后記錄。這里你看到的行取決於窗口的ORDER BY從句。你也可以說你在物理級別定義你的窗口。
當你使用RANGE選項事情就改變了。RANGE選項包含窗口里的所有行,和當前行有相同ORDER BY值。從剛才的圖片你可以看到,對於2005年11月的2條記錄你拿到同個匯總,因為這2行有同樣的ORDER BY值(2005年11月)。使用RANGE選項你在邏輯級別定義你的窗口。如果更多的行有同個ORDER BY值,當你使用ROWS選項你的窗口會包含更多的行。
小結
在今天的文章里你看到了當你為你的分析計算定義窗口時,ROWS和RANGE選項之間的區別。使用ROWS選項你在物理級別定義在你窗口里有多少行。使用RANGE選項取決於ORDER BY值在窗口里有多少行被包含。因此當你使用RANGE選項時有性能上的巨大區別。在接下來的文章我會討論下這些副作用。
感謝關注!
參考文章:
https://www.sqlpassion.at/archive/2015/01/22/sql-server-windowing-functions-rows-vs-range/