greenplum last_value()函数

本文详细解析了Greenplum窗口函数的使用,包括first_value和last_value的特性,窗口范围的影响,以及在不同排序情况下的表现。通过案例分析,展示了优化窗口函数使用方法,将二次排序改进为一次排序,大幅提升了SQL执行效率。

greenplum窗口函数使用浅析

 最近处于系统不活跃期,没怎么升级,因此有了时间可以对整个ETL系统在稳定的基础上进行优化。每天列出TOP 10 COST TIME JOB进行分析,其中TOP1 COSTTIME JOB采用了窗口函数first_value和last_value,结果SQL全部使用的是first_value,并且为了全部使用first_value,对窗口函数进行了二次排序。通过explain这段代码,可以发现两次sort消耗的时候大概是一次sort的1.7倍,把sort二次改进成一次,并且把SQL从datastage迁移到greenplum的function里面,整个过程由24分钟降至40秒。

分析为什么只使用first_value的写法,且为了完全使用first_value不惜二次sort,原因如下:

WINDOW CALL: WINDOW window_name (partition by xxx order by xxx)
在使用first_value,last_value的时候,partition和order by会对得出的结果有影响。
分析函数包含三个分析子句:partition by,order by ,window.window里面rows的方式如下:unbounded preceding(第一行),current row(当前行),unbounded following(最后一行)
(1)语句为(partition by xxx order by xxx),则默认的窗口为 unbounded preceding and current row
(2)语句为(partition by xxx), 窗口默认为unbounded preceding and unbounded following
(3)语句为(),窗口默认为全体结果集。
可能出现的问题就是语句使用第一种方式的时候。
测试环境如下:
create table windowcheck
(
 oc_date  integer ,
city     varchar(50),
id       integer,
sale     integer
);
select *from windowcheck;
 oc_date  | city |  id  | sale  
----------+------+------+-------
20120701 | bj   | 3299 | 10040
20120701 | cs   | 3210 |  7100
20120701 | nj   | 3300 |  8900
20120701 | nj   | 3301 |  9000
20120701 | tj   | 3303 |  3890
20120701 | wh   | 3302 |  4700
select oc_date,city,id,sale,last_value(sale) over (partition by oc_date order by city) last_value
from windowcheck;
 oc_date  | city |  id  | sale  | last_value
----------+------+------+-------+------------
20120701 | bj   | 3299 | 10040 |      10040
20120701 | cs   | 3210 |  7100 |       7100
20120701 | nj   | 3301 |  9000 |       8900
20120701 | nj   | 3300 |  8900 |       8900
20120701 | tj   | 3303 |  3890 |       3890
20120701 | wh   | 3302 |  4700 |       4700
问题出来了:我们通过oc_date进行分区,对city进行排序,得出的结果集最后一个值为wh,其sale值为4700.那我们原来的想法就是结果集所有的last_value应该都为4700。那么问题出在哪个地方呢?问题出在之前写的窗口的范围上了。有partition与order的默认的窗口为 unbounded preceding and current row。此时,读取第一条的时候,窗口范围仅自己一条,其last_value值为10040,读取第二条的时候,窗口范围为第一条与自己这一条,那么得出last_value值 为7100,以此类推.解决方案就是把窗口范围扩大些。语句如下:
select oc_date,city,id,sale,last_value(sale) over (partition by oc_date order by city rows between unbounded preceding and unbounded following) last_value
from windowcheck;
到这里,把窗口范围大小会引起的歧义解决了。还有一个疑惑是:如果在使用分区函数的时候,这个SQL语句本身也进行排序会怎么样?因为SQL语句的结果集的顺序会影响ast_value或者first_value的值。这里就要分析整个语句的先后执行顺序了:分析函数是在整个SQL查询结束后(SQL语句中的ORDER BY的执行比较特殊)再进行的操作, 也就是说
SQL语句中的ORDER BY也会影响分析函数的执行结果。分析语句如下:
--产生结果集的SQL语句的order by与分区函数里面的order by是一致的
select oc_date,city,id,sale,last_value(sale) over (partition by oc_date order by city rows between unbounded preceding and unbounded following) last_value
from windowcheck order by city;
 oc_date  | city |  id  | sale  | last_value
----------+------+------+-------+------------
20120701 | bj   | 3299 | 10040 |       4700
20120701 | cs   | 3210 |  7100 |       4700
20120701 | nj   | 3301 |  9000 |       4700
20120701 | nj   | 3300 |  8900 |       4700
20120701 | tj   | 3303 |  3890 |       4700
20120701 | wh   | 3302 |  4700 |       4700
--产生结果集的SQL语句的order by与分区函数里面的order by不一致
select oc_date,city,id,sale,last_value(sale) over (partition by oc_date order by city rows between unbounded preceding and unbounded following) last_value
from windowcheck order by city desc;
 oc_date  | city |  id  | sale  | last_value
----------+------+------+-------+------------
20120701 | wh   | 3302 |  4700 |       4700
20120701 | tj   | 3303 |  3890 |       4700
20120701 | nj   | 3301 |  9000 |       4700
20120701 | nj   | 3300 |  8900 |       4700
20120701 | cs   | 3210 |  7100 |       4700
20120701 | bj   | 3299 | 10040 |       4700
由以上二个语句,可以分析出:产生结果集的SQL语句里面的order by不会对分区函数里面的结果造成影响,原因是如果结果集的order by与分区函数里面的不一致时,先使用分区函数里面的order by进行结果运算,然后再执行结果集里面的order by.如果一致,则分区函数分析时不需要排序。
GP里面使用WINDOW的另外方式
select oc_date,city,id,sale,last_value(sale) over (w) last_value
from windowcheck
where oc_date=20120701
WINDOW w as  (partition by oc_date order by city rows between unbounded preceding and unbounded following);

<think>好的,用户想了解Greenplum中date_sub函数的用法。我需要先确认这个函数Greenplum中的存在性,因为不同的数据库可能有不同的函数名称或语法。比如,MySQL有DATE_SUB,但PostgreSQL通常使用interval进行日期运算,而Greenplum是基于PostgreSQL的,所以可能也是这样。 首先,我应该检查Greenplum的官方文档,确认是否有date_sub函数。假设用户可能误用了函数名,或者Greenplum确实有这个函数。如果不存在,需要告诉用户替代方法,比如使用日期加减interval的方式。 然后,考虑用户可能需要的是如何从一个日期中减去特定的时间间隔。例如,减去几天、几个月等。这时候应该给出语法示例,比如使用current_date - interval '7 days',或者date_sub的等效函数,如果有的话。 另外,用户可能希望看到具体的例子,比如如何减去天数、月数,甚至更复杂的情况。需要提供不同的示例,并说明参数的使用方法。如果Greenplum不支持date_sub,应该明确说明,并指导用户使用正确的语法,比如直接使用减法操作符和interval类型。 还要注意用户提到的语法结构,可能包括参数顺序、返回值类型等。同时,检查是否有常见的错误用法,比如参数顺序颠倒,或者错误的时间单位,避免用户踩坑。 最后,生成相关问题时要围绕日期函数的使用,比如其他日期函数、加减日期的不同方法,或者常见错误处理,这样可以帮助用户更全面地了解相关知识。</think>### Greenplum DATE_SUB函数使用说明 Greenplum数据库中处理日期运算的标准方法是使用$interval$类型配合算术运算符[^1],其等效实现方式如下: #### 语法形式 ```sql 基准日期 - interval '数值 单位' ``` #### 参数说明 - $基准日期$:DATE/TIMESTAMP类型字段或表达式 - $数值$:整数类型的时间跨度 - $单位$:支持day/month/year/hour/minute/second等单位 #### 使用示例 1. 计算三天前的日期: ```sql SELECT current_date - interval '3 days'; -- 输出格式:2024-01-01(假设当前是2024-01-04) ``` 2. 处理带时间的减法运算: ```sql SELECT now() - interval '2 hours 30 minutes'; -- 输出格式:2024-01-04 10:30:00(假设当前是2024-01-04 13:00:00) ``` 3. 在表查询中应用: ```sql SELECT order_date - interval '7 days' AS prev_week FROM sales WHERE order_id = 1001; ``` #### 注意事项 1. 时间单位必须使用复数形式(如days/months) 2. 减号运算符两侧需要保留空格 3. 对于月份减法会自动处理月末日期: ```sql SELECT DATE '2024-03-31' - interval '1 month'; -- 返回2024-02-29(自动修正为有效日期) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值