Sql 将UNION重写为JOIN

Sql 将UNION重写为JOIN,sql,postgresql,Sql,Postgresql,我有下表: CREATE TABLE temp ( grp int, version int, deleted boolean not null, PRIMARY KEY (grp, version) ); 对于每个实体grp,可以存在多个版本,版本号越大,创建版本的时间越近。由于各种原因,版本通常会被隐藏或删除。可能整个实体通常都应该隐藏,在这种情况下,grp的所有版本都将被删除 我想为每个实体选择/加入/筛选一行,其中该行要么

我有下表:

CREATE TABLE temp (
    grp         int,
    version     int,
    deleted     boolean not null,
    PRIMARY KEY (grp, version)
);
对于每个实体grp,可以存在多个版本,版本号越大,创建版本的时间越近。由于各种原因,版本通常会被隐藏或删除。可能整个实体通常都应该隐藏,在这种情况下,grp的所有版本都将被删除

我想为每个实体选择/加入/筛选一行,其中该行要么是未删除的最新版本,要么是已删除该实体所有版本的最新版本

我目前有一个使用联合的解决方案,但我担心如果我尝试对联合进行进一步的连接或过滤,性能会很差,我不希望在每个联合查询中重复这些连接/过滤

下面的查询是否可以重写为不需要联合

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:

在Postgres中,我认为最简单的解决方案是使用distinct on:


这将保持每组一行。该行是基于order by子句的第一行。

使用row\u编号可以得到相同的结果:

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:

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