我有下表:
CREATE TABLE temp (
grp int,
version int,
deleted boolean not null,
PRIMARY KEY (grp, version)
);
对于每个实体(grp
),可以存在多个版本(version
),版本号越大,版本的创建时间越近。由于各种原因,通常可以隐藏版本(deleted
)。通常可能会隐藏整个实体,在这种情况下,version
的所有grp
都将为deleted
。
我想为每个实体选择/加入/过滤一行,其中该行是未删除的最新版本,如果删除了所有该实体的版本,则为最新版本。
我目前有一个使用union的解决方案,但我担心如果我尝试对union进行进一步的连接或过滤,性能会很差,我宁愿不必在每个中重复这些连接/过滤器联合查询。
下面的查询是否可以重写,以便不需要联合?
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
答案 0 :(得分:2)
在Postgres中,我认为最简单的解决方案使用distinct on
:
select distinct on (grp) t.*
from temp t
order by grp,
deleted::int asc,
version desc;
每组保留一行。该行是基于order by
子句的第一行。
答案 1 :(得分: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