如何编写递归SQL查询从Tag表指定种子id向上查所有父级,现有语句仅返回1行如何解决
问题原因分析
- 第一个错误:子查询的排序逻辑不符合向上递归的要求
你原来的子查询select * from tag order by parentId, id返回的行顺序是id从小到大,也就是父节点在前、子节点在后。当你从子节点(比如示例中的id=9)开始查询时,遍历到id=9这一行的时候,它的所有父节点(8、7、4、2)都已经被扫描过了,SQL不会再回头重新匹配这些已经扫过的行,所以只能返回id=9这一行。
而你向下查询的逻辑能正常运行,就是因为向下查询要求父节点先出现、子节点后出现,原排序刚好匹配这个逻辑。 - 第二个错误:未处理parentId为NULL的边界情况
当遍历到根节点(parentId为NULL)时,concat(@var, ',', parentId)的结果会直接变成NULL,此时length(NULL)返回NULL,会导致根节点这一行的WHERE条件不成立,最终根节点不会被返回。
修复方案
首先将子查询的排序改为ID倒序,保证子节点先被扫描、父节点后被扫描;然后新增NULL处理逻辑,保证根节点可以正常返回。
修复后的SQL示例:
SELECT * FROM (SELECT * FROM tag ORDER BY id DESC) tags_sorted, (SELECT @var := '9') seed WHERE FIND_IN_SET(id, @var) AND IF(parentId IS NOT NULL, LENGTH(@var := CONCAT(@var, ',', parentId)), 1);
执行逻辑说明
- 子查询
tags_sorted按id倒序返回行,示例数据的返回顺序为9、8、7、6、5、4、3、2、1 - 初始
@var = '9',扫描到id=9时匹配成功,将parentId=8追加到@var,@var变为'9,8',返回该行 - 扫描到id=8时匹配成功,将parentId=7追加到
@var,@var变为'9,8,7',返回该行 - 扫描到id=7时匹配成功,将parentId=4追加到
@var,@var变为'9,8,7,4',返回该行 - 扫描到id=6、5、3时均不匹配,直接跳过
- 扫描到id=4时匹配成功,将parentId=2追加到
@var,@var变为'9,8,7,4,2',返回该行 - 扫描到id=2时匹配成功,parentId为NULL,无需追加变量,直接返回该行
- 扫描到id=1时不匹配,跳过
最终返回结果和预期完全一致。
内容的提问来源于stack exchange,提问作者matlab user
相关产品推荐
相关产品推荐

