为了了解递归的行为(在SQLite中,我尝试使用以下语句用递归语句对表的行重新编号:
让我们创建一个示例表,
CREATE TABLE tb
(x TEXT(1) PRIMARY KEY);
INSERT INTO tb
VALUES ('a'), ('b'), ('c');
并重新编号从例如2个开始的行
SELECT tb.x as x, tb.rowid + 1 as idx from tb;
/* yields expected:
a|2
b|3
c|4
*/
[尝试对递归WITH
执行相同操作(忽略ROWID
)会导致分歧-在这里,我添加了LIMIT 6
以防止分歧:
WITH RECURSIVE
newtb AS (
SELECT tb.x, 2 AS idx FROM tb
UNION ALL
SELECT tb.x, newtb.idx + 1
FROM tb, newtb
LIMIT 6 -- only to prevent divergence!
)
SELECT * FROM newtb;
/* yields indefinitely:
a|2
b|2
c|2
a|3
b|3
c|3
...
*/
为什么递归到达表tb
的末尾时不停止?可以预防吗?
为什么递归到达表tb的末尾时不停止?
因为这就是它的设计方式,因此非常有用。它与大多数具有某种形式的递归的语言没有什么不同,并且通常是解决某些编程问题(例如遍历目录树)的有效途径。
[大多数计算机编程语言通过允许函数从自己的代码中调用自身。一些功能编程语言没有定义任何循环结构,而是依赖完全基于递归来反复调用代码。可计算性理论证明这些仅递归语言是图灵完整的;他们与图灵完全命令一样强大的计算能力语言,这意味着它们可以解决与命令式语言,甚至没有迭代控制结构,例如一会儿。Recursion (computer science)
如果您使用LIMIT(SELECT tb()from tb)而不是LIMIT 6,则递归将基于表中的行数而停止。
但是,如果您要重新编号(通过在行ID上加1),那么您将看到更多类似:-
WITH RECURSIVE
cte(idx,newidx) AS (
SELECT (SELECT max(rowid) FROM tb),(SELECT max(rowid) FROM tb) +1
UNION ALL
SELECT
idx-1, newidx-1 FROM cte
WHERE idx > 0
)
SELECT (SELECT x FROM tb WHERE tb.rowid = cte.idx) AS x, newidx, idx AS original FROM cte WHERE x IS NOT NULL;
(假设tb的行包含a,b和c...。X,Y和Z,并且删除了d-w行,结果为:-SQlite的推理是:-
递归公用表表达式提供了执行树和图的分层或递归查询,一种功能这是SQL语言无法提供的。SQL As Understood By SQLite - WITH clause可以防止吗?
是的,您不能使用递归,因为可能有其他选择,但是与递归其他语言一样,如果您确实使用递归,则必须具有某种方法来检测何时应完成递归。使用WHERE或LIMIT子句可以简化此过程。