oracle recursive WITH子句如何在引擎盖下工作

时间:2017-07-11 19:59:05

标签: sql oracle recursion common-table-expression

使用公用表表达式aka with子句,我们可以命名子查询,并从我们的SQL语句中的任何位置引用此子查询。更有趣的是,我们可以从查询本身引用查询,从而启用递归,这使得SQL使用完整的语言。

这个概念很简单,但是我很感兴趣Oracle在技术上如何在调用堆栈,行和评估的渴望方面实现递归方面。

以下是递归with子句的简单示例。它的强制递归with子句由两个成员组成:锚成员(初始行)和递归成员,由union all运算符组合。

with numbers(val) as (
  select 1 as val from dual
  union all
  select val + 1 from numbers
  where val < 5
)
select val from numbers

哪个产生

VAL
--
1
2
3
4
5

调用堆栈如何累积结果集&#34;看起来像&#34;在这个例子中?所有的逻辑是如何根据SQL术语从这个语句中构造出可以得到的结果,但是我还没有得到它,或者Oracle是如何解释这个语句来实现递归的呢?

另外,为什么限制因子(where子句)必须在递归成员本身,而不是CTE的使用位置?以下尝试引发错误

with numbers(val) as (
  select 1 as val from dual
  union all
  select val + 1 from numbers
)
select val from numbers where val < 5

错误是

ORA-32044: cycle detected while executing recursive WITH query

这是否意味着Oracle不支持使用公用表表达式进行延迟评估?相比之下,以下适用于PostgreSQL。

WITH RECURSIVE t(v) AS (
  SELECT 1     -- Seed Row
  UNION ALL
  SELECT v + 1 -- Recursion
  FROM t
)
SELECT v
FROM t
LIMIT 5

这让我想起了更多关于终端操作的懒惰评估数据。这与Oracle有什么技术差异?

1 个答案:

答案 0 :(得分:1)

我必须承认我在理解你的问题时遇到了问题。因此构建了递归查询:

<start query>
UNION ALL
<next query>

&lt; start query&gt;执行并检索行。对于这些行中的每一行&lt; next query&gt;执行,生成更多行。并且对于每个新创建的行&lt;下一个查询&gt;再次执行,依此类推,直到不再满足WHERE子句中的条件为止。

您创建一个值为1的行。然后您创建一个1 + 1 = 2的新行。然后创建一个2 + 1 = 3的新行。然后创建一个3 + 1 = 4的新行。然后创建一个4 + 1 = 5的新行。你停下来,因为5与标准value < 5不符。

如果删除WHERE子句,递归查询应该无休止地运行。我不明白这里的ORA错误,因为你永远不会进入一个循环,因为值总是在增加。您可能会耗尽内存或超出允许的最大整数值,但不能进入循环。所以我认为错误信息具有误导性。

如果PostgreSQL在这里使用延迟评估,那么你很幸运。我不认为他们保证会发生这种情况。始终有一个WHERE子句来结束递归cte中的递归。