Один из способов сделать это - создать рекурсивный CTE, который имеет для каждого пользователя по одной строке для каждого предка этого пользователя в дереве.Затем вы можете использовать CTE для фильтрации по предкам.Например, с этим деревом:
Bob
|-Alice
|-Jim
CTE вернет что-то вроде:
User Ancestor Level
---- -------- -----
Bob NULL 1
Alice Bob 1
Jim Alice 1
Jim Bob 2
Столбец Level
окажется не очень важным, но я нашел, что это помогло, когдаЯ писал запрос.
Вот пример сценария, который идентифицирует всех пользователей, которые находятся под Алисой в иерархии:
CREATE TABLE Users(
UserId int NOT NULL PRIMARY KEY,
Name nvarchar(25),
ManagerId int
);
GO
INSERT INTO Users (UserId, Name, ManagerId)
SELECT 1, 'Bob', NULL UNION ALL
SELECT 2, 'Steve', 1 UNION ALL
SELECT 3, 'Chris', 2 UNION ALL
SELECT 4, 'Alice', 1 UNION ALL
SELECT 5, 'Roger', 4 UNION ALL
SELECT 6, 'Tony', 5;
GO
WITH all_ancestors AS (
SELECT
u.UserId,
u.Name,
u.ManagerId AS AncestorId,
1 AS level
FROM
Users AS u
UNION ALL
SELECT
alla.UserId,
alla.Name,
u.ManagerId AS AncestorId,
alla.level + 1
FROM
all_ancestors AS alla
INNER JOIN
Users AS u
ON
alla.AncestorId = u.UserId
)
SELECT
u.*
FROM
Users AS u
INNER JOIN
all_ancestors AS a
ON
u.UserId = a.UserId
WHERE
a.AncestorId = 4; -- Alice
GO
DROP TABLE Users;
GO