【问题标题】:hierarchical query match with multiple tables its challenging分层查询与多个表匹配,具有挑战性
【发布时间】:2018-05-13 20:43:04
【问题描述】:

我有这个业务表

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

我想更新 business_table 的 parent_id

parent_customer 是另一个表,它列出了下面给出的 ref_ID 和 parent_id 的层次结构。

要更新 business_table stap 的 parent_id 是

1) 检查 business_table 的 ref_id 和 parent_customer 的 ref_id。例如。 business_table 的 ref_ID ABC-0001 与 parent_customer ref_id 第一行 1 匹配 ref_id-ABC-0001 opr-656 找到匹配项

2) 然后检查匹配记录的 parent_customer 的 parent_id,在本例中为 parent_id opr-656 检查 match_table_CM 表

match_table_CM 表列出了我们要在更新记录之前匹配的 id(我们正在检查这个,因为这是 CRM id 需要检查雇员是否存在)

3) 未找到匹配然后检查 parent_customer 的 parent_id opr-656 与同一张表 parent_customer ref_id ,第二条记录与 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) 并更新该 id,即使未找到匹配项,所以在这种情况下,如果未找到匹配项,则 ttK-668 应该是 终于更新了

注意:- parent_customer 表列出了数据的层次结构,其中当 ref_id 和 parent_id 相同时,表示它是整个层次结构的父级。

例如:

4 PQR-899 PQR-899 这是层次结构的最终父级

父客户

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

【问题讨论】:

  • 为什么4 PQR-899 PQR-899是root,他不是nobody的父母?
  • 好的。你是对的。您已经预先知道了一组固定的表格。您可以在问题开始时发布图表或仅描述您的表格吗?到目前为止,我看到:business_tableparent_customermatch_table_CM 但很难从您的问题中了解它们的关系。请使用格式。
  • 4 PQR-899 PQR-899 它的调用最终父级
  • 例如。巴克莱公司是最终母公司,其子公司是巴克莱美国、巴克莱英国等
  • 表之间没有直接关系,你必须根据数据编写SQL。我知道有点连线。

标签: sql sql-server tsql


【解决方案1】:

这应该会返回预期的结果:

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
;

【讨论】:

  • 给出错误:- 递归公用表表达式“层次结构”的递归部分不允许外连接。
  • @Gajanan:哎呀,我不知道 SQL Server 在递归部分不支持外连接(在我的 Teradata 上试过),看我的重写
  • 你在层级中上升,但要求是自下而上
  • 第一个匹配是 imp ,当第一个 parent_id 与匹配 id 匹配时
  • @Gajanan: 从下到上 = 在层次结构中上升。对不起,我没有得到你想要的,这个查询返回你预期的结果集。
【解决方案2】:

您可以使用递归 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

【讨论】:

  • 你能设置一个 SQL Fiddle 或类似的东西吗? “错误结果”非常含糊,不提供任何指导。
猜你喜欢
  • 2016-02-06
  • 2013-07-18
  • 1970-01-01
  • 1970-01-01
  • 2021-03-02
  • 2016-02-17
  • 1970-01-01
  • 2012-01-11
  • 2018-06-13
相关资源
最近更新 更多