greenplum中的窗口函数,转自GP中文网

窗口表达式

窗口表达式允许应用开发者更容易地使用标准SQL命令构造复杂的在线分析处理(OLAP)查询。 例如,通过窗口查询,用户可以在多个区间上计算移动平均或者总和、在选择的列值改变时重置聚集和排名以及用简单的术语表达合比。

窗口表达式表示将一个窗口函数应用到一个窗口帧,后者在一个特殊的OVER()子句中定义。窗口分区是一个行的集合,这些行被集合起来应用一个窗口函数。这与使用聚合函数和GROUP BY子句可以完成的计算类型相当。和聚集函数(为每个行分组返回一个结果值)不同,窗口函数为每一行返回一个结果值,但是该结果值是针对一个特定窗口分区中的行计算得来。 如果没有指定分区,窗口函数会在完整的中间结果集上计算。

Greenplum数据库不支持将窗口函数制定为另一个窗口函数的参数。

窗口表达式的语法是:

window_function ( [expression [, ...]] ) OVER ( window_specification )
其中window_functionwindow_function是列在 Table 4中的函数之一,expression是任何不含窗口表达式的值表达式,而window_specification是:

[window_name]
[PARTITION BY expression [, ...]]
[[ORDER BY expression [ASC | DESC | USING operator] [NULLS {FIRST | LAST}] [, ...]
    [{RANGE | ROWS} 
       { UNBOUNDED PRECEDING
       | expression PRECEDING
       | CURRENT ROW
       | BETWEEN window_frame_bound AND window_frame_bound }]]

其中window_frame_bound可以是下列之一:

    UNBOUNDED PRECEDING
    expression PRECEDING
    CURRENT ROW
    expression FOLLOWING
    UNBOUNDED FOLLOWING

窗口只能出现在SELECT 命令的选择列表中。例如:

SELECT count(*) OVER(PARTITION BY customer_id), * FROM sales;

在窗口表达式中,一个窗口函数调用必须紧跟OVER 子句。OVER子句使得窗口函数与其他聚集或者报表函数相区别。OVER子句定义窗口函数要应用于其上的window_specification。

窗口说明具有下列特点:

PARTITION BY 子句定义窗口函数要应用于其上的窗口分区。如果省略,整个结果集会被当做一个分区。
ORDER BY 子句定义在窗口分区内用来排序行的表达式。 窗口说明的ORDER BY子句是独立的并且与一个常规查询表达式的ORDER BY 子句不同。 计算排名的窗口函数会要求ORDER BY 子句,因为它要确定排名值的排名程度。 对于OLAP聚集,使用窗口帧(ROWS和RANGE 子句)也要求ORDER BY子句。
Note: 没有一致排序的数据类型列(如 time)并不适合在窗口说明的ORDER BY子句中使用。 time(不管有没有指定的时区)缺少一种一致的排序,因为加法和减法无法得到预期的效果。例如,下面的式子并不总是为真:x::time < x::time + '2 hour'::interval
ROWS 或者 RANGE 子句为聚集(非排名)窗口函数定义窗口帧。一个窗口帧在一个窗口分区内定义一个行集合。当一个窗口帧被定义时,窗口函数会在这个移动帧的内容上计算,而不是在整个窗口分区的固定内容上计算。 窗口帧可以是基于行的(ROWS)或者基于值的(RANGE)。
窗口例子

以下示例演示如何使用带有分区和窗口框架的窗口函数

例1 –分区上的聚合窗口函数

在OVER子句用PARTITION BY将行进行分组或分区,在相同值的分组内使用指定表达式。

此例子比较员工工资和部门平均工资:

SELECT depname, empno, salary, avg(salary) OVER(PARTITION BY depname)
FROM empsalary;
  depname  | empno | salary |          avg          
-----------+-------+--------+-----------------------
 develop   |     9 |   4500 | 5020.0000000000000000
 develop   |    10 |   5200 | 5020.0000000000000000
 develop   |    11 |   5200 | 5020.0000000000000000
 develop   |     7 |   4200 | 5020.0000000000000000
 develop   |     8 |   6000 | 5020.0000000000000000
 personnel |     5 |   3500 | 3700.0000000000000000
 personnel |     2 |   3900 | 3700.0000000000000000
 sales     |     1 |   5000 | 4866.6666666666666667
 sales     |     3 |   4800 | 4866.6666666666666667
 sales     |     4 |   4800 | 4866.6666666666666667
(10 rows)

前三个输出列来自表empsalary,表中每一行都有一个输出行。第四列计算具有相同的 depname值的平均数。 相同的 depname行组成一个分区,在这个例子中有三个分区。 avg函数与常规的聚合函数avg相同, 但是 OVER子句使它被用作一个窗口函数。

你可以把窗口的命名放在WINDOW 子句中,在select中引用. 这个例子相当于之前的查询:

SELECT depname, empno, salary, avg(salary) OVER(mywindow)
FROM empsalary
WINDOW mywindow AS (PARTITION BY depname);

当select列表中有多个使用相同功能的窗口函数时,定义一个命名的窗口比较有用。

例2 – 使用ORDER BY子句对窗口函数进行排序

在OVER子句中的ORDER BY ,控制窗口函数处理行的顺序。 窗口函数的ORDER BY 列表不必匹配查询的输出顺序。 这个例子使用 rank() 窗口函数来排序部门内的员工工资:

SELECT depname, empno, salary,
    rank() OVER (PARTITION BY depname ORDER BY salary DESC)
FROM empsalary;
  depname  | empno | salary | rank 
-----------+-------+--------+------
 develop   |     8 |   6000 |    1
 develop   |    11 |   5200 |    2
 develop   |    10 |   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)
例3 – 行窗口帧的具体函数

A RANGE 或 ROWS子句定义窗口函数计算的窗口帧(一个分区内的多个行)。 ROWS指定要处理的物理行,例如从分区开始到当前行之间的所有行。

此例按部门计算员工工资的连续总额。使用 sum() 函数计算分区开始到当前行的总行数:

SELECT depname, empno, salary,
    sum(salary) OVER (PARTITION BY depname ORDER BY salary
        ROWS between UNBOUNDED PRECEDING AND CURRENT ROW)
FROM empsalary ORDER BY depname, sum;
  depname  | empno | salary |  sum  
-----------+-------+--------+-------
 develop   |     7 |   4200 |  4200
 develop   |     9 |   4500 |  8700
 develop   |    11 |   5200 | 13900
 develop   |    10 |   5200 | 19100
 develop   |     8 |   6000 | 25100
 personnel |     5 |   3500 |  3500
 personnel |     2 |   3900 |  7400
 sales     |     4 |   4800 |  4800
 sales     |     3 |   4800 |  9600
 sales     |     1 |   5000 | 14600
(10 rows)
例4 – Range窗口帧的聚合函数

RANGE 指定OVER子句中基于ORDER BY 表达式的逻辑值。这个例子展示了 ROWS和RANGE的不同。窗口帧包含小于或等于当前行的所有行的工资值。 与之前的例子不同,相同工资的员工,总和是相同的,包括所有这些员工的工资。

SELECT depname, empno, salary,
    sum(salary) OVER (PARTITION BY depname ORDER BY salary
        RANGE between UNBOUNDED PRECEDING AND CURRENT ROW)
FROM empsalary ORDER BY depname, sum;
  depname  | empno | salary |  sum  
-----------+-------+--------+-------
 develop   |     7 |   4200 |  4200
 develop   |     9 |   4500 |  8700
 develop   |    11 |   5200 | 19100
 develop   |    10 |   5200 | 19100
 develop   |     8 |   6000 | 25100
 personnel |     5 |   3500 |  3500
 personnel |     2 |   3900 |  7400
 sales     |     4 |   4800 |  9600
 sales     |     3 |   4800 |  9600
 sales     |     1 |   5000 | 14600
(10 rows)

下列内建窗口函数是Greenplum对于PostgreSQL数据库的扩展。所有的窗口函数都是immutable。

函数 返回类型 完整语法 描述

cume_dist() double precision

CUME_DIST() OVER ( [PARTITION BY expr ] ORDER BY expr ) 计算一组值中一个值的累积分布。具有相等值的行总是具有相同的累积分布值。

dense_rank() bigint

DENSE_RANK () OVER ( [PARTITION BY expr ] ORDER BY expr ) 计算一个有序行组中一行的无跳跃排名值的排名。具有相等值的行会得到相同的排名值。

first_value(expr) same as input expr type

FIRST_VALUE( expr ) OVER ( [PARTITION BY expr ] ORDER BY expr [ROWS|RANGE frame_expr ] ) 返回一个有续值集合中的第一个值。

lag(expr [,offset] [,default]) same as input expr type

LAG( expr [, offset ] [, default ]) OVER ( [PARTITION BY expr ] ORDER BY expr ) 在不做自连接的情况下,提供对于同一个表中多于一行的访问。给定一个查询返回的一系列行以及该游标的一个位置,LAG提供对位于该位置之前一个给定物理偏移量的行的访问。默认的offset为1。 default设置当偏移量超出窗口范围之外时要返回的值。如果没有指定default,默认值是空值。

last_value(expr) same as input expr type

LAST_VALUE(expr) OVER ( [PARTITION BY expr] ORDER BY expr [ROWS|RANGE frame_expr] ) 返回一个有序值集合中的最后一个值。

lead(expr [,offset] [,default]) same as input expr type

LEAD(expr [,offset] [,exprdefault]) OVER ( [PARTITION BY expr] ORDER BY expr ) 在不做自连接的情况下,提供对于同一个表中多于一行的访问。给定一个查询返回的一系列行以及该游标的一个位置,lead提供对位于该位置之后一个给定物理偏移量的行的访问。如果没有指定offset,默认偏移量是1。default设置当偏移量超出窗口范围之外时要返回的值。如果没有指定default,默认值是空值。

ntile(expr) bigint

NTILE(expr) OVER ( [PARTITION BY expr] ORDER BY expr ) 把一个有序数据集划分成一些桶(由expr)定义)并且为每一行分配一个桶号。

percent_rank() double precision

PERCENT_RANK () OVER ( [PARTITION BY expr] ORDER BY expr ) 计算一个假设行R的排名减1,然后除以被计算的行数(在一个窗口分区内)减1。

rank() bigint

RANK () OVER ( [PARTITION BY expr] ORDER BY expr ) 计算一行在一个有序值组中的排名。根据排名标准有相等值的行得到相同的排名。被占用的行数被加到排名数上来计算下一个排名值。在这种情况下,排名可能不是连续的数字。

row_number() bigint

ROW_NUMBER () OVER ( [PARTITION BY expr] ORDER BY expr ) 为窗口分区中的每一行或者查询中的每一行分配一个唯一的编号。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342