Моя задача — отметить участников «уровня начальника» в данных, собранных на собраниях, на основе заданной организационной структуры.
Другими словами, необходимо определить человека(ов) с самым высоким рейтингом на данном собрании, «босса» в рамках линии подчинения (ветви или поддерева в организационном дереве).
Если у участников нет начальника (в пределах их поддерева/структуры отчетности), они становятся начальником.
Если присутствует начальник (внутри его поддерева/структуры отчетности), он не является начальником.
На собраниях может быть несколько начальников (если они не находятся на одной ветке дерева).
Таким образом, сотрудник, ближайший к корню, является начальником, и все его начальники не были бы начальниками на собрании, если бы они присутствовали.
Инструменты: SQL Server (версия 2019 или новее).
Дерево организационной диаграммы: Организационная диаграмма
Данные организационной диаграммы:
Данные встречи и ожидаемые результаты (Босс):
Я предполагаю, что здесь может потребоваться рекурсивный CTE, но интересно, есть ли более простые методы для этого. Также интересует общепринятая терминология для описания этой проблемы. Спасибо!
Данные испытаний:
Select *
From
(
values
('Root', NULL),
('Billy', 'Root'),
('Jacob', 'Billy'),
('Susan', 'Billy'),
('Tracy', 'Billy'),
('Sheri', 'Billy'),
('Carlos', 'Tracy'),
('Andrew', 'Tracy'),
('Hunter', 'Sheri'),
('Charly', 'Root'),
('Larry', 'Charl'),
('Harry', 'Charly'),
('Toni', 'Charly'),
('Chris', 'Larry'),
('Michael', 'Harry'),
('Anita', 'Toni')
) A (Name, Superior)
Select *
From
(
values
('Meeting 1', 'Tracy', 'Y'),
('Meeting 1', 'Hunter', 'Y'),
('Meeting 2', 'Billy', 'Y'),
('Meeting 2', 'Charly', 'Y'),
('Meeting 2', 'Hunter', 'N'),
('Meeting 2', 'Larry', 'N'),
('Meeting 3', 'Billy', 'Y'),
('Meeting 3', 'Hunter', 'N'),
('Meeting 3', 'Anita', 'Y'),
('Meeting 4', 'Anita', 'Y'),
('Meeting 4', 'Billy', 'Y'),
('Meeting 5', 'Anita', 'Y'),
('Meeting 6', 'Billy', 'Y'),
('Meeting 6', 'Charly', 'Y')
) A ([Meeting], [Name], [Meeting Boss (expected results)])
Каковы ваши ожидаемые результаты? Можете ли вы объяснить ваши правила лучше? Будет ли ответ таков: на собрании также присутствует любой участник собрания, у которого нет начальника (кто-либо выше него в иерархии организационной структуры)? Это может означать, что на собраниях может быть более одного «начальника». Заменяет ли флаг «Босс» другую логику, означая, что все участвующие боссы включены в результаты, даже если один подчиняется другому?
@siggemannen, спасибо! Я добавил дерево организации в виде текстовой таблицы.
@TN Извините за неточность, я добавил в пост больше жаргона. Может быть, очень просто: необходимо отметить сотрудников с самым высоким рейтингом, присутствующих на собрании, но только в пределах их подчиненности.
Добавлен sql для создания тестовых данных.
Итак, ваши тестовые данные находятся в двух таблицах, я не понимаю, какой ожидаемый результат должен быть получен из этих двух таблиц.
@GuidoG проверьте поле [Встреча с руководителем (ожидаемые результаты)] во второй таблице
Я могу придумать два подхода, но оба потребуют рекурсивного CTE для обхода иерархии.
Один из подходов — начать с каждого участника и использовать рекурсивный CTE для обхода иерархии в поисках начальника, который также присутствует на том же собрании. Если он найден, то начинающий участник не является боссом. Если ни один не найден, этот участник является боссом.
WITH AttendeeSuperiors AS (
SELECT M.Meeting, M.Participant, M.Expected, O.Superior
FROM MeetingData M
JOIN OrgChart O
ON O.Employee = M.Participant
UNION ALL
SELECT ATS.Meeting, ATS.Participant, ATS.Expected, O.Superior
FROM AttendeeSuperiors ATS
JOIN OrgChart O
ON O.Employee = ATS.Superior
)
SELECT
ATS.Meeting, ATS.Participant, ATS.Expected,
CASE WHEN MAX(M2.Participant) IS NULL THEN 'Y' ELSE 'N' END AS Boss
FROM AttendeeSuperiors ATS
LEFT JOIN MeetingData M2
ON M2.Meeting = ATS.Meeting
AND M2.Participant = ATS.Superior
GROUP BY ATS.Meeting, ATS.Participant, ATS.Expected
ORDER BY ATS.Meeting, ATS.Participant;
(Может быть небольшое преимущество в производительности при проверке превосходного участия в CTE, так что мы можем остановить рекурсию при первом совпадении. См. связанную демонстрацию для модифицированной версии.)
Другой подход — использовать рекурсивный CTE для создания полного списка всех руководителей для каждого сотрудника. (В идеале это можно записать в таблицу и проиндексировать для эффективного повторного использования.) Затем для каждого участника собрания мы будем искать в этом превосходном списке того, кто также является участником того же собрания. Если он найден, то начинающий участник не является боссом. Если ни один не найден, этот участник является боссом.
WITH EmployeeSuperiors AS (
SELECT O.Employee, O.Superior
FROM OrgChart O
--WHERE O.Employee IN (SELECT DISTINCT Participant FROM MeetingData)
UNION ALL
SELECT S.Employee, O.Superior
FROM EmployeeSuperiors S
JOIN OrgChart O
ON O.Employee = S.Superior
)
SELECT
M.*,
CASE WHEN NOT EXISTS(
SELECT *
FROM EmployeeSuperiors S
JOIN MeetingData M2
ON M2.Meeting = M.Meeting
AND M2.Participant = S.Superior
WHERE S.Employee = M.Participant
) THEN 'Y' ELSE 'N' END AS Boss
FROM MeetingData M
ORDER BY M.Meeting, M.Participant;
Если мы вычисляем EmployeeSuperiors
на лету для каждого выполнения (и не сохраняем эти данные), мы можем ограничить этот расчет только теми сотрудниками, которые участвуют в собраниях, раскомментировав условие WHERE
выше.
Что касается того, какой подход более эффективен, я считаю, что первый вариант может быть лучше для небольшого количества встреч и участников по отношению к общему количеству сотрудников. Второй подход может быть лучше, если вы будете обрабатывать множество собраний и иметь возможность определять, заполнять, индексировать и поддерживать постоянную таблицу EmployeeSuperiors
. В любом случае я предлагаю вам провести собственные тесты производительности.
См. эту db<>fiddle для демонстрации.
Спасибо, работает потрясающе! Для моего сценария последний вариант кажется наиболее подходящим! Очень ценю!
Эту проблему легко решить с помощью WHERE EXISTS против рекурсивного объекта, имеющего иерархию сотрудников. Если вы предоставите иерархию в формате текстовой таблицы, это упростит написание ответа.