3.5. ÐконнÑе ÑÑнкÑии #
ÐÐºÐ¾Ð½Ð½Ð°Ñ ÑÑнкÑÐ¸Ñ Ð²ÑполнÑÐµÑ Ð²ÑÑиÑÐ»ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð½Ð°Ð±Ð¾Ñа ÑÑÑок, некоÑоÑÑм обÑазом ÑвÑзаннÑÑ Ñ ÑекÑÑей ÑÑÑокой. ÐÑ Ð´ÐµÐ¹ÑÑвие можно ÑÑавниÑÑ Ñ Ð²ÑÑиÑлением, пÑоизводимÑм агÑегаÑной ÑÑнкÑией. Ðднако Ñ Ð¾ÐºÐ¾Ð½Ð½Ñми ÑÑнкÑиÑми ÑÑÑоки не гÑÑппиÑÑÑÑÑÑ Ð² Ð¾Ð´Ð½Ñ Ð²ÑÑ Ð¾Ð´Ð½ÑÑ ÑÑÑокÑ, ÑÑо Ð¸Ð¼ÐµÐµÑ Ð¼ÐµÑÑо Ñ Ð¾Ð±ÑÑнÑми, не оконнÑми, агÑегаÑнÑми ÑÑнкÑиÑми. ÐмеÑÑо ÑÑого, ÑÑи ÑÑÑоки оÑÑаÑÑÑÑ Ð¾ÑделÑнÑми ÑÑÑноÑÑÑми. ÐнÑÑÑи же, Ð¾ÐºÐ¾Ð½Ð½Ð°Ñ ÑÑнкÑиÑ, как и агÑегаÑнаÑ, Ð¼Ð¾Ð¶ÐµÑ Ð¾Ð±ÑаÑаÑÑÑÑ Ð½Ðµ ÑолÑко к ÑекÑÑей ÑÑÑоке ÑезÑлÑÑаÑа запÑоÑа.
ÐÐ¾Ñ Ð¿ÑимеÑ, показÑваÑÑий, как ÑÑавниÑÑ Ð·Ð°ÑплаÑÑ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ ÑоÑÑÑдника Ñо ÑÑедней заÑплаÑой его оÑдела:
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, но пÑедложение OVER пÑевÑаÑÐ°ÐµÑ ÐµÑ Ð² оконнÑÑ, Ñак ÑÑо ÐµÑ Ð´ÐµÐ¹ÑÑвие огÑаниÑиваеÑÑÑ Ñамками окон.)
ÐÑзов оконной ÑÑнкÑии вÑегда ÑодеÑÐ¶Ð¸Ñ Ð¿Ñедложение OVER, ÑледÑÑÑее за названием и аÑгÑменÑами оконной ÑÑнкÑии. ÐÑо ÑинÑакÑиÑеÑки оÑлиÑÐ°ÐµÑ ÐµÑ Ð¾Ñ Ð¾Ð±ÑÑной, не оконной агÑегаÑной ÑÑнкÑии. ÐÑедложение OVER опÑеделÑеÑ, как именно нÑжно ÑазделиÑÑ ÑÑÑоки запÑоÑа Ð´Ð»Ñ Ð¾Ð±ÑабоÑки оконной ÑÑнкÑией. ÐÑедложение PARTITION BY, дополнÑÑÑее OVER, ÑазделÑÐµÑ ÑÑÑоки по гÑÑппам, или Ñазделам, обÑединÑÑ Ð¾Ð´Ð¸Ð½Ð°ÐºÐ¾Ð²Ñе знаÑÐµÐ½Ð¸Ñ Ð²ÑÑажений PARTITION BY. ÐÐºÐ¾Ð½Ð½Ð°Ñ ÑÑнкÑÐ¸Ñ Ð²ÑÑиÑлÑеÑÑÑ Ð¿Ð¾ ÑÑÑокам, попадаÑÑим в один Ñаздел Ñ ÑекÑÑей ÑÑÑокой.
ÐÑ Ð¼Ð¾Ð¶ÐµÑе Ñакже опÑеделÑÑÑ Ð¿Ð¾ÑÑдок, в коÑоÑом ÑÑÑоки бÑдÑÑ Ð¾Ð±ÑабаÑÑваÑÑÑÑ Ð¾ÐºÐ¾Ð½Ð½Ñми ÑÑнкÑиÑми, иÑполÑзÑÑ ORDER BY в OVER. (ÐоÑÑдок 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)
Ðак показано здеÑÑ, ÑÑнкÑÐ¸Ñ rank вÑдаÑÑ Ð¿Ð¾ÑÑдковÑй Ð½Ð¾Ð¼ÐµÑ Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ ÑникалÑного знаÑÐµÐ½Ð¸Ñ Ð² Ñазделе ÑекÑÑей ÑÑÑоки, по коÑоÑÐ¾Ð¼Ñ Ð²ÑполнÑÐµÑ ÑоÑÑиÑÐ¾Ð²ÐºÑ Ð¿Ñедложение ORDER BY. У ÑÑнкÑии rank Ð½ÐµÑ Ð¿Ð°ÑамеÑÑов, Ñак как ÐµÑ Ð¿Ð¾Ð²ÐµÐ´ÐµÐ½Ð¸Ðµ полноÑÑÑÑ Ð¾Ð¿ÑеделÑеÑÑÑ Ð¿Ñедложением OVER.
СÑÑоки, обÑабаÑÑваемÑе оконной ÑÑнкÑией, пÑедÑÑавлÑÑÑ Ñобой «виÑÑÑалÑнÑе ÑаблиÑÑ», ÑозданнÑе из пÑÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ FROM и заÑем пÑоÑедÑие ÑеÑез ÑилÑÑÑаÑÐ¸Ñ Ð¸ гÑÑппиÑÐ¾Ð²ÐºÑ WHERE и GROUP BY и, возможно, ÑÑловие HAVING. ÐапÑимеÑ, ÑÑÑока, оÑÑилÑÑÑÐ¾Ð²Ð°Ð½Ð½Ð°Ñ Ð¸Ð·-за наÑÑÑÐµÐ½Ð¸Ñ ÑÑÐ»Ð¾Ð²Ð¸Ñ WHERE, не бÑÐ´ÐµÑ Ð²Ð¸Ð´Ð½Ð° Ð´Ð»Ñ Ð¾ÐºÐ¾Ð½Ð½ÑÑ
ÑÑнкÑий. ÐапÑÐ¾Ñ Ð¼Ð¾Ð¶ÐµÑ ÑодеÑжаÑÑ Ð½ÐµÑколÑко оконнÑÑ
ÑÑнкÑий, ÑазделÑÑÑиÑ
даннÑе по-ÑÐ°Ð·Ð½Ð¾Ð¼Ñ Ñ Ð¿Ñименением ÑазнÑÑ
пÑедложений OVER, но вÑе они бÑдÑÑ Ð¾Ð±ÑабаÑÑваÑÑ Ð¾Ð´Ð¸Ð½ и ÑÐ¾Ñ Ð¶Ðµ Ð½Ð°Ð±Ð¾Ñ ÑÑÑок ÑÑой виÑÑÑалÑной ÑаблиÑÑ.
ÐÑ Ñже видели, ÑÑо ORDER BY можно опÑÑÑиÑÑ, еÑли поÑÑдок ÑÑÑок не важен. Также возможно опÑÑÑиÑÑ PARTITION BY, в ÑÑом ÑлÑÑае обÑазÑеÑÑÑ Ð¾Ð´Ð¸Ð½ Ñаздел, ÑодеÑжаÑий вÑе ÑÑÑоки.
ÐÑÑÑ ÐµÑÑ Ð¾Ð´Ð½Ð¾ важное понÑÑие, ÑвÑзанное Ñ Ð¾ÐºÐ¾Ð½Ð½Ñми ÑÑнкÑиÑми: Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ ÑÑÑоки ÑÑÑеÑÑвÑÐµÑ Ð½Ð°Ð±Ð¾Ñ ÑÑÑок в ÐµÑ Ñазделе, назÑваемÑй Ñамкой окна. ÐекоÑоÑÑе оконнÑе ÑÑнкÑии обÑабаÑÑваÑÑ ÑолÑко ÑÑÑоки Ñамки окна, а не вÑего Ñаздела. Ðо ÑмолÑÐ°Ð½Ð¸Ñ Ñ Ñказанием ORDER BY Ñамка ÑоÑÑÐ¾Ð¸Ñ Ð¸Ð· вÑеÑ
ÑÑÑок Ð¾Ñ Ð½Ð°Ñала Ñаздела до ÑекÑÑей ÑÑÑоки и ÑÑÑок, ÑавнÑÑ
ÑекÑÑей по знаÑÐµÐ½Ð¸Ñ Ð²ÑÑÐ°Ð¶ÐµÐ½Ð¸Ñ ORDER BY. Ðез ORDER BY Ñамка по ÑмолÑÐ°Ð½Ð¸Ñ ÑоÑÑÐ¾Ð¸Ñ Ð¸Ð· вÑеÑ
ÑÑÑок Ñаздела. [5] ÐоÑмоÑÑиÑе на пÑÐ¸Ð¼ÐµÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ 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)
Так как в ÑÑом пÑимеÑе Ð½ÐµÑ ÑÐºÐ°Ð·Ð°Ð½Ð¸Ñ ORDER BY в пÑедложении OVER, Ñамка окна ÑодеÑÐ¶Ð¸Ñ Ð²Ñе ÑÑÑоки Ñаздела, а он, в ÑÐ²Ð¾Ñ Ð¾ÑеÑедÑ, без пÑÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ PARTITION BY вклÑÑÐ°ÐµÑ Ð²Ñе ÑÑÑоки ÑаблиÑÑ; дÑÑгими Ñловами, ÑÑмма вÑÑиÑлÑеÑÑÑ Ð¿Ð¾ вÑей ÑаблиÑе и Ð¼Ñ Ð¿Ð¾Ð»ÑÑаем один ÑезÑлÑÑÐ°Ñ Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ ÑÑÑоки ÑезÑлÑÑаÑа. Ðо еÑли Ð¼Ñ Ð´Ð¾Ð±Ð°Ð²Ð¸Ð¼ ORDER BY, Ð¼Ñ Ð¿Ð¾Ð»ÑÑим ÑовÑем дÑÑгие ÑезÑлÑÑаÑÑ:
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)
ÐдеÑÑ Ð² ÑÑмме накапливаÑÑÑÑ Ð·Ð°ÑплаÑÑ Ð¾Ñ Ð¿ÐµÑвой (Ñамой низкой) до ÑекÑÑей, вклÑÑÐ°Ñ Ð¿Ð¾Ð²ÑоÑÑÑÑиеÑÑ ÑекÑÑие знаÑÐµÐ½Ð¸Ñ (обÑаÑиÑе внимание на ÑезÑлÑÑÐ°Ñ Ð² ÑÑÑÐ¾ÐºÐ°Ñ Ñ Ð¾Ð´Ð¸Ð½Ð°ÐºÐ¾Ð²Ð¾Ð¹ заÑплаÑой).
ÐконнÑе ÑÑнкÑии ÑазÑеÑаеÑÑÑ Ð¸ÑполÑзоваÑÑ Ð² запÑоÑе ÑолÑко в ÑпиÑке SELECT и пÑедложении ORDER BY. Ðо вÑеÑ
оÑÑалÑнÑÑ
пÑедложениÑÑ
, вклÑÑÐ°Ñ GROUP BY, HAVING и WHERE, они запÑеÑенÑ. ÐÑо обÑÑÑнÑеÑÑÑ Ñем, ÑÑо логиÑеÑки они вÑполнÑÑÑÑÑ Ð¿Ð¾Ñле ÑÑиÑ
пÑедложений, а Ñакже поÑле не оконнÑÑ
агÑегаÑнÑÑ
ÑÑнкÑий, и знаÑÐ¸Ñ Ð°Ð³ÑегаÑнÑÑ ÑÑнкÑÐ¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ вÑзÑваÑÑ Ð² аÑгÑменÑаÑ
оконной, но не наобоÑоÑ.
ÐÑли вам нÑжно оÑÑилÑÑÑоваÑÑ Ð¸Ð»Ð¸ ÑгÑÑппиÑоваÑÑ ÑÑÑоки поÑле вÑÑиÑÐ»ÐµÐ½Ð¸Ñ Ð¾ÐºÐ¾Ð½Ð½ÑÑ ÑÑнкÑий, Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе иÑполÑзоваÑÑ Ð²Ð»Ð¾Ð¶ÐµÐ½Ð½Ñй запÑоÑ. ÐапÑимеÑ:
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; ÐаннÑй запÑÐ¾Ñ Ð¿Ð¾ÐºÐ°Ð¶ÐµÑ ÑолÑко Ñе ÑÑÑоки внÑÑÑеннего запÑоÑа, Ñ ÐºÐ¾ÑоÑÑÑ
rank (поÑÑдковÑй номеÑ) менÑÑе 3.
Ðогда в запÑоÑе вÑÑиÑлÑÑÑÑÑ Ð½ÐµÑколÑко оконнÑÑ
ÑÑнкÑий Ð´Ð»Ñ Ð¾Ð´Ð¸Ð½Ð°ÐºÐ¾Ð²Ð¾ опÑеделÑннÑÑ
окон, конеÑно можно напиÑаÑÑ Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ из ниÑ
оÑделÑное пÑедложение OVER, но пÑи ÑÑом оно бÑÐ´ÐµÑ Ð´ÑблиÑоваÑÑÑÑ, ÑÑо неизбежно бÑÐ´ÐµÑ Ð¿ÑовоÑиÑоваÑÑ Ð¾Ñибки. ÐоÑÑÐ¾Ð¼Ñ Ð»ÑÑÑе опÑеделение окна вÑделиÑÑ Ð² пÑедложение WINDOW, а заÑем ÑÑÑлаÑÑÑÑ Ð½Ð° него в OVER. ÐапÑимеÑ:
SELECT sum(salary) OVER w, avg(salary) OVER w FROM empsalary WINDOW w AS (PARTITION BY depname ORDER BY salary DESC);
ÐодÑобнее об оконнÑÑ ÑÑнкÑиÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ ÑзнаÑÑ Ð² ÐодÑазделе 4.2.8, Разделе 9.22, ÐодÑазделе 7.2.5 и в ÑпÑавке SELECT.
[5] Рамки окна можно опÑеделÑÑÑ Ð¸ дÑÑгими ÑпоÑобами, но в ÑÑом введении они не ÑаÑÑмаÑÑиваÑÑÑÑ. УзнаÑÑ Ð¾ Ð½Ð¸Ñ Ð¿Ð¾Ð´Ñобнее Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе в ÐодÑазделе 4.2.8.