使用公用表表达式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有什么技术差异?
答案 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中的递归。