postgreSQL to select 昨天的值,一个月的平均值

postgreSQL to select value of yesterday, month average

我有一个 PostgreSQL table:

create table UV(
f_date int,
uv bigint
)

数据:

f_date   |   uv 
---------+-------
20150103 | 620964 
20150104 | 595367

那么如何使用 sql 生成这样的 table:

f_date   |   uv_today | uv_yesterday |  uv_month_avg
---------+------------+--------------+--------------
20150103 | 620964     |(uv of 20150102)| average uv from 20141204 to 20150103
20150104 | 595367     |  620964        |

我会选择 select 列表中的子 select:

select f_date,
       uv as uv_today,
       (select uv from uv as u2
        where u2.f_date = uv.f_fdate - 1) as uv_yesterday,
       (select avg(uv) from uv as u2
        where u2.f_date between uv.f_fdate - 30 and uv.f_fdate) as uv_month_avg
from uv

请注意,我没有注意正确计算负 1 个月,因为我不知道在 postgresql 中是如何完成的,只用了 - 30 天。

首先:不要将日期存储为整数!如果你想约会就用date!尤其不要将日期存储为具有用于表示年、月和日的位值的整数。严重地。在继续实际使用它之前,您需要修复此模式。要么将纪元值存储为儒略日期,要么使用本机数据类型 datetimestampinterval 进行适当的 date/time 工作。

第一部分是 window 函数的简单应用;只是 lag(uv, 1) OVER (ORDER BY f_date).

第二个有点棘手,但一旦您修复了架构,它就不会太糟糕。您可以使用 avg(uv) OVER (PARTITION BY date_trunc('month', f_date)),假设您想要一个日历月。如果你想要30天的间隔,那就另当别论了。

所以像这样:

create table UV(
f_date date,
uv bigint
);

insert into UV (f_date, uv)
VALUES ('20150103', '620964'),
       ('20150104', '595367');

SELECT
  f_date,
  uv,
  lag(uv, 1) OVER (ORDER BY f_date),
  avg(uv) OVER (PARTITION BY date_trunc('month', f_date))
FROM UV;

如图:http://sqlfiddle.com/#!15/c953f/1