Sql Server 2014 - глубокое рекурсивное самостоятельное объединение родителей и детей - PullRequest
0 голосов
/ 21 марта 2019

Я пытаюсь создать глубокий рекурсивный запрос на самообъединение. Имея стол вроде:

Id | ParentId
1  | NULL
2  | 1
3  | 1
4  | 2
5  | 3
6  | 8
7  | 9

Для идентификатора 1 мой запрос должен быть 1,2,3,4,5, поскольку они являются либо детьми 1, либо детьми детей 1. В приведенном примере 6 и 7 не должны включаться в запрос результат.

Я пытался использовать CTE, но получаю тонны дубликатов:

WITH CTE AS (
    SELECT Id, ParentId
    FROM dbo.Table
    WHERE ParentId IS NULL
UNION ALL
    SELECT t.Id, t.ParentId
    FROM dbo.Table t
    INNER JOIN CTE c ON t.ParentId = c.Id
)
SELECT * FROM CTE

Идеи

Ответы [ 5 ]

1 голос
/ 21 марта 2019

Вы можете попробовать использовать DISTINCT для фильтрации повторяющихся строк.

;WITH CTE AS (
    SELECT Id, ParentId
    FROM T
    WHERE ParentId IS NULL
UNION ALL
    SELECT t.Id, t.ParentId
    FROM T
    INNER JOIN CTE c ON t.ParentId = c.Id
)
SELECT DISTINCT Id, ParentId
FROM CTE
0 голосов
/ 21 марта 2019

Этот запрос поможет вам

CREATE TABLE #table( ID INT, ParentId INT )

INSERT INTO #table(ID,ParentId)
VALUES (1, NULL ), (2, 1 ), (3, 1 ), (4, 2 ), (5, 3 ), (6, 8 ), (7, 9 )

;WITH CTE AS (
SELECT ID FROM #table WHERE PARENTID IS NULL
UNION ALL
SELECT T.ID FROM #table T  
INNER JOIN  #table T1 ON T.PARENTID =T1.ID 
) SELECT * FROM CTE
0 голосов
/ 21 марта 2019

Я не вижу дубликатов.

Ваш код возвращает следующие данные на предоставленных вами данных:

Id  ParentId
1   
2   1
3   1
5   3
4   2

, что вы хотите.

Здесь - это дБ <> скрипка.

Вот код:

WITH t as (
      SELECT *
      FROM (VALUES (1, NULL), (2, 1), (3, 1), (4, 2), (5, 3), (6, 8), (7, 9)
           ) v(id, parentId)
    ),
    CTE AS (
    SELECT Id, ParentId
    FROM t
    WHERE ParentId IS NULL
UNION ALL
    SELECT t.Id, t.ParentId
    FROM t
    INNER JOIN CTE c ON t.ParentId = c.Id
)
SELECT *
FROM CTE;

Если вы получаете дубликаты в вашем фактическом наборе результатов, то, вероятно, у вас есть дубликаты в вашеморигинальный стол.Я бы рекомендовал удалить их перед выполнением рекурсивной логики:

with t as (
      select distinct id, parentid
      from <your query>
     ),
     . . .

Затем запустить рекурсивную логику.

0 голосов
/ 21 марта 2019

Попробуйте этот сценарий sql, который приведет к родительской дочерней иерархии

;WITH CTE(Id , ParentId)
AS
(
SELECT 1 , NULL  UNION ALL
SELECT 2 , 1     UNION ALL
SELECT 3 , 1     UNION ALL
SELECT 4 , 2     UNION ALL
SELECT 5 , 3     UNION ALL
SELECT 6 , 8     UNION ALL
SELECT 7 , 9
)
,Cte2
AS
(
    SELECT Id , 
          ParentId ,
         CAST('\'+ CAST(Id AS VARCHAR(MAX))AS VARCHAR(MAX)) AS [Hierarchy]
    FROM CTE
    WHERE ParentId IS NULL
    UNION ALL
    SELECT c1.Id , 
          c1.ParentId ,
        [Hierarchy]+'\'+ CAST(c1.Id AS VARCHAR(MAX)) AS [Hierarchy]
    FROM Cte2 c2
    INNER JOIN CTE c1
    ON  c1.ParentId = c2.Id
)
SELECT Id,
       RIGHT([Hierarchy],LEN([Hierarchy])-1) AS ParentChildHierarchy 
FROM Cte2

GO

Результат

Id  ParentChildHierarchy
-------------------------
1    1
2    1\2
3    1\3
5    1\3\5
4    1\2\4
0 голосов
/ 21 марта 2019

Попробуйте следующий запрос с CTE, где вы можете установить parentId с помощью @parentID:

DECLARE @parentID INT = 1
;WITH cte AS 
(
    SELECT 
    t.ID
    , t.ParentId
    FROM @table t
),
cteParent AS
(
    SELECT 
    t.ID
    , t.ParentId
    FROM @table t
    WHERE t.ParentId IN (SELECT t1.ID FROM @table t1 WHERE T1.ParentId = @parentID)
)

SELECT 
DISTINCT c1.ID
, c1.ParentId
FROM cte c1
INNER JOIN cte c2 ON c2.ParentId = c1.ID
UNION ALL 
SELECT * 
FROM cteParent

И пример данных:

DECLARE @table TABLE
(
    ID INT
    , ParentId INT
)

INSERT INTO @table
(
    ID,
    ParentId
)
VALUES
  (1, NULL )
, (2, 1 )

, (3, 1 )

, (4, 2 )

, (5, 3 )

, (6, 8 )

, (7, 9 )

ВЫХОД:

ID  ParentId
1   NULL
2   1
3   1
4   2
5   3
...