Необходимо получить список дочерних элементов в хранимой процедуре

#sql #sql-server-2008 #tsql #stored-procedures #hierarchy

#sql #sql-server-2008 #tsql #хранимые процедуры #иерархия

Вопрос:

Описание:

Существует таблица, состоящая из двух столбцов (ParentID и childID), которая отображает иерархию некоторых объектов. Каждый идентификатор может быть представлен в столбце ParentID только один раз. Это означает, что у каждой сущности есть только одна дочерняя сущность.

Проблема: мне нужно проверить, есть ли объект (его идентификатор) в списке потомков родительского объекта.

Комментарии:

1. Вы пытаетесь выполнить обнаружение цикла?

2. Существует ли уникальное ограничение на ParentID?

3. Пара ParentID и childID является уникальным ограничением. Но никаких других ограничений в таблице нет.

Ответ №1:

 DECLARE @parentId INT
DECLARE @childId INT
DECLARE @targetChildId INT
SET @targetChildId=<put id of a child you want to find>
SET @parentId=<put id of a parent you are looking child for>
SET @childId=0

WHILE (@childId<>@targetChildId)
    BEGIN
        IF(EXISTS(SELECT ChildId FROM Hierarchies WHERE ParentId=@parentId))
        BEGIN
            SET @childId=(SELECT ChildId FROM Hierarchies WHERE ParentId=@parentId)
            SET @parentId=@childId
        END 
        ELSE
        BEGIN
            SET @childId=0
            BREAK
        END
    END
PRINT @childId
  

Возвращает 0, если целевой потомок не найден в целевом родителе.

Ответ №2:

Пример данных:

 CREATE TABLE [dbo].[EntityHierarchy]
(
    [EntityId] INT,
    [ChildEntityId] INT
)

INSERT  [dbo].[EntityHierarchy]
VALUES  (1, 2),
        (2, 3),
        (3, 4),
        (4, 1) -- Cycle
  

Найти циклические связи:

 DECLARE @SearchEntityId INT = 1

;WITH [cteRursive] AS
(
    SELECT  1 AS [ROW_NUMBER],
            [ChildEntityId] AS [EntityId]
    FROM [dbo].[EntityHierarchy]
    WHERE [EntityId] = @SearchEntityId
    UNION ALL
    SELECT  r.[ROW_NUMBER]   1,
            h.[ChildEntityId]
    FROM [cteRursive] r
    INNER JOIN [dbo].[EntityHierarchy] h 
        ON r.[EntityId] = h.[EntityId]
    WHERE h.[ChildEntityId] <> @SearchEntityId
)
SELECT h.*
FROM [cteRursive] r
INNER JOIN [dbo].[EntityHierarchy] h 
    ON r.[EntityId] = h.[EntityId]
WHERE r.[ROW_NUMBER] = (SELECT MAX([ROW_NUMBER]) FROM [cteRursive])
  

Я использую рекурсивный CTE для составления списка потомков. Потомок последнего потомка либо создает цикл, либо нет.

Комментарии:

1. Хорошее указание, но мне просто нужно проверить, есть ли childID в списке потомков ParentID. Без какого-либо цикла.

2. Я немного обновил этот CTE, и он работает нормально. Именно то, что я искал.