Mysql 8.0+ 的递归查询WITH RECURSIVE

MySQL with Recursive是一种基于递归思想的MySQL查询方式,可以实现对数据的递归查询和处理,返回符合条件的数据,在MySQL 8.0版本中,该功能被正式引入。

这种递归查询方式用于单表自关联,可以应用在很多场景下,比如对于树形结构、层级结构的数据处理,以及对数据进行分类汇总等。比如在开发中常见的有部门层级查询,省市区结构查询。

一、基本递归语法
WITH recursive r as (
    -- 递归基:由此开始递归
    select id,parent_id,name from category where id = 1
    union ALL
    -- 递归步:关联查询
    select c.id,c.parent_id,c.name
    from category c inner join r 
    -- r作为父表,c作为子表,所以查询条件是c的parent_id=r.id
    where r.id = c.parent_id
)
select id,parent_id,name from r

 

二、添加层级 path、与树形自关联结构(用部门id联结)

WITH RECURSIVE department_tree (department_id, department_name, parent_department_id, depth, path) AS (
        SELECT 
            department_id, 
            department_name, 
            parent_department_id, 
            1 AS depth, 
            CAST(department_id AS CHAR(200)) AS path
        FROM company_department
        WHERE parent_department_id IS NULL
        UNION ALL
        SELECT 
            cd.department_id, 
            cd.department_name, 
            cd.parent_department_id, 
            dt.depth + 1 AS depth, 
            CONCAT(dt.path, ',', cd.department_id) AS path
        FROM company_department cd
            JOIN department_tree dt ON cd.parent_department_id = dt.department_id
    )
SELECT 
    department_id, department_name, parent_department_id, depth, path
FROM department_tree
ORDER BY path;

 

<think>我们正在处理用户关于MySQL 8.0中使用WITH RECURSIVE时遇到'with is not valid at this position'错误的问题。 根据错误信息,这通常是因为SQL语句中WITH子句的位置不正确。在MySQL中,WITH RECURSIVE必须作为语句的开头(在SELECT、INSERT、UPDATE等之前),并且只能用于最外层查询,不能用于子查询中。 参考引用[2]中提到了MySQL 8.0的一些空间函数使用,但没有直接关于WITH RECURSIVE的信息。不过,我们可以根据MySQL官方文档的规则来解答。 解决步骤: 1. 确保WITH RECURSIVE子句位于整个查询的最前面,并且后面紧跟一个SELECT(或其他DML语句)。 2. 注意:在MySQL 8.0中,WITH RECURSIVE不能用于子查询中(包括派生表、子查询等),只能用于最顶层的查询。 3. 检查是否在同一个查询中使用了多个WITH子句,在MySQL中,一个查询只能有一个WITH子句,但可以定义多个公共表表达式(CTE),用逗号分隔。 示例: 正确的写法: WITH RECURSIVE cte (n) AS ( SELECT 1 UNION ALL SELECT n+1 FROM cte WHERE n < 5 ) SELECT * FROM cte; 错误的写法(将WITH RECURSIVE放在子查询中): SELECT * FROM ( WITH RECURSIVE cte (n) AS ( ... ) SELECT * FROM cte ) AS t; 在子查询中使用会报错,因为MySQL不允许在子查询中使用WITH RECURSIVE。 另外,还要注意递归CTE的语法规则: - 递归部分(UNION ALL之后的部分)不能包含聚合函数、窗口函数、GROUP BY、ORDER BY、DISTINCT等。 - 必须有一个非递归部分(第一个SELECT)和递归部分(引用CTE自身的SELECT)。 - 递归部分中引用CTE只能出现一次,并且只能在FROM子句中。 如果用户是在存储过程或函数中使用WITH RECURSIVE,需要确保MySQL版本是8.0以上,并且存储过程的创建语法正确。但根据引用[1]中提到的错误,如果表mysql.proc有问题,可能会导致存储过程加载失败,但用户的问题似乎是语法错误,所以暂时不考虑。 因此,用户需要检查他们的SQL语句,确保WITH RECURSIVE位于最外层查询的开头,并且没有嵌套在子查询中。 如果用户提供了具体的SQL语句,我们可以帮助进一步分析。 生成相关问题: 1. 如何正确编写MySQL递归查询? 2. WITH RECURSIVEMySQL中有哪些限制? 3. 除了递归查询MySQL 8.0还支持哪些CTE特性? 4. 如何解决MySQL存储过程加载失败的问题(如mysql.proc表缺失)? 5. 在子查询中能否使用WITH RECURSIVE?如果不能,有什么替代方案?</think>### MySQL 8.0 WITH RECURSIVE 报错 'with is not valid at this position' 解决方法 该错误通常由以下原因引起: 1. **位置错误** `WITH RECURSIVE` **必须作为查询的第一部分**,不能出现在子查询或嵌套结构中。 错误示例: ```sql SELECT * FROM ( WITH RECURSIVE cte AS (...) -- 错误!不能出现在子查询中 SELECT ... ) ``` 正确写法: ```sql WITH RECURSIVE cte AS ( -- 必须是整个查询的第一行 ... ) SELECT ... FROM cte; ``` 2. **缺少 RECURSIVE 关键字** 递归 CTE 必须显式声明 `RECURSIVE`: ```sql WITH RECURSIVE cte AS ( -- 必须包含 RECURSIVE ... ) ``` 3. **递归结构错误** 递归 CTE 必须包含: - 初始查询(非递归部分) - `UNION ALL` - 引用自身的递归查询 示例: ```sql WITH RECURSIVE cte(n) AS ( SELECT 1 -- 初始部分 UNION ALL SELECT n+1 FROM cte -- 递归部分(引用cte) WHERE n < 10 ) SELECT * FROM cte; ``` 4. **版本兼容问题** 确保 MySQL 版本 ≥ 8.0.1(CTE 功能引入版本),可通过 `SELECT VERSION();` 验证[^1]。 5. **特殊符号未转义** 若递归查询包含特殊字符(如 `>`、`<`),需用反引号包裹列名: ```sql WITH RECURSIVE cte(`depth`) AS (...) ``` --- ### 验证示例 生成数字序列 1-5: ```sql WITH RECURSIVE numbers AS ( SELECT 1 AS n UNION ALL SELECT n + 1 FROM numbers WHERE n < 5 ) SELECT * FROM numbers; ``` 结果: ``` +---+ | n | +---+ | 1 | | 2 | | 3 | | 4 | | 5 | +---+ ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值