为何含递归CTE的多CTE查询需在首个CTE前加RECURSIVE?
为什么包含递归CTE的多CTE查询必须在首个CTE前加RECURSIVE?
核心原因
在MySQL(以及遵循SQL标准的数据库)中,只要查询里包含任意一个递归CTE,整个WITH子句就必须以RECURSIVE开头——不管第一个CTE是不是递归的。这是语法规则的硬性要求,判断依据是整个WITH块是否包含递归CTE,而非单个CTE的类型。
具体解释
你遇到的Error Code: 1146错误,本质是数据库没有识别出这是一个包含递归逻辑的查询:当你不加RECURSIVE时,数据库会把所有CTE都当作普通非递归CTE处理,递归CTE里对自身的引用(比如你的temp_cte2自关联)会被当成查找普通表的操作,自然找不到对应的表,所以抛出“表不存在”的错误。
而加上WITH RECURSIVE后,数据库会进入递归CTE的解析模式,能正确识别出查询中的递归逻辑,包括对递归CTE自身的引用,因此可以正常执行。
示例对比
错误写法(无RECURSIVE)
WITH temp_cte1 AS ( SELECT id FROM some_table WHERE parent_id IS NULL ), temp_cte2 AS ( SELECT id, parent_id FROM temp_cte1 UNION ALL SELECT t.id, t.parent_id FROM some_table t JOIN temp_cte2 tc ON t.parent_id = tc.id ) SELECT * FROM temp_cte2;
此写法会触发1146错误,因为数据库将temp_cte2当作普通表查找,无法识别其递归身份。
正确写法(加RECURSIVE)
WITH RECURSIVE temp_cte1 AS ( SELECT id FROM some_table WHERE parent_id IS NULL ), temp_cte2 AS ( SELECT id, parent_id FROM temp_cte1 UNION ALL SELECT t.id, t.parent_id FROM some_table t JOIN temp_cte2 tc ON t.parent_id = tc.id ) SELECT * FROM temp_cte2;
这里尽管temp_cte1是非递归的,但整个WITH块因包含temp_cte2这个递归CTE,必须以RECURSIVE开头,数据库才能正确解析递归逻辑。
总结
一句话概括:只要查询中存在递归CTE,整个WITH子句就必须带RECURSIVE关键字,这是SQL语法的规定,和第一个CTE是否递归无关。
内容的提问来源于stack exchange,提问作者Stryken_03
相关产品推荐
相关产品推荐

