?
This document uses PHP Chinese website manual Release
窗口函數(shù)通過在某種程度上關(guān)系到當(dāng)前行的表行執(zhí)行一組計(jì)算。 這相當(dāng)于可以做一個(gè)聚合函數(shù)的計(jì)算類型。但不同于常規(guī)的聚合函數(shù),使用的窗口函數(shù)不會(huì) 導(dǎo)致行成為分組到一個(gè)單一的輸出行;行保留其獨(dú)立的身份。在后臺(tái),窗口函數(shù)能夠訪問不止查詢 結(jié)果的當(dāng)前行。
這里是一個(gè)例子,說明如何比較每個(gè)員工的工資和在他或她的部門的平均工資:
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,并有一個(gè)表中的每一行的輸出行。
第四列將代表所有含有相同的depname值的表行的平均值作為當(dāng)前值。
(這實(shí)際上是標(biāo)準(zhǔn)avg
聚合函數(shù)功能,但是OVER條款使其
視為一個(gè)窗口函數(shù)和整個(gè)一套合適的計(jì)算行。)
窗口函數(shù)的調(diào)用總是包含一個(gè)OVER子句,即窗口函數(shù)的名稱和參數(shù)。 該語法區(qū)別于普通函數(shù)或聚合功能。OVER子句決定究竟將 查詢的行如何通過窗口函數(shù)拆分處理。OVER子句內(nèi)的PARTITION BY分區(qū)指定 行劃分成組,或分區(qū),共享相同的PARTITION BY值。 對于每一行,窗口函數(shù)通過同一個(gè)分區(qū)作為當(dāng)前行的行進(jìn)行計(jì)算。
雖然無論什么樣的順序的行avg
將產(chǎn)生相同的結(jié)果,但并這不是對于所有的
窗口函數(shù)。當(dāng)需要時(shí),你可以使用
OVER內(nèi)的ORDER BY控制順序。下面是一個(gè)例子:
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
功能在每個(gè)不同ORDER BY
值的當(dāng)前行分區(qū)產(chǎn)生一個(gè)數(shù)值排名。
rank
需要沒有明確的參數(shù),因?yàn)樗耆Q于OVER子句。
窗口函數(shù)的行是通過查詢FROM子句"virtual table"產(chǎn)生的, 如果有的話,過濾WHERE, GROUP BY和HAVING子句。 例如,行刪除,因?yàn)樗环蠜]有任何窗口函數(shù)WHERE條件。 查詢可以包含多個(gè)窗口的功能,通過不同的OVER子句不同的方式分割數(shù)據(jù),但是 他們所有的行動(dòng)在這個(gè)虛擬表中定義的同一行的集合。
我們已經(jīng)看到了,如果行排序并不重要,ORDER BY可以省略。 在一個(gè)分區(qū)包含所有行的情況下,也可以省略PARTITION BY。
還有一個(gè)重要的與窗口功能相關(guān)的概念:
對于每一行,是有其分區(qū)范圍內(nèi)的行集,又稱為它的window frame。
許多(但不是全部)窗口功能,只作用于窗框行上,而不是整個(gè)分區(qū)。
默認(rèn)情況下,如果使用ORDER BY,那么這個(gè)frame包含從分區(qū)開始到當(dāng)前的所有行,
以及那些當(dāng)前行后面的,根據(jù)ORDER BY規(guī)則等于當(dāng)前行的所有行,
如果不使用ORDER BY,那么,frame默認(rèn)包含分區(qū)中的所有行。
[1]
下面是一個(gè)使用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)
如上,因?yàn)樵?tt class="LITERAL">OVER子句沒有使用ORDER BY,因此, 窗框與分區(qū)(不使用PARTITION BY時(shí)即整個(gè)表)相同; 換句話說,每一次sum求和都是使用表中所有的salary,所以我們得到了每個(gè)輸出 行的相同結(jié)果。 但是,如果我們添加ORDER BY子句,我們會(huì)得到不同的結(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)
這里的總和是通過從第一個(gè)(最低)工資 到當(dāng)前一個(gè),包括任何當(dāng)前重復(fù)的(注意 重復(fù)薪金結(jié)果)。
窗函數(shù)僅允許在SELECT和ORDER BY語句中使用。 在其他地方禁止使用,比如GROUP BY, HAVING 和WHERE子句,這是因?yàn)樗鼈兲幚磉@些子句之后是邏輯 執(zhí)行。此外,標(biāo)準(zhǔn)聚合函數(shù)后,執(zhí)行窗口函數(shù)功能。 這意味在執(zhí)行一個(gè)窗口函數(shù)時(shí),發(fā)出一個(gè)標(biāo)準(zhǔn)聚合函數(shù)的請求是有效的,但反過來不行。
執(zhí)行窗口計(jì)算后,如果有必要進(jìn)行過濾或組行,你可以使用子選擇。例如:
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的行。
當(dāng)查詢涉及多個(gè)窗口函數(shù)功能,可以將每一個(gè)查詢結(jié)果通過單獨(dú)的OVER子句輸出, 但是,如果同一窗口行為需要多種功能,就會(huì)產(chǎn)生重復(fù),并且容易出錯(cuò)。 相反,每個(gè)窗口的操作可以在WINDOW子句中進(jìn)行命名,然后再被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ù)的更多詳細(xì)細(xì)節(jié)查閱 Section 4.2.8, Section 9.19, Section 7.2.4和 SELECT的參考頁。
[1] | 當(dāng)然,還有其他定義frame的方法,但本教程并不包括它們。詳情請參閱Section 4.2.8。 |