?
Ce document utilise Manuel du site Web PHP chinois Libérer
窗口函數(shù)通過在某種程度上關(guān)系到當前行的表行執(zhí)行一組計算。 這相當于可以做一個聚合函數(shù)的計算類型。但不同于常規(guī)的聚合函數(shù),使用的窗口函數(shù)不會 導(dǎo)致行成為分組到一個單一的輸出行;行保留其獨立的身份。在后臺,窗口函數(shù)能夠訪問不止查詢 結(jié)果的當前行。
這里是一個例子,說明如何比較每個員工的工資和在他或她的部門的平均工資:
SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary;
depname | empno | salary | avg -----------+-------+--------+----------------------- develop | 11 | 5200 | 5020.0000000000000000 develop | 7 | 4200 | 5020.0000000000000000 develop | 9 | 4500 | 5020.0000000000000000 develop | 8 | 6000 | 5020.0000000000000000 develop | 10 | 5200 | 5020.0000000000000000 personnel | 5 | 3500 | 3700.0000000000000000 personnel | 2 | 3900 | 3700.0000000000000000 sales | 3 | 4800 | 4866.6666666666666667 sales | 1 | 5000 | 4866.6666666666666667 sales | 4 | 4800 | 4866.6666666666666667 (10 rows)
前三輸出列直接來自表empsalary,并有一個表中的每一行的輸出行。
第四列將代表所有含有相同的depname值的表行的平均值作為當前值。
(這實際上是標準avg
聚合函數(shù)功能,但是OVER條款使其
視為一個窗口函數(shù)和整個一套合適的計算行。)
窗口函數(shù)的調(diào)用總是包含一個OVER子句,即窗口函數(shù)的名稱和參數(shù)。 該語法區(qū)別于普通函數(shù)或聚合功能。OVER子句決定究竟將 查詢的行如何通過窗口函數(shù)拆分處理。OVER子句內(nèi)的PARTITION BY分區(qū)指定 行劃分成組,或分區(qū),共享相同的PARTITION BY值。 對于每一行,窗口函數(shù)通過同一個分區(qū)作為當前行的行進行計算。
雖然無論什么樣的順序的行avg
將產(chǎn)生相同的結(jié)果,但并這不是對于所有的
窗口函數(shù)。當需要時,你可以使用
OVER內(nèi)的ORDER BY控制順序。下面是一個例子:
SELECT depname, empno, salary, rank() OVER (PARTITION BY depname ORDER BY salary DESC) FROM empsalary;
depname | empno | salary | rank -----------+-------+--------+------ develop | 8 | 6000 | 1 develop | 10 | 5200 | 2 develop | 11 | 5200 | 2 develop | 9 | 4500 | 4 develop | 7 | 4200 | 5 personnel | 2 | 3900 | 1 personnel | 5 | 3500 | 2 sales | 1 | 5000 | 1 sales | 4 | 4800 | 2 sales | 3 | 4800 | 2 (10 rows)
如下所示,在由ORDER BY定義子句的順序中,
rank
功能在每個不同ORDER BY
值的當前行分區(qū)產(chǎn)生一個數(shù)值排名。
rank
需要沒有明確的參數(shù),因為它完全取決于OVER子句。
窗口函數(shù)的行是通過查詢FROM子句"virtual table"產(chǎn)生的, 如果有的話,過濾WHERE, GROUP BY和HAVING子句。 例如,行刪除,因為它不符合沒有任何窗口函數(shù)WHERE條件。 查詢可以包含多個窗口的功能,通過不同的OVER子句不同的方式分割數(shù)據(jù),但是 他們所有的行動在這個虛擬表中定義的同一行的集合。
我們已經(jīng)看到了,如果行排序并不重要,ORDER BY可以省略。 在一個分區(qū)包含所有行的情況下,也可以省略PARTITION BY。
還有一個重要的與窗口功能相關(guān)的概念:
對于每一行,是有其分區(qū)范圍內(nèi)的行集,又稱為它的window frame。
許多(但不是全部)窗口功能,只作用于窗框行上,而不是整個分區(qū)。
默認情況下,如果使用ORDER BY,那么這個frame包含從分區(qū)開始到當前的所有行,
以及那些當前行后面的,根據(jù)ORDER BY規(guī)則等于當前行的所有行,
如果不使用ORDER BY,那么,frame默認包含分區(qū)中的所有行。
[1]
下面是一個使用sum
的例子:
SELECT salary, sum(salary) OVER () FROM empsalary;
salary | sum --------+------- 5200 | 47100 5000 | 47100 3500 | 47100 4800 | 47100 3900 | 47100 4200 | 47100 4500 | 47100 4800 | 47100 6000 | 47100 5200 | 47100 (10 rows)
如上,因為在OVER子句沒有使用ORDER BY,因此, 窗框與分區(qū)(不使用PARTITION BY時即整個表)相同; 換句話說,每一次sum求和都是使用表中所有的salary,所以我們得到了每個輸出 行的相同結(jié)果。 但是,如果我們添加ORDER BY子句,我們會得到不同的結(jié)果:
SELECT salary, sum(salary) OVER (ORDER BY salary) FROM empsalary;
salary | sum --------+------- 3500 | 3500 3900 | 7400 4200 | 11600 4500 | 16100 4800 | 25700 4800 | 25700 5000 | 30700 5200 | 41100 5200 | 41100 6000 | 47100 (10 rows)
這里的總和是通過從第一個(最低)工資 到當前一個,包括任何當前重復(fù)的(注意 重復(fù)薪金結(jié)果)。
窗函數(shù)僅允許在SELECT和ORDER BY語句中使用。 在其他地方禁止使用,比如GROUP BY, HAVING 和WHERE子句,這是因為它們處理這些子句之后是邏輯 執(zhí)行。此外,標準聚合函數(shù)后,執(zhí)行窗口函數(shù)功能。 這意味在執(zhí)行一個窗口函數(shù)時,發(fā)出一個標準聚合函數(shù)的請求是有效的,但反過來不行。
執(zhí)行窗口計算后,如果有必要進行過濾或組行,你可以使用子選擇。例如:
SELECT depname, empno, salary, enroll_date FROM (SELECT depname, empno, salary, enroll_date, rank() OVER (PARTITION BY depname ORDER BY salary DESC, empno) AS pos FROM empsalary ) AS ss WHERE pos < 3;
上面的查詢只顯示內(nèi)部查詢rank小于3的行。
當查詢涉及多個窗口函數(shù)功能,可以將每一個查詢結(jié)果通過單獨的OVER子句輸出, 但是,如果同一窗口行為需要多種功能,就會產(chǎn)生重復(fù),并且容易出錯。 相反,每個窗口的操作可以在WINDOW子句中進行命名,然后再被OVER引用。 例如:
SELECT sum(salary) OVER w, avg(salary) OVER w FROM empsalary WINDOW w AS (PARTITION BY depname ORDER BY salary DESC);
關(guān)于窗口化函數(shù)的更多詳細細節(jié)查閱 Section 4.2.8, Section 9.19, Section 7.2.4和 SELECT的參考頁。
[1] | 當然,還有其他定義frame的方法,但本教程并不包括它們。詳情請參閱Section 4.2.8。 |