SQL 复杂的递归 CTE

SQL complicated recursive CTE

我在 SQL Server 2014 中工作。我有一个奇怪的数据层次结构情况。 (至少,我以前没有经历过这样的事情。)

在我的层次结构中,有几个根/最高级别的对象。根级别以下的每个对象都映射到它上面的一个且仅一个对象。并非每个节点路径的长度都相同。例如,一条路径中可以有 2 个对象级别,而另一条路径中可以有 20 个对象级别。

层次结构中的每个对象都有一个 IsInherited 属性,以及一些其他属性(称之为 SomeAttribute)。 IsInherited 属性指示给定对象是否从其最直接的父对象继承了 SomeAttribute 的值。自然地,如果对象的 IsInherited 属性是 'Y',则给定对象从其最直接的父对象继承 SomeAttribute 的值(反过来,它可以继承其最直系亲属等)。否则,指定对象的 SomeAttribute 值。

现在,上述所有情况都不一定不常见。使这种情况不常见的是这种继承的特定实现。此层次结构存储在单个 table 中(这是否使它成为邻接列表模型?),并且 SomeAttribute 的值是 not 填充给定对象/ 行,如果它的 IsInherited 属性是 'Y'.

我的目标是 return 层次结构中所有对象的 SomeAttribute 值。

table的样本如下:

CREATE TABLE hierarchy (
    ID int NOT NULL
    ,ParentID int NULL
    ,SomeAttribute char(1) NULL
    ,IsInherited char(1) NOT NULL
)
;
INSERT INTO hierarchy (ID, ParentID, SomeAttribute, IsInherited)
VALUES
(1, NULL, 'a', 'N')
,(2, NULL, 'b', 'N')
,(3, NULL, 'c', 'N')
,(4, NULL, 'd', 'N')
,(5, NULL, 'e', 'N')
,(6, NULL, 'f', 'N')
,(7, NULL, 'g', 'N')
,(8, 2, NULL, 'Y')
,(9, 3, 'h', 'N')
,(10, 4, NULL, 'Y')
,(11, 5, 'j', 'N')
,(12, 6, NULL, 'Y')
,(13, 6, 'k', 'N')
,(14, 7, 'l', 'N')
,(15, 7, 'm', 'N')
,(16, 10, NULL, 'Y')
,(17, 11, NULL, 'Y')
,(18, 16, NULL, 'Y')
,(19, 17, NULL, 'Y')
,(20, 19, 'o', 'N')
;

这为我们提供了以下节点路径:

1
2-8
3-9
4-10-16-18
5-11-17-19-20
6-12,13
7-14,15

因此,对于此示例 table,我希望 return:

ID    SomeAttribute
1     a
2     b
3     c
4     d
5     e
6     f
7     g
8     b (inherited from 2)
9     h
10    d (inherited from 4)
11    j
12    f (inherited from 6)
13    k
14    l
15    m
16    d (inherited from 10, inherited from 4)
17    j (inherited from 11)
18    d (inherited from 16, inherited from 10, inherited from 4)
19    j (inherited from 17, inherited from 11)
20    o

我知道这可能需要递归 CTE。我正在努力为此编写 SQL。我如何 return 我想要的输出?

这是邻接表模型,因为每一行代表一对相邻节点。

递归 CTE 如下所示:

 with q as
(
  select id, SomeAttribute, cast(id as varchar(max)) SomeAttributePath
  from hierarchy
  where ParentID is null
  union all
  select c.id, case when c.IsInherited = 'Y' then q.SomeAttribute else c.SomeAttribute end as SomeAttribute, cast(concat(q.SomeAttributePath,'-',c.id) as varchar(max))
  from q
  join hierarchy c
  on c.ParentID = q.ID
)
select *
from q
order by id

输出:

id          SomeAttribute SomeAttributePath
----------- ------------- -----------------
1           a             1
2           b             2
3           c             3
4           d             4
5           e             5
6           f             6
7           g             7
8           b             2-8
9           h             3-9
10          d             4-10
11          j             5-11
12          f             6-12
13          k             6-13
14          l             7-14
15          m             7-15
16          d             4-10-16
17          j             5-11-17
18          d             4-10-16-18
19          j             5-11-17-19
20          o             5-11-17-19-20