首页/数据/数仓建模速查/递归 CTE 构建维度层级
维度与事实设计149 条

递归 CTE 构建维度层级

自引用层级(组织/类目/账户)用递归 CTE 从根展开到叶,适合中小规模层级;结果常用于生成路径列或校验孤儿节点。

数仓建模速查数据更新于 2026-10-13

递归 CTE 的适用边界

自引用层级(组织、类目、账户)可以用递归 CTE 从根节点逐层展开到叶子,PostgreSQL、Hive 与 Spark SQL 都支持 WITH RECURSIVE 语法。它适合中小规模层级,结果常用来生成路径列、导出层级视图或校验孤儿节点与环路。

基本信息

语法WITH RECURSIVE,PostgreSQL、Hive、Spark SQL 均支持
语句结构锚定查询取根节点,递归部分关联子节点
常见用途展开层级、找根节点、检测环路、生成路径列
深度保护限制层级深度,防止脏数据导致无限递归
规模上限节点多时性能明显下降,需要物化

典型使用场景

  • 组织树展开:从集团根节点展开到部门与小组
  • 类目层级:生成三级类目路径供报表下钻
  • 账户结构:展开主账户下的全部子账户
  • 数据校验:找出没有父节点的孤儿记录
  • 路径物化:把递归结果写入路径列,后续查询不再递归

递归展开并生成路径

递归展开并生成路径
-- 递归展开组织树,同时生成路径与层级
WITH RECURSIVE tree AS (
  SELECT org_id, parent_id, 1 AS lvl,
         cast(org_id AS string) AS path
  FROM dim_org
  WHERE parent_id IS NULL
  UNION ALL
  SELECT o.org_id, o.parent_id, t.lvl + 1,
         concat(t.path, '/', o.org_id)
  FROM dim_org o
  JOIN tree t ON o.parent_id = t.org_id
  WHERE t.lvl < 10
)
SELECT org_id, lvl, path FROM tree;

各环节作用

环节作用注意事项
锚定查询取根节点作为起点根节点判定条件要唯一
递归部分按父子关系向下展开关联字段要建索引
深度限制防止无限递归脏数据成环时尤其重要
输出结果层级、路径与节点清单只读结果,不直接更新维表
环路要提前检测:层级表出现 A 是 B 的父、B 又是 A 的父时,递归会一直展开直到资源耗尽,因此递归语句必须带深度上限。
层级规模大时物化路径列或闭包表:每次查询都现场递归会让响应时间随深度增长,物化后按前缀过滤即可完成子树查询。
递归结果建议物化成按天分区的层级快照:既能做历史比对,也避免每次查询都重新递归,代价是每天多一份存储。

易错点

  • 没有环路检测:脏数据导致递归死循环,任务被拖垮
  • 每次查询现场递归:层级大时性能不可接受
  • 根节点判定条件不唯一:出现多棵重复的树,结果行数翻倍
  • 递归深度上限设得过大:异常数据仍会消耗大量资源
  • 递归结果直接更新维表:中间状态被写入,出错后难以回滚

数据来源与参考

  • PostgreSQL 文档:WITH RECURSIVE;Spark SQL 参考
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌