跳到主要内容
跳到主要内容

WITH 子句

ClickHouse 支持公共表表达式(CTE),并在 WITH 子句的所有使用位置替换定义的代码。命名的子查询可以在允许表对象的地方包含到当前和子查询上下文中。通过在 WITH 表达式中隐藏当前级别的 CTE,避免了递归的发生。

请注意,CTE 在调用的所有地方不保证相同的结果,因为查询将为每个使用情况重新执行。

下面是这样的行为示例

如果 CTE 传递的确切是结果,而不仅仅是一段代码,你将始终看到 1000000

然而,由于我们引用了 cte_numbers 两次,因此每次都会生成随机数,因此我们看到不同的随机结果,280501, 392454, 261636, 196227 等等...

语法

示例

示例 1: 将常量表达式用作“变量”

示例 2: 从 SELECT 子句列列表中剔除 sum(bytes) 表达式结果

示例 3: 使用标量子查询的结果

示例 4: 在子查询中重用表达式

递归查询

可选的 RECURSIVE 修饰符允许 WITH 查询引用其自身的输出。例如:

示例: 从 1 到 100 的整数求和

备注

递归 CTE 依赖于在版本 24.3 中引入的 新查询分析器。如果您使用的是版本 24.3+ 并遇到 (UNKNOWN_TABLE)(UNSUPPORTED_METHOD) 异常,这表明您的实例、角色或配置中禁用了新分析器。要激活分析器,请启用设置 allow_experimental_analyzer 或将 compatibility 设置更新为更新版本。 从版本 24.8 开始,新分析器已完全推广至生产环境,设置 allow_experimental_analyzer 已重命名为 enable_analyzer

递归 WITH 查询的一般形式总是一个非递归项,然后是 UNION ALL,然后是递归项,只有递归项可以包含对查询自身输出的引用。递归 CTE 查询按以下方式执行:

  1. 评估非递归项。将非递归项查询的结果放置在临时工作表中。
  2. 只要工作表不是空的,就重复以下步骤:
    1. 评估递归项,用工作表的当前内容替换递归自引用。将递归项查询的结果放置在临时中间表中。
    2. 用中间表的内容替换工作表的内容,然后清空中间表。

递归查询通常用于处理层次结构或树结构的数据。例如,我们可以编写一个执行树遍历的查询:

示例: 树遍历

首先让我们创建树表:

我们可以通过这样的查询遍历这些树:

示例: 树遍历

搜索顺序

为了创建深度优先顺序,我们为每个结果行计算一个我们已经访问过的行的数组:

示例: 树遍历深度优先顺序

为了创建广度优先顺序,标准方法是添加一个跟踪搜索深度的列:

示例: 树遍历广度优先顺序

循环检测

首先让我们建立图表:

我们可以通过这样的查询遍历该图:

示例: 无循环检测的图遍历

但是如果我们在该图中添加循环,之前的查询将因 Maximum recursive CTE evaluation depth 错误而失败:

处理循环的标准方法是计算一个已经访问的节点数组:

示例: 带循环检测的图遍历

无限查询

如果在外部查询中使用 LIMIT,还可以使用无限递归 CTE 查询:

示例: 无限递归 CTE 查询