2016-03-08 92 views
1

我有如下表:重寫UNION作爲JOIN

CREATE TABLE temp (
    grp   int, 
    version  int, 
    deleted  boolean not null, 
    PRIMARY KEY (grp, version) 
); 

對於每個實體(grp)有可能存在多個版本(version),較大的版本號最近的版本已創建。由於各種原因,版本通常可能會隱藏(deleted)。這可能是整個實體一般應隱藏的,在這種情況下,所有version■對於grpdeleted

我要選擇/加盟/過濾每一行對應一個實體,其中該行要麼是最新版本不會被刪除,或最新版本,如果所有實體的版本將被刪除。

我目前有一個使用聯合的解決方案,但我擔心如果我嘗試對聯合進行進一步的聯接或篩選,性能會很差,我寧願不必在每個聯合中重複這些聯接/篩選的聯合查詢。

可以下面的查詢被改寫,使得工會不需要?

SELECT 
    main.grp 
    , main.version 
    , main.deleted 
-- , current_filter.version 
-- , current_filter.deleted 
FROM temp AS main 
LEFT JOIN temp AS current_filter 
    ON (
     current_filter.grp = main.grp 
     AND current_filter.version > main.version 
     AND NOT current_filter.deleted 
    ) 
WHERE 
    current_filter.version IS null 
    AND NOT main.deleted 
UNION 
SELECT 
    main.grp 
    , main.version 
    , main.deleted 
-- , current_filter.version 
-- , current_filter.deleted 
-- , any_not_deleted.version 
-- , any_not_deleted.deleted 
FROM temp AS main 
LEFT JOIN temp AS current_filter 
    ON (
     current_filter.grp = main.grp 
     AND current_filter.version > main.version 
    ) 
LEFT JOIN temp AS any_not_deleted 
    ON (
     any_not_deleted.grp = main.grp 
     AND any_not_deleted.version < main.version 
     AND NOT any_not_deleted.deleted 
    ) 
WHERE 
    current_filter.version IS null 
    AND any_not_deleted.version IS null 
    AND main.deleted 
ORDER BY grp, version 

SQLFiddle:http://sqlfiddle.com/#!15/f0b7d/1/0

回答

2

在Postgres裏,我覺得最簡單的解決方案使用distinct on

select distinct on (grp) t.* 
from temp t 
order by grp, 
     deleted::int asc, 
     version desc; 

這樣可以使每個組一行。該行是第一個基於order by條款的行。

+0

非常感謝您! – Matt

0

您可以通過使用ROW_NUMBER()獲得相同的結果:

select t.grp, t.version , t.deleted 
from 
(select t.grp, t.version , t.deleted 
     , row_number() over (partition by grp order by deleted asc , version desc) as rnum 
    from temp t) t 
where rnum = 1   

SQLFiddle:http://sqlfiddle.com/#!15/934ba/11