具有层次结构和层次结构级别数量可变的查询

Query with hierarchical structure and variable number of hierarchy levels

我有 table 'Areas' 包含客户区域:

ID, AREA_NAME, PARENT_ID

区域使用指向父级 AREA_ID 的 PARENT_ID 最多四层进行组织。 PARENT_ID 顶级区域为 NULL。

Table of 'Customers' hase AREA_ID 引用区域层次结构的最低级别:

ID, CUSTOMER_NAME, AREA_ID

我想得到这样的结果table:

CUSTOMER_NAME,AREA_LVL_1,AREA_LVL_2,AREA_LVL_3,AREA_LVL_4

这里的问题是客户的区域(AREA_ID)并不总是指向最低的四级区域。有时指向第四层 AREA_ID,有时指向第三层,依此类推。

根据区域级别,生成的 table 应如下所示:

CUSTOMER_NAME | AREA_LVL_1 | AREA_LVL_2 | AREA_LVL_3 | AREA_LVL_4
==============+============+============+============+===========
John          | A          | A1         | A13        | A136
Maria         | B          | B2         | <null>     | <null>
Steve         | A          | A2         | A24        | <null>

我不知道如何在单个 SQL 查询中使用可变级别数进行递归。 我只需要一个 SQL 查询(而不是游标通过递归循环的过程)。

您需要一个递归 CTE,每个区域的 returns 所有级别都将连接到 customers:

with 
  cte as (
    select id, area_name, parent_id, id start, 1 level from areas
    union all
    select a.id, a.area_name, a.parent_id, c.start, c.level + 1 
    from areas a inner join cte c
    on c.parent_id = a.id
    where c.parent_id is not null
  ),
  levels as (
    select id, area_name, parent_id, start, 
      max(level) over (partition by start) - level + 1 level 
    from cte
  )
select c.customer_name,
  max(case when l.level = 1 then l.area_name end) area_lvl_1,
  max(case when l.level = 2 then l.area_name end) area_lvl_2,
  max(case when l.level = 3 then l.area_name end) area_lvl_3,
  max(case when l.level = 4 then l.area_name end) area_lvl_4
from customers c left join levels l 
on l.start = c.area_id 
group by c.id, c.customer_name

参见demo
结果:

> customer_name | area_lvl_1 | area_lvl_2 | area_lvl_3 | area_lvl_4
> :------------ | :--------- | :--------- | :--------- | :---------
> John          | A          | A1         | A13        | A136      
> Maria         | B          | B2         | null       | null      
> Steve         | A          | A2         | A24        | null 

一个更简单的解决方案:

select customer_name,

  case when a3.id is null then a4.area_name
       when a2.id is null then a3.area_name
       when a1.id is null then a2.area_name
       else a1.area_name
  end as area_name_lvl1,

  case when a3.id is null then null
       when a2.id is null then a4.area_name
       when a1.id is null then a3.area_name
       else a2.area_name
  end as area_name_lvl2,

  case when a2.id is null then null
       when a1.id is null then a4.area_name
       else a3.area_name
  end as area_name_lvl3,

  case when a1.id is null then null
       else a4.area_name
  end as area_name_lvl4

from customers c
left join areas a4 on a4.id=c.area_id
left join areas a3 on a3.id=a4.parent_id
left join areas a2 on a2.id=a3.parent_id
left join areas a1 on a1.id=a2.parent_id

参见demo