5

我正在学习 SQL,并且很难理解以下递归 SQL 语句。

WITH RECURSIVE t(n) AS (
    SELECT 1
    UNION ALL
    SELECT n+1 FROM t WHERE n < 100
)
SELECT sum(n) FROM t;

n 和 t 是SELECT sum(n) FROM t;什么?据我所知,n 是 t 的一个集合。我对吗?

还有这个语句是如何触发递归的?

4

3 回答 3

5

您使用的语法类似于 Postgres。SQL 中的“递归”并不是真正的递归,而是迭代。你的说法是:

WITH RECURSIVE t(n) AS (
    SELECT 1
    UNION ALL
    SELECT n+1 FROM t WHERE n < 100
)
SELECT sum(n) FROM t;

for 的语句t被评估为:

  1. 评估非自指部分 ( select 1)。
  2. 然后评估自引用部分。(最初这给出 2。)
  3. 然后再次评估自引用部分。(3)。
  4. 以此类推,条件仍然有效 ( n < 100)。

完成t后,子查询完成,可以评估最终语句。

于 2013-09-17T03:56:06.033 回答
2

让我们把它分开:

WITH RECURSIVE t(n) AS (

一个公用表表达式 (CTE),它应该包括一个种子查询和一个递归查询。CTE 称为t并返回 1 列:n

种子查询:

    SELECT 1

返回 ans 答案集(在这种情况下只有一行:1)并将其副本放入最终答案集中

现在开始递归部分:

    UNION ALL

现在处理从种子查询返回的行并返回 n+1(同样是单行答案集:2)并复制到最终答案集中:

    SELECT n+1 FROM t WHERE n < 100

如果此步骤返回非空答案集(activity_count > 0),则重复(永远)。

像这样的n+1计算的 WHERE 条件通常用于避免无限递归。人们通常知道基于数据的最大可能级别,对于复杂的查询,很容易将某些条件错误;-)

最后返回答案集:

)
SELECT sum(n) FROM t;

当你简单地做一个SELECT * FROM t; 您将看到从 1 到 100 的所有数字,这不是生成此列​​表的一种非常有效的方法。

要记住的最重要的事情是,每个步骤都会产生最终结果的一部分,并且只有上一步中的那些行在下一个递归级别中被处理。

于 2013-09-17T10:48:46.817 回答
2

这称为公用表表达式或 CTE。

查询中的RECURSIVEthe 没有任何意义:它只是另一个名称,例如nor t。使事情递归的是命名的 CTEt在表达式中引用自身。为了产生表达式的结果,查询引擎因此必须递归地构建结果,每次评估都会触发下一次。它达到了这一点:SELECT n+1 FROM t...并且必须停止并评估t。为此,它必须再次调用自身,以此类推,直到条件 ( n < 100) 不再成立。提供SELECT 1了一个起点,并WHERE n < 100使得查询不会永远重复。

至少,这就是它在概念上应该如何工作的方式。通常真正发生的是查询引擎迭代地构建结果,而不是递归地构建结果,如果可以的话,但这是另一回事。

于 2013-09-17T03:58:25.363 回答