開窗函數支持分區、排序和框架三種元素,其語法格式以下:express
OVER ( [ <PARTITION BY clause> ] [ <ORDER BY clause> ] [ <ROW or RANGE clause> ] ) <PARTITION BY clause> ::= PARTITION BY value_expression , ... [ n ] <ORDER BY clause> ::= ORDER BY order_by_expression [ COLLATE collation_name ] [ ASC | DESC ] [ ,...n ] <ROW or RANGE clause> ::= { ROWS | RANGE } <window frame extent> <window frame extent> ::= { <window frame preceding> | <window frame between> } <window frame between> ::= BETWEEN <window frame bound> AND <window frame bound> <window frame bound> ::= { <window frame preceding> | <window frame following> } <window frame preceding> ::= { UNBOUNDED PRECEDING | <unsigned_value_specification> PRECEDING | CURRENT ROW } <window frame following> ::= { UNBOUNDED FOLLOWING | <unsigned_value_specification> FOLLOWING | CURRENT ROW } <unsigned value specification> ::= { <unsigned integer literal> }
【窗口分區】:就是將窗口指定列具備相同值的那些行進行分區,分區與分組比較相似,可是分組指定後對於整個SELECT語句只能按照這個分組,不過度區能夠在一條語句中指定不一樣的分區。
【窗口排序】:分區以後能夠指定排序列,那麼在窗口計算以前,各個窗口的行的邏輯順序將肯定。
【窗口框架】:框架是對窗口進行進一步的分區,框架有兩種範圍限定方式:一種是使用ROWS子句,經過指定當前行以前或以後的固定數目的行來限制分區中的行數;另外一種是RANGE子句,按照排序列的當前值,根據相同值來肯定分區中的行數。框架
一、未使用 partition by 指定分區示例函數
select *, sum(U_Id) over(order by U_Id) 列1, sum(U_Id) over(order by U_Id RANGE BETWEEN unbounded preceding AND CURRENT ROW) 列2, sum(U_Id) over(order by U_Id rows BETWEEN unbounded preceding AND CURRENT ROW) 列3, sum(U_Id) over(order by U_Id rows BETWEEN 1 preceding AND 2 following) 列4, sum(U_Id) over(order by U_Id ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) 列5 from UserInfo
結果分析:性能
RANGE 是邏輯窗口,是指定當前行對應值的範圍取值,列數不固定,只要行值在範圍內,對應列都包含在內。
ROWS 是物理窗口,即根據order by 子句排序後,取的前N行及後N行的數據計算。(與當前行的值無關,只與排序後的行號相關)spa
二、使用 partition by 指定分區示例3d
select *, sum(U_Id) over(partition by U_Pwd order by U_Id) 列1, sum(U_Id) over(partition by U_Pwd order by U_Id RANGE BETWEEN unbounded preceding AND CURRENT ROW) 列2, sum(U_Id) over(partition by U_Pwd order by U_Id rows BETWEEN unbounded preceding AND CURRENT ROW) 列3, sum(U_Id) over(partition by U_Pwd order by U_Id rows BETWEEN 1 preceding AND 2 following) 列4, sum(U_Id) over(partition by U_Pwd order by U_Id ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) 列5 from UserInfo
以上根據 列(U_Pwd)被分爲3個區,使用 partition by 指定分區就是先進行分區,而後再根據指定窗口和指定窗口取值範圍進行計算。code
當你用OVER()子句進行你的分析計算來打開你的窗口,你也能夠在窗口裏看到的,經過ROWS與RANGE選項來限制你的行數。來看下面的T-SQL語句: blog
SELECT t.OrderYear, t.OrderMonth, t.TotalDue, SUM(t.TotalDue) OVER(ORDER BY t.OrderYear, t.OrderMonth ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS 'RunningTotal' FROM ( SELECT YEAR(OrderDate) AS 'OrderYear', MONTH(OrderDate) AS 'OrderMonth', SalesPersonID, TotalDue FROM Sales.SalesOrderHeader ) AS t WHERE t.SalesPersonID = 274 AND t.OrderYear = 2005 GO
這個T-SQL語句用SUM()聚合函數進行彙總計算。窗口自己從第1行(UNBOUNDED PRECEDING)上至當前行(CURRENT ROW)。對於記錄級中的每1行,窗口變得愈來愈大,所以很容易進行彙總運算。下圖演示了這個概念。排序
從輸出你能夠看到,結果是個自增加的彙總——運行合計彙總的結果。圖片
如今假設你修改窗口爲RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,會發生什麼:
SELECT t.OrderYear, t.OrderMonth, t.TotalDue, SUM(t.TotalDue) OVER(ORDER BY t.OrderYear, t.OrderMonth RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS 'RunningTotal' FROM ( SELECT YEAR(OrderDate) AS 'OrderYear', MONTH(OrderDate) AS 'OrderMonth', SalesPersonID, TotalDue FROM Sales.SalesOrderHeader ) AS t WHERE t.SalesPersonID = 274 AND t.OrderYear = 2005 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選項取決於ORDER BY值在窗口裏有多少行被包含。所以當你使用RANGE選項時有性能上的巨大區別。