sql - PostgreSQL - 我应该如何使用 first_value()?

标签 sql postgresql postgresql-9.2 window-functions

这个答案显示了如何从代码生成高/低/开盘/收盘值:
Retrieve aggregates for arbitrary time intervals

我正在尝试基于此 (PG 9.2) 实现解决方案,但很难获得 first_value() 的正确值。

到目前为止,我已经尝试了两个查询:

SELECT  
    cstamp,
    price,
    date_trunc('hour',cstamp) AS h,
    floor(EXTRACT(minute FROM cstamp) / 5) AS m5,
    min(price) OVER w,
    max(price) OVER w,
    first_value(price) OVER w,
    last_value(price) OVER w
FROM trades
Where date_trunc('hour',cstamp) = timestamp '2013-03-29 09:00:00'
WINDOW w AS (
    PARTITION BY date_trunc('hour',cstamp), floor(extract(minute FROM cstamp) / 5)
    ORDER BY date_trunc('hour',cstamp) ASC, floor(extract(minute FROM cstamp) / 5) ASC
    )
ORDER BY cstamp;

这是结果的一部分:

        cstamp         price      h                 m5  min      max      first    last
"2013-03-29 09:19:14";77.00000;"2013-03-29 09:00:00";3;77.00000;77.00000;77.00000;77.00000

"2013-03-29 09:26:18";77.00000;"2013-03-29 09:00:00";5;77.00000;77.80000;77.80000;77.00000
"2013-03-29 09:29:41";77.80000;"2013-03-29 09:00:00";5;77.00000;77.80000;77.80000;77.00000
"2013-03-29 09:29:51";77.00000;"2013-03-29 09:00:00";5;77.00000;77.80000;77.80000;77.00000

"2013-03-29 09:30:04";77.00000;"2013-03-29 09:00:00";6;73.99004;77.80000;73.99004;73.99004

如您所见,77.8 不是我认为 first_value() 的正确值,它应该是 77.0。

虽然这可能是由于 WINDOW 中的 ORDER BY 不明确,所以我将其更改为

ORDER BY cstamp ASC 

但这似乎也打乱了PARTITION:

        cstamp         price      h                 m5  min      max      first    last
"2013-03-29 09:19:14";77.00000;"2013-03-29 09:00:00";3;77.00000;77.00000;77.00000;77.00000

"2013-03-29 09:26:18";77.00000;"2013-03-29 09:00:00";5;77.00000;77.00000;77.00000;77.00000
"2013-03-29 09:29:41";77.80000;"2013-03-29 09:00:00";5;77.00000;77.80000;77.00000;77.80000
"2013-03-29 09:29:51";77.00000;"2013-03-29 09:00:00";5;77.00000;77.80000;77.00000;77.00000

"2013-03-29 09:30:04";77.00000;"2013-03-29 09:00:00";6;77.00000;77.00000;77.00000;77.00000

因为 max 和 last 的值 在分区内变化

我做错了什么?有人可以帮助我更好地理解 WINDOWPARTITIONORDER 之间的关系吗?


虽然我有一个答案,但这里有一个精简的 pg_dump,它将允许任何人重新创建表。唯一不同的是表名。

CREATE TABLE wtest (
    cstamp timestamp without time zone,
    price numeric(10,5)
);

COPY wtest (cstamp, price) FROM stdin;
2013-03-29 09:04:54 77.80000
2013-03-29 09:04:50 76.98000
2013-03-29 09:29:51 77.00000
2013-03-29 09:29:41 77.80000
2013-03-29 09:26:18 77.00000
2013-03-29 09:19:14 77.00000
2013-03-29 09:19:10 77.00000
2013-03-29 09:33:50 76.00000
2013-03-29 09:33:46 76.10000
2013-03-29 09:33:15 77.79000
2013-03-29 09:30:08 77.80000
2013-03-29 09:30:04 77.00000
\.

最佳答案

SQL Fiddle

您使用的所有功能都作用于窗框,而不是分区。如果省略,则帧末尾是当前行。要使窗口框架成为整个分区,请在 frame 子句 (range...) 中声明它:

SELECT  
    cstamp,
    price,
    date_trunc('hour',cstamp) AS h,
    floor(EXTRACT(minute FROM cstamp) / 5) AS m5,
    min(price) OVER w,
    max(price) OVER w,
    first_value(price) OVER w,
    last_value(price) OVER w
FROM trades
Where date_trunc('hour',cstamp) = timestamp '2013-03-29 09:00:00'
WINDOW w AS (
    PARTITION BY date_trunc('hour',cstamp) , floor(extract(minute FROM cstamp) / 5)
    ORDER BY cstamp
    range between unbounded preceding and unbounded following
    )
ORDER BY cstamp;

关于sql - PostgreSQL - 我应该如何使用 first_value()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15721207/

相关文章:

java - 如何在插入行之前在 Sybase SQL 中生成 ID

postgresql - PostgreSQL 将大型 csv 文件加载到表中时出现问题

sql - 如何从 PostgreSQL 触发器发送电子邮件?

ruby-on-rails - 连接被拒绝(PGError)(postgresql 和 rails)

postgresql - 如何从 Ubuntu 命令行将用户添加到 PostgreSQL?

mysql - 询问!我如何获得每个用户三张 table 的总餐费和费用!这是我的第一个问题,很抱歉给您带来不便

php - Sql从字符串中选择数据选择id

sql - 在该范围内每天将 "From"和 "To"日期列扩展到 1 行

postgresql - 如何使 Microstrategy 与 Redshift/psql 表中的用户模式一起工作?

Postgresql 使用索引对连接表进行排序