SQL CTE для поиска старших менеджеров в иерархии (2-й уровень сверху) - PullRequest
0 голосов
/ 29 октября 2018

У меня есть таблица Employee IDs с соответствующим Manager IDs, как показано ниже:

Желаемый результат : Столбец старшего менеджера, в котором есть менеджер свертки, который напрямую отчитывается Джону Смиту (EmpID: 1) или Анне Уайт (EmpID: 2).

Пример: Том отчитывается перед Джеком, который отчитывается перед Тимом, который отчитывается перед Анной.

Следовательно, старший менеджер Джека Блэка - Тим Смит, 4.

Том -> Джек -> Тим -> Анна

enter image description here

Я работал над CTE, но запрос возвращает много дублированных строк. В противном случае CTE выводит правильные данные.

   WITH cte AS 
    (
        SELECT EmpID, FirstName, LastName, EmpID as SeniorManager
        FROM Employees
        WHERE ManagerID < 3 
            AND EmpActive = 1
        UNION ALL
        SELECT emp.EmpID, emp.FirstName, emp.LastName, c.SeniorManager 
        FROM Employees emp
        JOIN cte c ON c.EmpID = emp.ManagerID
        WHERE emp.EmpID <> emp.ManagerID
            AND emp.EmpActive = 1
        )

    SELECT * FROM cte

Данные в качестве примера представляют собой упрощенную версию фактических данных, которые хранятся в базе данных компании. Мой главный вопрос: почему CTE возвращает дублированные строки?

Вот пример данных:

 CREATE TABLE Employees (
  EmpID INT NOT NULL PRIMARY KEY,
  FirstName VARCHAR(35) NOT NULL,
  LastName VARCHAR(35) NOT NULL,
  ManagerID INT NOT NULL);

 INSERT INTO Employees
  (EmpID, FirstName, LastName, ManagerID)
 VALUES
  (1, 'John', 'Smith', 2),
  (2, 'Anna', 'White', 1),
  (3, 'Jack', 'Black', 4),
  (4, 'Tim', 'Smith', 2),
  (5, 'Jason', 'Black', 3),
  (6, 'Tom', 'Black', 3);

Ответы [ 2 ]

0 голосов
/ 29 октября 2018

После долгих поисков и устранения проблем я нашел решение. Надеюсь, это поможет кому-то нуждающемуся:)

WITH cte AS 
(
    SELECT EmpID, FirstName, LastName, EmpID as SeniorManager
    FROM Employees
    WHERE ManagerID <= 2
        AND Active = 1
    UNION ALL
    SELECT e.EmpID, e.FirstName, e.LastName, c.SeniorManager 
    FROM tblEmployee e
    JOIN cte c ON c.EmpID = e.ManagerID
    WHERE e.EmpID <> e.ManagerID
        AND e.EmpID >= 3
        AND e.Active = 1
    )

SELECT EmpID, FirstName, LastName, MAX(SeniorManager) SeniorManager FROM cte
GROUP BY EmpID, FirstName, LastName

Объяснение:

  • Добавлен e.EmpID> 3 для второй части объединения. Дублированные строки происходят из-за бесконечного цикла, потому что есть 2 человека друг с другом в качестве менеджера, поэтому я должен был исключить их.

  • Выберите последнюю строку для каждого дублируемого EmpID. По какой-то причине в cte было 2 записи для каждого EmpID, первая запись с top-level manager и вторая строка с second-level manager. Из-за этого мне нужно выбрать второй ряд.

Редактировать:

Мой OP заявляет, что код уже дает мне вывод, который я хочу, за исключением того, что он работает в бесконечном цикле. Это был мой первичный вопрос, и он был решен после исключения первых сотрудников из объединения.

Я работаю с корпоративными данными, которые намного сложнее, чем показанные в примере данные, и я не могу ни воспроизвести их здесь, ни исправить данные. Если кто-то сталкивается с подобными проблемами, я не знаю, смогу ли я предоставить вам точное решение, но, надеюсь, приведенного мною кода достаточно для начала работы.

Почему я ответил на свой вопрос, но принял ответ другого человека: мой ответ очень специфичен для базы данных. Это сработало для этой конкретной проблемы, но я не думаю, что это лучший подход. Ответ, который я принял, лучше.

0 голосов
/ 29 октября 2018

Вы можете попытаться добавить столбец level для представления иерархии лиц.

тогда есть только level = 1 человек.

WITH cte AS 
(
    SELECT EmpID,FirstName,LastName,ManagerID,1 level
    FROM Employees 
    UNION ALL
    SELECT t2.EmpID,t2.FirstName,t2.LastName,t2.ManagerID,level+ 1
    FROM cte t1 JOIN Employees t2
    on t1.EmpId = t2.ManagerID
    WHERE t1.ManagerID <> t2.EmpId
)
SELECT EmpID,FirstName,LastName  
FROM cte t1
where not exists (
    select 1 
    from cte tt
    WHERE tt.level = 2 and t1.EmpID = tt.EmpID
) and level = 1

sqlfiddle

Результат

mpID    FirstName   LastName    
1       John        Smith       
2       Anna        White       
...