答:因为跟 GROUP BY 一起使用的聚合函数针对的记录集合是每一个分组,排不排序不影响最终结果,而窗口函数针对的记录集合是每一个窗口里的子范围(这个子范围即”框架“,下面即将介绍 ),所以排序很关键。
ORDER BY 可以省略,即默认排序。
4、ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING 中,ROWS 用来定义窗口内的(行)范围,称为框架。
有三种写法:
① ROWS 2 PRECEDING -- 之前
② ROWS 2 FOLLOWING -- 之后
③ ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING -- 之间
可用 UNBOUNDED 代替数字表示无边界。
以 ① 为例,ROWS 2 PRECEDING 就是将窗口内的范围指定为“截止到之前 2 行”,也就是将作为汇总对象的记录限定为如下的 “最靠近的 3 行”:
● 自身(当前记录)
● 之前1行的记录
● 之前2行的记录
这样的统计方法称为移动平均(moving average)。
由于这种方法在希望实时把握“最近状态”时非常方便,因此常常会应用在对股市趋势的实时跟踪当中。
ROWS 可以省略,默认值为:
若不指定 ORDER BY,默认使用窗口内所有行,等于 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
若指定了 ORDER BY,默认使用窗口内第一行到当前值 ,等于ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
(3)应用场景例子1(用于累计):
SELECT product_id, product_name, sale_price, AVG (sale_price) OVER (ORDER BY product_id) AS current_avg FROM Product;结果:
product_id | product_name | sale_price | current_avg ----------+-----------+-------------+----------------------- 0001 | T恤衫 | 1000 | 1000.0000000000000000 ←(1000)/1 0002 | 打孔器 | 500 | 750.0000000000000000 ←(1000+500)/2 0003 | 运动T恤 | 4000 | 1833.3333333333333333 ←(1000+500+4000)/3 0004 | 菜刀 | 3000 | 2125.0000000000000000 ←(1000+500+4000+3000)/4 0005 | 高压锅 | 6800 | 3060.0000000000000000 ←(1000+500+4000+3000+6800)/5 0006 | 叉子 | 500 | 2633.3333333333333333 0007 | 擦菜板 | 880 | 2382.8571428571428571 0008 | 圆珠笔 | 100 | 2097.5000000000000000例子2(用于排名):
先介绍 3 个专用窗口函数,用来排名的。
RANK函数
计算排序时,如果存在相同位次的记录,则会跳过之后的位次。
例:有3 条记录排在第1 位时:1 位、1 位、1 位、4 位……
DENSE_RANK函数
同样是计算排序,即使存在相同位次的记录,也不会跳过之后的位次。
例:有3 条记录排在第1 位时:1 位、1 位、1 位、2 位……
ROW_NUMBER函数
赋予唯一的连续位次。
例:有3 条记录排在第1 位时:1 位、2 位、3 位、4 位……
例子:
SELECT product_name, product_type, sale_price, RANK () OVER (ORDER BY sale_price) AS ranking, DENSE_RANK () OVER (ORDER BY sale_price) AS dense_ranking, ROW_NUMBER () OVER (ORDER BY sale_price) AS row_num FROM Product;结果:
product_name | product_type | sale_price | ranking | dense_ranking | row_num 圆珠笔 | 办公用品 | 100 | 1 | 1 | 1 叉子 | 厨房用具 | 500 | 2 | 2 | 2 打孔器 | 办公用品 | 500 | 2 | 2 | 3 擦菜板 | 厨房用具 | 880 | 4 | 3 | 4 T恤衫 | 衣服 | 1000 | 5 | 4 | 5 菜刀 | 厨房用具 | 3000 | 6 | 5 | 6 运动T恤 | 衣服 | 4000 | 7 | 6 | 7 高压锅 | 厨房用具 | 6800 | 8 | 7 | 8上面的 累计 和 排名,本质上都属于同一种计算逻辑,即冯·诺依曼型递归集。
(4)提取 OVER 变量如果在 SQL 里写了很多重复的 OVER(),可以提取成一个 window 变量,简化代码。
SELECT *, avg("score") OVER window_frame as "subject_avg_score", avg("score") OVER window_frame as "subject_avg_score_2", avg("score") OVER window_frame as "subject_avg_score_3" FROM "testScore" window window_frame as (PARTITION BY "subject") 2、GROUPING 运算符 1、ROLLUPーー同时得出合计和小计 ( GROUPING 函数ーー让 NULL 更加容易分辨 )ROLLUP 可以用来同时得出合计和小计。而避免用 UNION 繁琐的方式。
(1)只用 ROLLUP SELECT product_type, regist_date, SUM(sale_price) AS sum_price FROM Product GROUP BY ROLLUP(product_type, regist_date);结果:
product_type regist_date sum_price16780
厨房用具 11180
厨房用具 2008-04-28 880
厨房用具 2009-01-15 6800
厨房用具 2009-09-20 3500
办公用品 600
办公用品 2009-09-11 500
办公用品 2009-11-11 100
衣服 5000
衣服 2009-09-20 1000
衣服 4000
GROUP BY ROLLUP (product_type, regist_date); 的结果等于:
① GROUP BY ()
② GROUP BY (product_type)
③ GROUP BY (product_type, regist_date)
三者的 UNION。
其中 ① 中的 GROUP BY () 表示没有聚合键,也就相当于没有 GROUP BY 子句(这时会得到全部数据的合计行的记录)。