Рекурсивный CTE с дополнительными условиями EXISTS?

У меня есть ситуация, когда мне нужно иметь возможность видеть, находится ли данный человек в иерархии пользователя/менеджера. У меня есть следующая структура таблицы: UserId UserName ManagerId

У меня есть 2 идентификатора: UserId (скажем, 5) и ManagerId (скажем, 2). В результате мне нужно знать, является ли менеджер с данным идентификатором (2) главным для пользователя с данным идентификатором (5)? Например, если

  1. Пользователь 1 подчиняется пользователю 2.
  2. Пользователь 3 подчиняется пользователю 1.
  3. Пользователь 4 отчитывается перед пользователем 3

результат SQL-запроса должен показать, что для UserId = 4 и ManagerId = 1 ответ верный.

Я только что создал запрос для получения всей иерархии:

WITH temp (level, UserName, UserId, ManagerId) AS
(
  SELECT 1 AS level, EmployeeName, EmployeeId, BossId
  FROM Employees
  WHERE BossId IS NULL

  UNION ALL

  SELECT level+1 AS level, EmployeeName, EmployeeId, BossId
  FROM Employees, temp
  WHERE BossId = UserId
)

SELECT t.* from temp AS t

Но теперь я не знаю, как получить результат запроса с указанными выше условиями :(

Заранее благодарю за любую помощь!


person John Duncan    schedule 02.02.2013    source источник
comment
Что означает IS_EXISTS?   -  person usr    schedule 03.02.2013
comment
Извините, СУЩЕСТВУЕТ конечно.   -  person John Duncan    schedule 03.02.2013


Ответы (3)


Найдите пользователя в якоре и пройдите обратно вверх по иерархии. Проверьте строки, которые вы получили в рекурсивном запросе, против менеджера.

Это вернет строку менеджера, если она существует.

WITH temp AS
(
  SELECT EmployeeName, EmployeeId, BossId
  FROM Employees
  WHERE EmployeeId = @UserID

  UNION ALL

  SELECT E.EmployeeName, E.EmployeeId, E.BossId
  FROM Employees AS E
    inner join temp AS T
      ON E.EmployeeId = T.BossId
)

SELECT * 
FROM temp
WHERE EmployeeId = @ManagerID
person Mikael Eriksson    schedule 02.02.2013

Это вернет BossID, если он или она существует:

WITH BOSSES AS 
(
    SELECT BossID
    FROM Employees
    WHERE EmployeeID = @uID

    UNION ALL

    SELECT E.BossID
    FROM Employees E 
    JOIN BOSSES B ON E.EmployeeID = B.BossID
)
SELECT *
FROM BOSSES 
WHEN BossID = @bID
person Hogan    schedule 02.02.2013

Я включил иерархию всех уровней с CTE, которую вы затем можете использовать для запросов. Используя эту иерархию, вы можете увидеть всех менеджеров данного сотрудника в столбце с разделителями (может быть полезно для других расчетов).

Попробуйте это:

WITH cte (UserId, ManagerId, Level, Hierarchy) as (
   SELECT EmployeeId, BossId, 0, CAST(EmployeeId as nvarchar)
   FROM Employee
   WHERE BossId IS NULL 
   UNION ALL
   SELECT EmployeeId, BossId, Level+1, 
      CAST(cte.Hierarchy + '-' + CAST(EmployeeId as nvarchar) as nvarchar)
   FROM Employee INNER JOIN cte ON Employee.BossId=cte.UserId 
)
SELECT * 
FROM cte
WHERE UserId = 4 
  AND '-' + Hierarchy LIKE '%-1-%' 

А вот и скрипт. Я использовал UserId = 4 и ManagerId = 1.

Удачи.

person sgeddes    schedule 02.02.2013