递归自引用 table 到平面结构

Recursive self referenced table to flat structure

Entity
---------
ID
TypeAID
TypeBID

TypeAIDTypeBID 是可为空的字段,其中行可以输入一个、两个或 none 值,并且两个 IDs 都指向相同的 table Entity.ID(自参考)。

有什么方法可以通过 3 层深层结构递归并获得 parent -> childparent -> grandchildchild -> grandchild 关系的平面结构?

这是示例,其中第一个 table 是正常层次结构,第二个是所需的平面输出。

数据:

Row   ID    TypeAID    TypeBID
1     A     NULL       NULL
2     B     NULL       NULL
3     C     A          NULL
4     D     B          C
5     E     NULL       C

想要的结果:

Row   Parent    Child
1     A         C
2     A         D
3     A         E
4     B         D
5     C         D
6     C         E

使用 CTE:

DECLARE @t TABLE (Id CHAR(1), TypeAId CHAR(1), TypeBId CHAR(1))

INSERT INTO @t VALUES
    ('A', NULL, NULL),
    ('B', NULL, NULL),
    ('C', 'A', NULL),
    ('D', 'B', 'C'),
    ('E', NULL, 'C')

-- All entities flattened
;WITH l1 AS (
    SELECT t.TypeAId AS Parent, t.Id AS Child
    FROM @t t
    WHERE t.TypeAId IS NOT NULL
    UNION
    SELECT t.TypeBId AS Parent, t.Id AS Child
    FROM @t t
    WHERE t.TypeBId IS NOT NULL)

-- Join l1 with itself
,l2 AS (
    SELECT l1.Parent, l2.Child
    FROM l1 l1
    INNER JOIN l1 l2 ON l2.Parent = l1.Child)

SELECT * FROM l1
UNION ALL SELECT * FROM l2
ORDER BY Parent

以下内容适用于任意数量的级别:

DECLARE @t table
(
    ID char(1)
    , TypeAID char(1)
    , TypeBID char(1)
)

INSERT INTO @t (ID, TypeAID, TypeBID)
VALUES
('A', NULL, NULL)
, ('B', NULL, NULL)
, ('C', 'A', NULL)
, ('D', 'B', 'C')
, ('E', NULL, 'C')
;

WITH cte
AS
(
    SELECT
        Parent
        , ID Child
    FROM
        (
            SELECT
                ID
                , TypeAID
                , TypeBID
            FROM @t
        ) D
        UNPIVOT
        (
            Parent FOR TypeID IN (
                [TypeAID]
                , [TypeBID]
            )
        ) U
)
,

cte2
AS
(
    SELECT
        Parent
        , Child
    FROM cte

    UNION ALL

    SELECT
        cte1.Parent
        , cte2.Child
    FROM
        cte2 cte1
        JOIN cte cte2 ON cte1.Child = cte2.Parent
)

SELECT
    Parent
    , Child
FROM cte2
ORDER BY
    Parent
    , Child