2016-03-08 93 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