MySQL 5.7下无法使用递归CTE,求加州河流父子链查询替代方案
MySQL 5.7 下获取完整河流链的替代方案
刚好碰到过类似的场景,MySQL 5.7确实没法用递归CTE,不过咱们可以用两种方法来实现需求,分别适配不同的场景:
方案一:用用户变量遍历任意层级的河流链
这个方法适合河流层级不确定的情况,能自动遍历从起点(ParentID=0)到所有下游子河流的完整链条。
假设你的表名叫rivers,结构是id INT, parent_id INT,咱们可以这么写:
SELECT @path AS river_chain, id AS current_river_id FROM ( SELECT id, parent_id, @path := CASE WHEN parent_id = 0 THEN CAST(id AS CHAR) ELSE CONCAT(@path, ' -> ', id) END AS path FROM rivers ORDER BY parent_id, id ) AS temp CROSS JOIN (SELECT @path := '') AS init WHERE parent_id != 0 OR (parent_id = 0 AND id IN (SELECT id FROM rivers WHERE parent_id = 0));
代码说明:
- 用
@path变量来动态拼接河流链,初始化时设为空字符串 - 遇到ParentID=0的起点河流时,直接把它的ID作为链条开头
- 后续的子河流会自动把自身ID拼接到对应父河流的链条后面
- 排序必须按
parent_id和id来,确保父河流先被处理,子河流紧跟其后
注意哈:如果你的河流有分叉(一条父河流对应多个子河流),这个方法会自动为每个子分支生成独立的完整链条,不会遗漏任何下游路径。
方案二:固定层级的多层自连接
如果你的河流链层级是固定的(比如最多3级:起点→一级子→二级子),可以用多层自连接的方式,写法更直观:
SELECT r1.id AS start_river, r2.id AS first_child, r3.id AS second_child, CONCAT(r1.id, ' -> ', COALESCE(r2.id, ''), ' -> ', COALESCE(r3.id, '')) AS river_chain FROM rivers r1 LEFT JOIN rivers r2 ON r1.id = r2.parent_id LEFT JOIN rivers r3 ON r2.id = r3.parent_id WHERE r1.parent_id = 0;
代码说明:
- 每一层JOIN对应一个层级的河流:
r1是起点(ParentID=0),r2是它的子河流,r3是r2的子河流 - 用
COALESCE处理没有下游的情况,避免链条中出现NULL值 - 如果层级更多,继续添加LEFT JOIN即可,比如加
r4就对应第三级子河流
额外提示
- 要是数据量较大,建议给
parent_id和id字段加索引,能大幅提升查询速度 - 方案一的变量方法一定要保证排序正确,否则链条拼接会出现错误
内容的提问来源于stack exchange,提问作者evet2364
相关产品推荐
相关产品推荐

