иерархическое сопоставление запросов с несколькими таблицами - PullRequest
0 голосов
/ 13 мая 2018

У меня есть эта business_table

ref_ID      name    parent_id 
-----------------------------
ABC-0001    Amb     NULL 
PQR-899     boss    NULL
tgv-632     pick    NULL
yyy-888     xyz     NULL
kkk-456     ued     NULL

Я хочу обновить parent_id для business_table

parent_customer - это еще одна таблица, в которой перечислены иерархии ref_ID и parent_id, приведенные ниже.

Чтобы обновить parent_id для business_table, введите

1) проверьте ref_id для business_table с помощью ref_id для parent_customer.например.ref_ID ABC-0001 совпадения business_table с parent_customer ref_id 1-я строка 1 ref_id-ABC-0001 найдено совпадение opr-656

2), затем проверяем parent_id parent_customer этой сопоставленной записи, которая в этом случае проверяется parent_id opr-656с таблицей match_table_CM

таблица таблиц match_table_CM перечисляет идентификаторы, которые мы хотим сопоставить перед обновлением записи (мы проверяем это, потому что это необходимо, чтобы идентификатор CRM проверял наличие emplpoyee на предмет отсутствия)

3) соответствияне найден, затем проверьте с помощью parent_id opr-656 для parent_customer с той же таблицей parent_customer ref_id, найдена 2-я запись с ref_id opr-656, затем выберите его проверку parent_id ttK-668 с найденным соответствием match_table_CM 1 ttK-668, затем обновите с помощью business_table parent_id другой мудрой проверкой доparent_customer ref_ID = parent_id (parent of all) и обновите этот идентификатор, даже если совпадение не найдено, поэтому в этом случае, если совпадение не найдено, ttK-668 должно быть обновлено в конце

примечание: - таблица parent_customer перечисляетиерархия данных, в которойкогда оба ref_id и parent_id одинаковы, это означает, что он является родителем всей иерархии.

Например:

4 PQR-899 PQR-899 это конечный родитель иерархии

parent_customer

ID  ref_id     parent_id  
---------------------------
1   ABC-0001   opr-656
2   opr-656    ttK-668
3   ttK-668    ttK-668
4   PQR-899    PQR-899
5   kkk-565    AJY-567  
6   AJY-567    UXO-989
7   UXO-989    tgv-632
8   tgv-632    mnb-784 
9   mnb-784    qwe-525 
10  qwe-525    qwe-525
11  kkk-456    jjj-888

match_table_CM:

id    main_id
--------------
1     ttK-668
2     PQR-899
3     tgv-632
4     mnb-784

Ожидаемый результат

ref_ID      name    parent_id 
-----------------------------
ABC-0001    Amb     ttK-668                    
PQR-899     boss    PQR-899
tgv-632     pick    qwe-525
yyy-888     xyz     NULL
kkk-456     ued     jjj-888

Ответы [ 2 ]

0 голосов
/ 13 мая 2018

Вы можете получить окончательного родителя, используя рекурсивный CTE:

with cte as (
      select pc.ref_id, pc.parent_id as ultimate_parent, 1 as lev
      from parent_customer pc
      where pc.ref_id = pc.parent_id
      union all
      select pc.ref_id, cte.ultimate_parent, lev + 1 
      from cte
           parent_customer pc
           on pc.parent_id = cte.ref_id and pc.ref_id <> pc.parent_id
    )
select *
from cte;

Вы можете поместить это в update:

with cte as (
      select pc.ref_id, pc.parent_id as ultimate_parent, 1 as lev
      from parent_customer pc
      where pc.ref_id = pc.parent_id
      union all
      select pc.ref_id, cte.ultimate_parent, lev + 1 
      from cte
           parent_customer pc
           on pc.parent_id = cte.ref_id and pc.ref_id <> pc.parent_id
    )
update bt
    set parent_id = cte.ultimate_parent
    from business_table bt join
         cte
         on cte.ref_id = bt.ref_id
0 голосов
/ 13 мая 2018

Это должно вернуть ожидаемый результат:

WITH hierarchy AS
 ( -- all rows from source table
   SELECT b.ref_id, pc.parent_id, 
      0 AS match,
      1 AS lvl
   FROM business_table AS b
   LEFT JOIN parent_customer AS pc
     ON b.ref_id = pc.ref_id

   UNION ALL

   SELECT h.ref_id, pc.parent_id, 
      -- check if we found a match or reached top of hierarchy
      CASE WHEN mt.main_id IS NOT NULL OR pc.parent_id = pc.ref_id THEN 1 ELSE 0 END,
      lvl+1
   FROM hierarchy AS h
   JOIN parent_customer AS pc 
     ON pc.ref_id = h.parent_id -- going up in the hierarchy
   LEFT JOIN match_table_CM AS mt
     ON mt.main_id = pc.ref_id
   WHERE h.match = 0 -- no match yet
     AND lvl < 10 -- just in case there's an endless loop due to bad data
 )
SELECT * FROM hierarchy AS h
WHERE lvl = 
 ( -- return the last row, matching or not
   SELECT Max(lvl)
   FROM hierarchy AS h2
   WHERE h.ref_id = h2.ref_id
 );

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

Переписать с использованием EXISTS, потому что SQL Server не поддерживает внешние соединения в рекурсивной части:

WITH hierarchy AS
 ( -- all rows from source table
   SELECT b.ref_id, pc.parent_id, 
      0 AS match,
      1 AS lvl
   FROM business_table AS b
   LEFT JOIN parent_customer AS pc
     ON b.ref_id = pc.ref_id

   UNION ALL

   SELECT h.ref_id, pc.parent_id, 
      -- check if we found a match or reached top of hierarchy
      CASE WHEN exists
            ( select * 
              from match_table_CM AS mt
              where mt.main_id = pc.ref_id
            ) OR pc.parent_id = pc.ref_id
           THEN 1
           ELSE 0
      END,
      lvl+1
   FROM hierarchy AS h
   JOIN parent_customer AS pc 
     ON pc.ref_id = h.parent_id -- going up in the hierarchy
   WHERE h.match = 0 -- no match yet
     AND lvl < 10 -- just in case there's an endless loop due to bad data
 )
SELECT * FROM hierarchy AS h
WHERE lvl = 
 ( -- return the last row, matching or not
   SELECT Max(lvl)
   FROM hierarchy AS h2
   WHERE h.ref_id = h2.ref_id
 );

План оптимизатора выглядел плохо, поэтому еще один переписать, чтобы использовать оконный агрегат вместо коррелированного подзапроса:

WITH  hierarchy AS
 ( -- all rows from source table
   SELECT b.ref_id, pc.parent_id, 
      0 AS match,
      1 AS lvl
   FROM business_table AS b
   LEFT JOIN parent_customer AS pc
     ON b.ref_id = pc.ref_id

   UNION ALL

   SELECT h.ref_id, pc.parent_id, 
      -- check if we found a match or reached top of hierarchy
      CASE WHEN exists
            ( select * 
              from match_table_CM AS mt
              where mt.main_id = pc.ref_id
            ) OR pc.parent_id = pc.ref_id
           THEN 1
           ELSE 0
      END,
      lvl+1
   FROM hierarchy AS h
   JOIN parent_customer AS pc 
     ON pc.ref_id = h.parent_id -- going up in the hierarchy
   WHERE h.match = 0 -- no match yet
     AND lvl < 10 -- just in case there's an endless loop due to bad data
 )
select *
from 
 ( 
   SELECT h.*,
      max(lvl) over (partition by ref_id) as maxlvl
   FROM hierarchy AS h
 ) as dt
WHERE lvl = maxlvl
;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...