Получите более высокое значение, если первое значение не соответствует критериям

Я работаю над запросом для получения информации о сотрудниках, в том числе о том, кто может утверждать табели учета рабочего времени сотрудников. В нашей базе данных указано, кому подчиняется сотрудник, но этот человек не обязательно будет тем, кто может утверждать табели учета рабочего времени. Данные выглядят так

EENum Позиция Отчеты перед 1 Разнорабочий 3 2 Разнорабочий 3 3 Бригадир 6 4 Разнорабочий 5 5 Бригадир 7 6 Супер 8 7 Супер 8 8 ПМ 8

В этом примере только должности «Супер» и «PM» могут утверждать табели учета рабочего времени. Поскольку сотрудники 1 и 2 подчиняются сотруднику 3, который является бригадиром и не может утверждать табели учета рабочего времени, мне нужен запрос, который будет изучать данные сотрудника 3, чтобы узнать, кому они подчиняются, в данном случае сотруднику 6, который является суперменом и может поэтому одобряйте их табели учета рабочего времени. Таким образом, окончательный результат запроса должен выглядеть следующим образом:

EENum Утверждено 1 6 2 6 3 6 4 7 5 7 6 8 7 8 8 8

И хотя это не часто встречается, бывают случаи, когда может быть третий «уровень», поэтому я не могу просто выполнить оператор «IF», ​​чтобы подняться на один уровень. Ему нужно идти вверх, пока он не найдет «подчиненных», положение которых позволяет им утверждать табели учета рабочего времени.

Я пробовал выполнять рекурсивный поиск, но они не извлекали информацию правильно, и, к сожалению, я недостаточно хорошо понимаю рекурсивный поиск, чтобы объяснить, что происходит с возвращаемыми данными.

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

Пользователь, сообщающий самому себе, а не NULL, был осознанным выбором в нашем наборе данных по причинам, в которые я не буду вдаваться. Он применяется даже реже, чем можно предположить из примера набора данных, но, поскольку это ДЕЙСТВИТЕЛЬНО случается, я включил один из них в качестве примера, чтобы гарантировать, что он был учтен в ответах.

Grant Baugh 14.08.2024 00:30
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
1
56
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Это должно идти по дереву, пока вы не найдете подходящего утверждающего:

with tree as (
    select EENum as EEBase, EENum, ReportsTo, 'N' as approver
    from Employees
    union all
    select EEBase, e.EENum, e.ReportsTo,
        case when e.Position in ('PM', 'Super') then 'Y' else 'N' end
    from tree t inner join Employees e on e.EENum = t.ReportsTo
    where t.approver = 'N'
)
select EEBase as EENum, EENum as ApprovedBy
from tree
where approver = 'Y';

https://dbfiddle.uk/0nrOydrD

У данных есть утверждающий, который отчитывается перед самим собой. Это может завершиться при первом проходе. Если у вас есть такой цикл на неодобрительной позиции, это приведет к ошибке. Я не понимаю цели этого (обычно верхний уровень имеет значение null) и не знаю, должен ли запрос обрабатывать какой-либо из этих сценариев по-разному.

Когда я пробую это, я получаю максимальную ошибку рекурсии независимо от того, насколько высоко я устанавливаю эту опцию.

Joel Coehoorn 13.08.2024 23:49

@JoelCoehoorn Возможно, я исправил это, исправив один из псевдонимов всего за несколько минут до вашего комментария.

shawnt00 13.08.2024 23:50

Мне все еще не удается: dbfiddle.uk/SCUX3W3Q

Joel Coehoorn 13.08.2024 23:52

Кроме того: идея вопроса заключается в том, что у одного работника может быть более одного утверждающего в своем дереве, и он хочет остановиться на первом утверждающем.

Joel Coehoorn 13.08.2024 23:53

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

shawnt00 13.08.2024 23:54

Если я изменю данные, все равно не получится, поэтому 8 отчетов будут равны NULL dbfiddle.uk/iNyaIFUO

Joel Coehoorn 13.08.2024 23:55

@shawnt00 большое спасибо! Мне удалось заставить это работать в реальной базе данных, и, судя по моим тестам, это сработало. Я планирую более подробно рассмотреть ваше решение, чтобы лучше понять рекурсию в целом. Я не могу проголосовать за ваш ответ прямо сейчас, так как у меня недостаточно репутации, поэтому мне придется попытаться получить еще немного.

Grant Baugh 14.08.2024 00:27

@JoelCoehoorn Спасибо за устранение неполадок. Первоначально я думал, что максимальная рекурсия выполнена из-за изменений, которые мне пришлось внести при работе с полным набором данных.

Grant Baugh 14.08.2024 00:27

@GrantBaugh, вы не можете проголосовать за него (в любом случае это необязательно), но вы можете «принять» его, нажав галочку под стрелками голосования.

Dale K 14.08.2024 00:44

@DaleK Спасибо!

Grant Baugh 15.08.2024 17:40

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

WITH ApproverCTE AS (
    -- Anchor member: Start with all employees
    SELECT 
        E.EENum AS EmployeeID,
        E.Position,
        E.ReportsTo,
        E.EENum AS RootEmployeeID -- Keep track of the original employee
    FROM 
        Employees E

    UNION ALL

    -- Recursive member: Move up the hierarchy until we find a "Super" or "PM"
    SELECT 
        E.EENum AS EmployeeID,
        E.Position,
        E.ReportsTo,
        CTE.RootEmployeeID
    FROM 
        Employees E
    INNER JOIN 
        ApproverCTE CTE ON E.EENum = CTE.ReportsTo
    WHERE 
        E.Position NOT IN ('Super', 'PM') -- Continue recursion if the position isn't a Super or PM
)
-- Final selection: Find the approver for each employee
SELECT 
    CTE.RootEmployeeID AS EmployeeID,
    E.EENum AS ApprovedBy
FROM 
    ApproverCTE CTE
INNER JOIN 
    Employees E ON CTE.ReportsTo = E.EENum
WHERE 
    E.Position IN ('Super', 'PM') -- Select only approvers who are Super or PM
ORDER BY 
    EmployeeID;

Пожалуйста, проверьте dbFiddle здесь.

Другие вопросы по теме