我有两张桌子(感兴趣)。第一个表是一个简单的层次结构。每行都有一个ID和一个父ID。显然,当我们到达特定层次结构的顶部时,父ID可以为NULL。 (我们在这里存储多个树,因此可以有多个NULL父项,但这可能不重要。)
第二个表包含具有非唯一标识符的对象,例如名称,时间戳和对第一个表的引用,以指示它所在的层次结构上的位置。
假设第一个表的层次结构为/A/B/C
,第二个表有一堆名为“Foo”的对象。如果我想在/A/B
中获取最新的Foo,那么我不想从C中得到任何东西。这看起来很简单。但是,如果/A/B
中的最新“Foo”在数据库中标记有一个字段,表示已将其删除,例如status = 'deleted'
,我想在/A
中获取最新的“Foo”即使在/A/B
中有其他具有早期时间戳的“Foo”对象。
这可以在CTE中做到吗?或者我是否必须求助于存储过程才能获得此类逻辑?我已经在使用一些存储过程仅用于重构目的,所以这不是障碍,但如果我能以更简单的方式做到这一点,那我可能会更好(包括性能)。
由于这可能有点模糊,我put this on SQLFiddle。如果我在模式的第24行添加覆盖,我应该将其作为输出。但是,如果我还在26中添加删除的对象,我需要回到“/ A中的更新”作为输出。
答案 0 :(得分:1)
我会用一个中间步骤扩展你的代码:
with recursive _rpath as (
select
0 as level,
id, parentid, name
from path
where id = 5 -- this would be filled in later
union all
select
child.level + 1 as level,
parent.id, parent.parentid, parent.name
from _rpath child
join path parent on child.parentid = parent.id
) , c AS (
select
rp, d, d.status
, ROW_NUMBER() OVER(PARTITION BY d.pathid ORDER BY d.creation DESC) AS rn
from data d
join _rpath rp
on rp.id = d.pathid
), datapaths AS (
SELECT *
FROM c
WHERE rn =1
AND status != 'deleted'
)
select dp.rp, dp.d
from datapaths dp
left join datapaths dpNext
on (dpNext.rp).level < (dp.rp).level or
((dpNext.rp).level = (dp.rp).level
and (dpNext.d).creation > (dp.d).creation)
where (dpNext.d).id is null;
<强> DBFiddle Demo 强>
工作原理:
-- calculate node number for each pathid sort by creation descending
-- newest one gets always 1
ROW_NUMBER() OVER(PARTITION BY d.pathid ORDER BY d.creation DESC)
-- get only first for each pathid but omit if it is 'deleted'
WHERE rn =1
AND status != 'deleted'