SQL查找顶级父级

时间:2019-01-25 14:42:07

标签: sql sql-server tsql common-table-expression recursive-query

我有这张桌子:

Id  ParentId    LevelName
1   0           XXXX
2   0           XXXX
4   2           XXXX
5   2           XXXX
6   2           XXXX
7   2           XXXX
8   2           XXXX
9   2           XXXX
18  2           XXXX
19  18          XXXX
20  19          XXXX

我想要这样的顶层ParentId。如果我将传递Id 20,则它将返回2,这是表中的顶级ID:

 Id ParentId    LevelName
 2  0           XXXX

我的尝试

WITH cteReports (LvlID, PrntID, LevelID) AS
    (SELECT Id,
            ParentId,
            1
     FROM Levels
     WHERE Id = @ParentId
     UNION ALL
     SELECT e.Id,
            e.ParentId,
            r.LevelID + 1
     FROM Levels e
          INNER JOIN cteReports r ON e.ParentId = r.LvlID)
SELECT Id
FROM Levels
WHERE Id IN (SELECT LvlID FROM cteReports);

2 个答案:

答案 0 :(得分:3)

这应该做到:

DECLARE @start_id INT = 20;
WITH rcte AS (
    SELECT *
    FROM t
    WHERE id = @start_id

    UNION ALL

    SELECT curr.*
    FROM t    AS curr
    JOIN rcte AS prev ON curr.id = prev.parentid
)
SELECT *
FROM rcte
WHERE parentid = 0

答案 1 :(得分:0)

最大的问题是您的加入导致表格翻转。

DECLARE @Levels TABLE(
    ID INT,
    ParentID INT,
    LevelName VARCHAR(20)
)   
INSERT INTO @Levels (ID,ParentID,LevelName) SELECT 1   ,0           ,'XXXX'
INSERT INTO @Levels (ID,ParentID,LevelName) SELECT 2   ,0           ,'XXXX'
INSERT INTO @Levels (ID,ParentID,LevelName) SELECT 4   ,2           ,'XXXX'
INSERT INTO @Levels (ID,ParentID,LevelName) SELECT 5   ,2           ,'XXXX'
INSERT INTO @Levels (ID,ParentID,LevelName) SELECT 6   ,2           ,'XXXX'
INSERT INTO @Levels (ID,ParentID,LevelName) SELECT 7   ,2           ,'XXXX'
INSERT INTO @Levels (ID,ParentID,LevelName) SELECT 8   ,2           ,'XXXX'
INSERT INTO @Levels (ID,ParentID,LevelName) SELECT 9   ,2           ,'XXXX'
INSERT INTO @Levels (ID,ParentID,LevelName) SELECT 18  ,2           ,'XXXX'
INSERT INTO @Levels (ID,ParentID,LevelName) SELECT 19  ,18          ,'XXXX'
INSERT INTO @Levels (ID,ParentID,LevelName) SELECT 20  ,19          ,'XXXX'

DECLARE @TargetID INT=20;

WITH cteReports (Id, ParentId, LevelID) AS
(
    SELECT Id,
        ParentId,
        1
    FROM @Levels
    WHERE Id = @TargetID
    UNION ALL
    SELECT e.Id,
        e.ParentId,
        r.LevelID + 1
    FROM @Levels e
    INNER JOIN cteReports r ON r.ParentId = e.Id
)
SELECT lvl.*
FROM @Levels lvl
INNER JOIN cteReports cte ON cte.ID=lvl.ID
WHERE LevelID = (
    SELECT MAX(LevelID) AS MaxLevelID
    FROM cteReports
)