递归查询加入层次结构级别 table 以计算第二级层次结构在分区中出现的次数 + 邮政编码 table
Recursive query to join Hierarchy Level table to count how many times the second level hierarchies appear in the divisision + Zipcode table
所以,我有三个 SQL tables,等级和邮政编码。
tables 的示例:(请记住,这只是一个示例,实际上系统中有 N 个层级,因此无法编写固定的查询)
层级:
ID HierarchyName FatherLevel
1 "top level" NULL
2 "medium" "top level"
3 "lowest" "medium"
4 "top level 2" NULL
5 "lowest 2" "top level 2"
部门:
ID Name HierachyLevel (I put the names here for ease of understanding but it'd be the IDs)
1 "National" "top level"
2 "Regional" "medium"
3 "Northeast" "lowest"
4 "North" "lowest"
5 "Southeast" "lowest"
6 "International" "top level 2"
7 "Europe" "lowest 2"
7 "Asia" "lowest 2"
邮政编码:
ID Code Division (Same as before, it'd be the IDs instead of the actual names)
1 101 Southeast
2 102 Southeast
3 103 North
4 104 Northeast
5 105 Europe
6 106 Asia
所以,我这里想看的是在ZipCode table中出现了多少次children的children。
例如,在列出的示例中,中等出现了 4 次(在顶级下方,最低出现了 2 次(在顶级 2 下方)。
我要构建的查询的最终表示是:
HierarchyName Count
"lowest 2" 2
"medium" 4
这是一个很复杂的问题,老实说,我不确定我是否解释得很好,抱歉。
简单来说:我想计算顶层下方的 children 层级在邮政编码 table 中通过其分区出现的次数。
编辑:Zipcode table 上只会出现层次结构的最低层级,我想统计的是 Zipcode 上第二层 children 出现的次数.
This fiddle有解决办法。
首先通过 division
得到 zip_code
的计数
with recursive divs as (
select d.id as division_id,
d.name as division_name,
d.hierarchy_level_id,
count(*) filter (where z.code is not null) as zip_count
from division d
left join zip_code z
on z.division_id = d.id
group by d.id, d.name, d.hierarchy_level_id
),
执行递归
tree as (
select h.id, h.hierarchy_name, h.father_id, d.division_name, d.zip_count,
1 as tier, array[h.hierarchy_name] as hier_path
from hierarchy_level h
join divs d
on d.hierarchy_level_id = h.id
where h.father_id is null
union all
select c.id, c.hierarchy_name, c.father_id, d.division_name, d.zip_count,
f.tier + 1, f.hier_path||c.hierarchy_name
from tree f
join hierarchy_level c
on c.father_id = f.id
join divs d
on d.hierarchy_level_id = c.id
)
使用 @>
“包含”运算符将每个级别连接到其所有后代,以获取每个级别下 zip_code
值的汇总 sum()
。
select t.id, t.hierarchy_name, t.father_id, t.division_name,
t.zip_count, t.tier, t.hier_path,
sum(coalesce(c.zip_count, 0)) + t.zip_count as total_zip_count
from tree t
left join tree c
on c.tier > t.tier
and c.hier_path @> t.hier_path
group by t.id, t.hierarchy_name, t.father_id, t.division_name,
t.zip_count, t.tier, t.hier_path
order by t.hier_path;
我在 fiddle 中留下了所有“展示你的作品”信息,这样你就可以看到发生了什么。您可以通过更改 select
列表、添加 where
子句并从 select
列表和 [=22= 中删除 t.division_name
来将其缩减为您想要的内容].
更新变体,必须完成任务:
WITH recursive levels AS (
SELECT id, 1 as level, HierarchyName, null::int as l2_parent
FROM Hierarchy WHERE FatherLevel IS NULL
UNION
SELECT h.id, levels.level+1, h.HierarchyName,
COALESCE(l.l2_parent, CASE WHEN l.level=2 THEN l.id ELSE NULL END)
FROM Hierarchy AS h JOIN levels AS l ON l.id = h.FatherLevel
)
SELECT HierarchyName, count(*)
FROM Division As d
JOIN levels AS l
ON d.HierachyLevel = l.id
AND l.l2_parent IS NOT NULL
JOIN ZipCode AS z
ON d.id = z.division
GROUP BY HierarchyName;
所以,我有三个 SQL tables,等级和邮政编码。
tables 的示例:(请记住,这只是一个示例,实际上系统中有 N 个层级,因此无法编写固定的查询)
层级:
ID HierarchyName FatherLevel
1 "top level" NULL
2 "medium" "top level"
3 "lowest" "medium"
4 "top level 2" NULL
5 "lowest 2" "top level 2"
部门:
ID Name HierachyLevel (I put the names here for ease of understanding but it'd be the IDs)
1 "National" "top level"
2 "Regional" "medium"
3 "Northeast" "lowest"
4 "North" "lowest"
5 "Southeast" "lowest"
6 "International" "top level 2"
7 "Europe" "lowest 2"
7 "Asia" "lowest 2"
邮政编码:
ID Code Division (Same as before, it'd be the IDs instead of the actual names)
1 101 Southeast
2 102 Southeast
3 103 North
4 104 Northeast
5 105 Europe
6 106 Asia
所以,我这里想看的是在ZipCode table中出现了多少次children的children。
例如,在列出的示例中,中等出现了 4 次(在顶级下方,最低出现了 2 次(在顶级 2 下方)。
我要构建的查询的最终表示是:
HierarchyName Count
"lowest 2" 2
"medium" 4
这是一个很复杂的问题,老实说,我不确定我是否解释得很好,抱歉。
简单来说:我想计算顶层下方的 children 层级在邮政编码 table 中通过其分区出现的次数。
编辑:Zipcode table 上只会出现层次结构的最低层级,我想统计的是 Zipcode 上第二层 children 出现的次数.
This fiddle有解决办法。
首先通过 division
zip_code
的计数
with recursive divs as (
select d.id as division_id,
d.name as division_name,
d.hierarchy_level_id,
count(*) filter (where z.code is not null) as zip_count
from division d
left join zip_code z
on z.division_id = d.id
group by d.id, d.name, d.hierarchy_level_id
),
执行递归
tree as (
select h.id, h.hierarchy_name, h.father_id, d.division_name, d.zip_count,
1 as tier, array[h.hierarchy_name] as hier_path
from hierarchy_level h
join divs d
on d.hierarchy_level_id = h.id
where h.father_id is null
union all
select c.id, c.hierarchy_name, c.father_id, d.division_name, d.zip_count,
f.tier + 1, f.hier_path||c.hierarchy_name
from tree f
join hierarchy_level c
on c.father_id = f.id
join divs d
on d.hierarchy_level_id = c.id
)
使用 @>
“包含”运算符将每个级别连接到其所有后代,以获取每个级别下 zip_code
值的汇总 sum()
。
select t.id, t.hierarchy_name, t.father_id, t.division_name,
t.zip_count, t.tier, t.hier_path,
sum(coalesce(c.zip_count, 0)) + t.zip_count as total_zip_count
from tree t
left join tree c
on c.tier > t.tier
and c.hier_path @> t.hier_path
group by t.id, t.hierarchy_name, t.father_id, t.division_name,
t.zip_count, t.tier, t.hier_path
order by t.hier_path;
我在 fiddle 中留下了所有“展示你的作品”信息,这样你就可以看到发生了什么。您可以通过更改 select
列表、添加 where
子句并从 select
列表和 [=22= 中删除 t.division_name
来将其缩减为您想要的内容].
更新变体,必须完成任务:
WITH recursive levels AS (
SELECT id, 1 as level, HierarchyName, null::int as l2_parent
FROM Hierarchy WHERE FatherLevel IS NULL
UNION
SELECT h.id, levels.level+1, h.HierarchyName,
COALESCE(l.l2_parent, CASE WHEN l.level=2 THEN l.id ELSE NULL END)
FROM Hierarchy AS h JOIN levels AS l ON l.id = h.FatherLevel
)
SELECT HierarchyName, count(*)
FROM Division As d
JOIN levels AS l
ON d.HierachyLevel = l.id
AND l.l2_parent IS NOT NULL
JOIN ZipCode AS z
ON d.id = z.division
GROUP BY HierarchyName;