具有层次结构和层次结构级别数量可变的查询
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。
我有 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。