最简单的递归自联接方式?

Chr*_*ris 93 sql sql-server recursion self-join hierarchical-data

在SQL Server中执行递归自联接的最简单方法是什么?我有这样一张桌子:

PersonID | Initials | ParentID
1          CJ         NULL
2          EB         1
3          MB         1
4          SW         2
5          YT         NULL
6          IS         5
Run Code Online (Sandbox Code Playgroud)

而且我希望能够获得仅与特定人员开始的层次结构相关的记录.所以,如果我通过PersonID = 1请求CJ的层次结构,我会得到:

PersonID | Initials | ParentID
1          CJ         NULL
2          EB         1
3          MB         1
4          SW         2
Run Code Online (Sandbox Code Playgroud)

对于EB,我会得到:

PersonID | Initials | ParentID
2          EB         1
4          SW         2
Run Code Online (Sandbox Code Playgroud)

我有点卡住这个可以想不出怎么做除了基于一堆连接的固定深度响应.这会发生,因为我们不会有很多级别,但我想做得恰到好处.

谢谢!克里斯.

Qua*_*noi 101

WITH    q AS 
        (
        SELECT  *
        FROM    mytable
        WHERE   ParentID IS NULL -- this condition defines the ultimate ancestors in your chain, change it as appropriate
        UNION ALL
        SELECT  m.*
        FROM    mytable m
        JOIN    q
        ON      m.parentID = q.PersonID
        )
SELECT  *
FROM    q
Run Code Online (Sandbox Code Playgroud)

通过添加排序条件,您可以保留树顺序:

WITH    q AS 
        (
        SELECT  m.*, CAST(ROW_NUMBER() OVER (ORDER BY m.PersonId) AS VARCHAR(MAX)) COLLATE Latin1_General_BIN AS bc
        FROM    mytable m
        WHERE   ParentID IS NULL
        UNION ALL
        SELECT  m.*,  q.bc + '.' + CAST(ROW_NUMBER() OVER (PARTITION BY m.ParentID ORDER BY m.PersonID) AS VARCHAR(MAX)) COLLATE Latin1_General_BIN
        FROM    mytable m
        JOIN    q
        ON      m.parentID = q.PersonID
        )
SELECT  *
FROM    q
ORDER BY
        bc
Run Code Online (Sandbox Code Playgroud)

通过更改ORDER BY条件,您可以更改兄弟姐妹的顺序.

  • +1,除了Chris需要`PersonID = theIdYouAreLookingFor`而不是`ParentID IS NULL`. (7认同)
  • 在我将第一行更改为“WITH RECURSIVE q AS”之前,此查询对我不起作用,作为参考,我正在使用“10.3.23-MariaDB-0+deb10u1” (3认同)

Adr*_*der 23

使用CTE你可以这样做

DECLARE @Table TABLE(
        PersonID INT,
        Initials VARCHAR(20),
        ParentID INT
)

INSERT INTO @Table SELECT     1,'CJ',NULL
INSERT INTO @Table SELECT     2,'EB',1
INSERT INTO @Table SELECT     3,'MB',1
INSERT INTO @Table SELECT     4,'SW',2
INSERT INTO @Table SELECT     5,'YT',NULL
INSERT INTO @Table SELECT     6,'IS',5

DECLARE @PersonID INT

SELECT @PersonID = 1

;WITH Selects AS (
        SELECT *
        FROM    @Table
        WHERE   PersonID = @PersonID
        UNION ALL
        SELECT  t.*
        FROM    @Table t INNER JOIN
                Selects s ON t.ParentID = s.PersonID
)
SELECT  *
FROm    Selects
Run Code Online (Sandbox Code Playgroud)

  • 很好的完整答案,重要的 WHERE PersonID = @PersonID (2认同)

小智 5

对大表进行了更改的 Quassnoi 查询。孩子多于 10 岁的父母:将 row_number() 格式化为 str(5)

与 q AS 
        (
        SELECT m.*, CAST(str(ROW_NUMBER() OVER (ORDER BY m.ordernum),5) AS VARCHAR(MAX)) COLLATE Latin1_General_BIN AS bc
        从#tm
        哪里 ParentID =0
        联合所有
        选择 m.*, q.bc + '.' + str(ROW_NUMBER() OVER (PARTITION BY m.ParentID ORDER BY m.ordernum),5) COLLATE Latin1_General_BIN
        从#tm
        加入q
        ON m.parentID = q.DBID
        )
选择 *
从 q
订购者
        公元前