在层次结构中查找最新对象,其中最新未标记为已删除

时间:2018-03-15 19:36:51

标签: sql postgresql

我有两张桌子(感兴趣)。第一个表是一个简单的层次结构。每行都有一个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中的更新”作为输出。

1 个答案:

答案 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'