2017-07-06 28 views
1

數據庫是HP Vertica的7或PostgreSQL 9如何將SQL連接重寫到窗口函數中?

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); 

在最近一天使用的支付卡,什麼是在最近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; 

但結果集不匹配,這怎麼辦?

測試數據在這裏: http://sqlfiddle.com/#!17/db317/1

+0

首先,Postgres的和Vertica的是兩個完全不同的事情。其次,你爲什麼期望兩個截然不同的查詢結果是相同的? – mustaccio

回答

1

據我所知,PostgreSQL的窗口功能不支持有界range preceding因此range between '90 days' preceding將無法​​正常工作。它支持有界rows precedingrows between 90 preceding,但隨後你將需要彙集類似於窗口功能對基於時間的行操作以下是按時間順序查詢:

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

1

我不能嘗試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