来自其他编程语言的SQL,递归查询的结构看起来很奇怪。一步一步地走,它似乎崩溃了。
考虑以下简单示例:
CREATE TABLE #NUMS
(N BIGINT);
INSERT INTO #NUMS
VALUES (3), (5), (7);
WITH R AS
(
SELECT N FROM #NUMS
UNION ALL
SELECT N*N AS N FROM R WHERE N*N < 10000000
)
SELECT N FROM R ORDER BY N;
让我们来看一看。
首先,执行锚成员并将结果集放入R。因此R初始化为{3,5,7}。
然后,执行降到UNION ALL以下,并且第一次执行递归成员。它在R上执行(即在我们当前拥有的R上:{3,5,7})。结果为{9,25,49}。
这个新结果如何处理?是否将{9,25,49}附加到现有的{3,5,7}上,标记结果并集R,然后从那里进行递归?还是将R重新定义为仅此新结果{9,25,49},然后再进行所有合并?
两种选择都没有道理。
如果R现在为{3,5,7,9,25,49}并且执行递归的下一个迭代,那么我们将以{9,25,49,81,625,2401}结束,并且失去了{3,5,7}。
如果现在R仅是{9,25,49},则存在标签错误的问题。R被理解为锚定成员结果集与所有后续递归成员结果集的并集。而{9,25,49}只是R的一个组成部分。到目前为止,我们还没有获得R的全部。因此,将递归成员写为从R中选择是没有意义的。
我当然感谢@Max Vernon和@Michael S.在下面进行了详细介绍。即,(1)创建所有组件直到递归限制或空集,然后(2)将所有组件结合在一起。这就是我理解SQL递归实际工作的方式。
如果我们正在重新设计SQL,也许我们将强制使用更清晰明了的语法,如下所示:
WITH R AS
(
SELECT N
INTO R[0]
FROM #NUMS
UNION ALL
SELECT N*N AS N
INTO R[K+1]
FROM R[K]
WHERE N*N < 10000000
)
SELECT N FROM R ORDER BY N;
有点像数学中的归纳证明。
目前,SQL递归的问题在于它以一种令人困惑的方式编写。编写方式说每个组件都是通过从R中选择来形成的,但这并不意味着到目前为止已经(或似乎已经)构造了完整的R。它仅表示先前的组件。