В своем комментарии я спросил вас, зачем вам вообще нужна таблица @CompanyRelationShip
... Это просто добавляет чертовски много сложности и возможностей для ошибок.
Мое предложение основано на первый стол один. Посмотрите, как я изменил родительские идентификаторы 105 и 151, чтобы поместить их ниже в иерархии. Просто чтобы показать принципы, я добавил второго ребенка ниже 150 :
DECLARE @Company TABLE (
CompanyId INT
,RootCompanyId INT
,CompanyName VARCHAR(100)
);
INSERT INTO @Company
VALUES (2,2,'ROOT')
,(106,2,'ABC')
,(105,106,'CDF')
,(3,3,'ROOT2')
,(150,3,'YXZ')
,(151,150,'XZX')
,(152,150,'Second below 150');
- запрос
WITH recCTE AS
(
SELECT CompanyId AS [RootId],CompanyName AS [RootName],*,1 AS HierarchyLevel FROM @Company WHERE CompanyId=RootCompanyId
UNION ALL
SELECT rc.RootId,rc.RootName,c.*,rc.HierarchyLevel+1
FROM @Company c
INNER JOIN recCTE rc ON c.RootCompanyId=rc.CompanyId AND c.CompanyId<>rc.CompanyId
)
SELECT RootId
,RootName
,RootCompanyId AS [PrevId]
,CompanyId
,CompanyName
,HierarchyLevel
FROM recCTE rc
ORDER BY RootId,HierarchyLevel;
Результат
RootId RootName PrevId CompanyId CompanyName HierarchyLevel
2 ROOT 2 2 ROOT 1
2 ROOT 2 106 ABC 2
2 ROOT 106 105 CDF 3
3 ROOT2 3 3 ROOT2 1
3 ROOT2 3 150 YXZ 2
3 ROOT2 150 151 XZX 3
3 ROOT2 150 152 Second below 150 3
Идея вкратце:
- Мы используем рекурсивный CTE (на самом деле это довольно итеративная концепция).
- Первый SELECT ( якорь ) начинается с компаний, в которых совпадают два идентификатора.
- Второй SELECT после UNION ALL выбирает следующий уровень, присоединяя к промежуточная строка результата
- Два столбца
RootId
и RootName
просто пропущены, чтобы отобразиться в вашем окончательном наборе.
HierarchyLevel
- это позиция в пределах линия, таким образом помещая 105 в пределах ROOT, но ниже 106.
Надеюсь, это поможет ...
Решение для данной структуры
Как уже говорилось, данная структура не является лучшим выбором и должна быть изменена. Но если вам нужно придерживаться этого, вы можете попробовать кое-что по этому поводу:
WITH recCTE AS
(
SELECT CompanyId AS [RootId],CompanyName AS [RootName],*,1 AS HierarchyLevel FROM @Company WHERE CompanyId=RootCompanyId
UNION ALL
SELECT rc.RootId,rc.RootName,c.*,rc.HierarchyLevel+1
FROM @Company c
INNER JOIN recCTE rc ON c.RootCompanyId=rc.CompanyId AND c.CompanyId<>rc.CompanyId
)
SELECT rc.CompanyId
,rc.CompanyName
,COALESCE(crs.PrimaryCompanyId,rc.RootCompanyId) AS ComputedPrevId
,COALESCE(c1.CompanyName,rc.RootName) AS ComputedPrevName
,rc.RootId
,rc.RootName
FROM recCTE rc
LEFT JOIN @CompanyRelationShip crs ON rc.CompanyId=crs.CompanyId AND rc.RootCompanyId<>crs.PrimaryCompanyId
LEFT JOIN @Company c1 ON crs.PrimaryCompanyId=c1.CompanyId
ORDER BY rc.RootId,rc.HierarchyLevel;
Сначала будет использован рекурсивный CTE, чтобы найти детей ниже их root компаний, и он попытается найти соответствующий строка в таблице ваших отношений.
Если вы используете просто SELECT *
вместо списка столбцов, вы можете увидеть полный набор. Использование LEFT JOIN
вернет NULL
, когда условие ON
не выполнено.
COALESCE
вернет первое значение, отличное от NULL, так что - надеюсь - то, что вы ищете.