在分层查询中用父数据覆盖空值

Overwriting nulls with parent data in a hierarchical query

我有一个 table,格式如下:

pk    fk     parent
===== ====== ========
001   23     000
002   null   001
003   46     001
004   12     000
005   null   004
006   null   005
=====================

pk是每一行的主键,fk是另一个的外键table我稍后需要加入,parent是记录的分层父级。我可以使用

对此数据创建分层查询
select 
    lpad(' ',2*level)||pk "primary_key",
    fk "foreign_key",
    sys_connect_by_path(pk,'/') "path"
from example_table
connect by prior pk = parent
;

我的问题是如何用没有空值的最低祖先的外键覆盖行的 null 外键?我在这种情况下的预期输出是

pk        fk   parent
========= ==== ======
001       23   000
  002     23   001
  003     46   001
004       12   000
  005     12   004
    006   12   005
====================

(填充主键以显示层次结构。)

您可以使用标准递归通用 table 表达式来表达:

with cte (pk, fk, parent, lvl, pat) as (
    select to_char(pk), fk, parent, 0, to_char(pk) from mytable where parent = 0
    union all
    select lpad(' ', 2 * (lvl + 1)) || t.pk, coalesce(t.fk, c.fk), t.parent, c.lvl + 1, c.pat || '/' || t.pk
    from cte c
    inner join mytable t on t.parent = c.pk
)
select pk, fk, parent from cte order by pat

Demo on DB Fiddlde:

PK    | FK | PARENT
:---- | -: | -----:
1     | 23 |      0
  2   | 23 |      1
  3   | 46 |      1
4     | 12 |      0
  5   | 12 |      4
    6 | 12 |      5

只需使用 sys_connect_by_path(fk,'/') 聚合父 FK 并使用正则表达式取最后一个:

with example_table( pk, fk, parent) as (
select '001', 23  , '000' from dual union all
select '002', null, '001' from dual union all
select '003', 46  , '001' from dual union all
select '004', 12  , '000' from dual union all
select '005', null, '004' from dual union all
select '006', null, '005' from dual 
)
select 
    lpad(' ',2*level)||pk "primary_key",
    fk "foreign_key",
    nvl(fk, regexp_substr(sys_connect_by_path(fk,'/'),'(\d+)/*$',1,1,'',1)) fk2,
    sys_connect_by_path(pk,'/') "path"
from example_table
connect by prior pk = parent
;

结果:

primary_key  foreign_key        FK2 path
------------ ----------- ---------- --------------------------------------------------------------------------------
  001                 23         23 /001
    002                          23 /001/002
    003               46         46 /001/003
  004                 12         12 /004
    005                          12 /004/005
      006                        12 /004/005/006
  002                               /002
  003                 46         46 /003
  005                               /005
    006                             /005/006
  006                               /006

11 rows selected.