Нашел то, что искал с помощью пары других постов. Основной ответ таков:
WITH cte AS
(
SELECT LegacyId ancestor, LegacyId descendant, 0 depth FROM Users
UNION ALL
SELECT cte.ancestor, u.LegacyId descendant, cte.depth + 1 depth
FROM dbo.Users u JOIN cte ON u.ManagerId = cte.descendant
)
select * from cte
Однако сначала меня поразило то, что некоторые плохие данные вызывали циклические зависимости. Мне удалось использовать следующий запрос, чтобы определить, где были эти экземпляры:
with cte (id,pid,list,is_cycle)
as
(
select legacyid id, managerid pid,',' + cast (legacyid as varchar(max)) + ',',0
from users
union all
select u.legacyid id,
u.managerid pid,
cte.list + cast(u.legacyid as varchar(10)) + ',' ,case when cte.list like '%,' + cast (u.legacyid as varchar(10)) + ',%' then 1 else 0 end
from cte join users u on u.managerid = cte.id
where cte.is_cycle = 0
)
select *
from cte
where is_cycle = 1
Как только я исправил циклические данные, все заработало отлично. Прочтите следующие сообщения SO для получения дополнительной информации, поскольку именно это я и использовал для своего решения: Есть ли способ обнаружить цикл в иерархических запросах в SQL Server? и Как я могу создать таблицу закрытия, используя данные из списка смежности?