递归查询加入层次结构级别 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;