MS SQL: Могу ли я присоединиться несколько раз, пока не появится строка? - PullRequest
0 голосов
/ 04 июня 2019

Опрашивая подмножество наших сотрудников, я пытаюсь добавить поле для SVP, к которому они «свернутся».

Сотрудники могут иметь от 1 до 5 или 6 степеней отделения от своего СВП. Проблема в том, что у нас нет конкретного иерархического индикатора для ссылки. Я должен сделать это, проходя через менеджера сотрудника несколько раз, пока у менеджера какого-нибудь менеджера не будет «SVP» в их названии.

Как я могу написать запрос для этого?

С другой стороны, я обнаружил, что сотрудники определенного SVP (в данном случае названы BM): «Менеджер сотрудника - BM, ИЛИ менеджер менеджера сотрудника - BM, ИЛИ Менеджер менеджера сотрудника - BM» и и так далее ...

В моем случае, я подозреваю, что я буду использовать только одну и ту же таблицу sys_user снова и снова, следуя полю диспетчера каждый раз, пока не достигну пользователя с SVP в заголовке.

+--------+-------------------+-----------+--------+
| sys_id |      name         | title     | manager|
+--------+-------------------+-----------+--------+
| 555789 | Tina Belcher      | Contractor| 123456 | 
| 123456 | Bob Belcher       | Manager   | 654321 |
| 654321 | Calvin Fischoeder | SVP       | 997755 |
+--------+-------------------+-----------+--------+
SELECT su.Name
     , su.Title
     , dp.name
     , mg.name

FROM sys_user                   su
    LEFT JOIN cmn_department    dp
        ON dp.sys_id = su.department
    LEFT JOIN sys_user          mg
        ON mg.sys_id = su.manager

WHERE su.Title like ('%contractor%')

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

Ответы [ 2 ]

1 голос
/ 04 июня 2019

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

Чтобы ответить на вопросы, которые вы задаете, вам будет полезно перекодировать данные в таблицу закрытия, которая отображает каждого сотрудника на всех его прямых и косвенных менеджеров / репортеров вместе с их степенью разделения, а также любую другую дополнительную соответствующую информацию , Однако, поскольку он представляет отношение «многие ко многим», вы не хотите перегружать его слишком большим количеством дополнительных данных. К счастью, благодаря утилите рекурсивных запросов вы можете легко создать ее на лету.

Чтобы создать таблицу замыкания, вы начинаете с ее заполнения отношениями степени 0, где каждый сотрудник считается своим менеджером / репортером. Обоснование этого немного выходит за рамки моего понимания, но оно как-то связано с математикой, лежащей в основе концепции транзитивного замыкания (отсюда и таблица замыканий имен). После этого вы многократно (рекурсивно) добавляете каждую дополнительную степень отчетности. Вы можете сделать это сверху вниз или снизу вверх

Вот версия сверху вниз :

with closure(manager_id, report_id, degree, is_managing_SVP, is_reporting_svp) as (
  select sys_id
       , sys_id
       , 0
       , case when title like '%SVP%' then 1 else 0 end
       , case when title like '%SVP%' then 1 else 0 end
    from sys_user
  union all
  select cur.manager_id
       , nxt.sys_id
       , cur.degree+1
       , cur.is_managing_SVP
       , case when nxt.title like '%SVP%' then 1 else 0 end
    from closure cur
    join sys_user nxt
      on nxt.manager = cur.report_id
     and nxt.sys_id <> nxt.manager
)
select * from closure

А вот версия Bottom Up :

with closure(manager_id, report_id, degree, is_managing_SVP, is_reporting_svp) as (
  select sys_id
       , sys_id
       , 0
       , case when title like '%SVP%' then 1 else 0 end
       , case when title like '%SVP%' then 1 else 0 end
    from sys_user
  union all
  select nxt.manager
       , cur.report_id
       , cur.degree+1
       , case when mgr.title like '%SVP%' then 1 else 0 end
       , cur.is_reporting_SVP
    from closure cur
    join sys_user nxt
      on nxt.sys_id = cur.manager_id
     and nxt.sys_id <> nxt.manager
    join sys_user mgr
      on mgr.sys_id = nxt.manager
)
select * from closure

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

После создания вы можете использовать таблицу закрытия, чтобы ответить на ваши вопросы о SVP, например, кто является SVP каждого подрядчика:

select r.sys_id, r.name, r.title, c.degree
     , c.manager_id SVP_ID
     , m.name SVP_name
     , m.title SVP_title
  from sys_user r
  join closure c
    on c.report_id = r.sys_id
  join sys_user m
    on m.sys_id = c.manager_id
 where r.title like '%contractor%'
   and c.is_managing_svp = 1
sys_id | name         | title      | degree | SVP_ID | SVP_name          | SVP_title
-----: | :----------- | :--------- | -----: | -----: | :---------------- | :--------
555789 | Tina Belcher | Contractor |      2 | 654321 | Calvin Fischoeder | SVP      

Или каждый прямой и косвенный отчет в СВП по имени Кельвин Фишхоудер:

select m.sys_id manager_id
     , m.name
     , m.title
     , c.degree
     , r.sys_id report_id
     , r.name report_name
     , r.title report_title
  from sys_user m
  join closure c
    on c.manager_id = m.sys_id
  join sys_user r
    on r.sys_id = c.report_id
 where m.name = 'Calvin Fischoeder'
 order by degree, report_name
manager_id | name              | title | degree | report_id | report_name       | report_title
---------: | :---------------- | :---- | -----: | --------: | :---------------- | :-----------
    654321 | Calvin Fischoeder | SVP   |      0 |    654321 | Calvin Fischoeder | SVP         
    654321 | Calvin Fischoeder | SVP   |      1 |    123456 | Bob Belcher       | Manager     
    654321 | Calvin Fischoeder | SVP   |      2 |    555789 | Tina Belcher      | Contractor  

Чтобы увидеть все запросы в действии, проверьте это db <> fiddle

1 голос
/ 04 июня 2019

Вы ищете рекурсивный CTE:

with cte as (
      select su.sys_id, su.name, su.title, su.manager, 1 as lev, 0 as hit_svp
      from sys_user su
      where su.Title like '%contractor%'
      union all
      select su.sys_id, su.name, su.title, su.manager, lev + 1,
             (case when su.title like '%SVP%' then 1 else 0 end) as hit_svp
      from sys_user su join
           cte
           on cte.manager = su.sys_id
      where cte.hit_svp = 0
     )
select . . .   -- whatever columns you want
from cte;      -- you may want additional joins here for other columns
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...