数据库是HP Vertica 7或PostgreSQL 9。
create table test (
id int,
card_id int,
tran_dt date,
amount int
);
insert into test values (1, 1, '2017-07-06', 10);
insert into test values (2, 1, '2017-06-01', 20);
insert into test values (3, 1, '2017-05-01', 30);
insert into test values (4, 1, '2017-04-01', 40);
insert into test values (5, 2, '2017-07-04', 10);
在过去1天内使用的支付卡中,过去90天内该卡上的最高金额是多少。
select t.card_id, max(t2.amount) max
from test t
join test t2 on t2.card_id=t.card_id and t2.tran_dt>='2017-04-06'
where t.tran_dt>='2017-07-06'
group by t.card_id
order by t.card_id;
结果是正确的
card_id max
------- ---
1 30
我想将查询重写为sql窗口函数。
select card_id, max(amount) over(partition by card_id order by tran_dt range between '60 days' preceding and current row) max
from test
where card_id in (select card_id from test where tran_dt>='2017-07-06')
order by card_id;
但结果集不匹配,怎么办呢?
答案 0 :(得分:2)
我无法尝试PostgreSQL,但在Vertica中,您可以应用ANSI标准OLAP窗口功能。
但是您需要嵌套两个查询:如果窗口函数具有需要在结果集中计算的所有行,则它仅返回合理的结果。
但您只想显示“2017-07-06”中的行。
因此,您必须在外部查询中过滤该日期:
WITH olap_output AS (
SELECT
card_id
, tran_dt
, MAX(amount) OVER (
PARTITION BY card_id
ORDER BY tran_dt
RANGE BETWEEN '90 DAYS' PRECEDING AND CURRENT ROW
) AS the_max
FROM test
)
SELECT
card_id
, the_max
FROM olap_output
WHERE tran_dt='2017-07-06'
;
card_id|the_max
1| 30
答案 1 :(得分:1)
据我所知,PostgreSQL窗口函数不支持有界range preceding
,因此range between '90 days' preceding
不起作用。它确实支持有界rows preceding
,例如rows between 90 preceding
,但是你需要为Window函数组装类似于以下内容的时间序列查询,以便对基于时间的行进行操作:
SELECT c.card_id, t.amount, g.d as d_series
FROM generate_series(
'2017-04-06'::timestamp, '2017-07-06'::timestamp, '1 day'::interval
) g(d)
CROSS JOIN ( SELECT distinct card_id from test ) c
LEFT JOIN test t ON t.card_id = c.card_id and t.tran_dt = g.d
ORDER BY c.card_id, d_series
根据您的需要(根据您的问题描述),我会坚持使用group by
。