子节点数量不同的表用UNION遇问题,求SQL解决方案
解决递归CTE查询层级表时的列数不匹配问题
看起来你在尝试用递归CTE遍历层级结构的Categories表时踩了两个小坑,导致出现了UNION ALL操作目标列数不一致的错误,我来帮你梳理并解决这个问题:
先看你SQL里的两个明显问题:
- 别名拼写错误:递归部分里写了
rr.parentId,但你定义的子节点表别名是cc,这里完全没定义rr,属于笔误; - 列数不匹配:锚点查询是
select * from Categories c where c.parentId = -1,返回的是3列(id、Name、parentId),但递归查询里你用了select * from Categories cc inner join testtable tt on ...,JOIN之后会返回Categories的3列 +testtable的3列,总共6列,和锚点的列数完全不一致,这就是报错的核心原因。
修正后的正确递归CTE写法:
递归CTE要求锚点成员和递归成员返回完全相同数量、相同类型的列,所以我们要明确指定要返回的列,避免用*带来的列数变化:
WITH testtable AS ( -- 锚点成员:获取所有根节点(parentId = -1) SELECT id, Name, parentId FROM Categories WHERE parentId = -1 UNION ALL -- 递归成员:逐层获取子节点,关联CTE中的父节点 SELECT c.id, c.Name, c.parentId FROM Categories c INNER JOIN testtable tt ON tt.id = c.parentId ) SELECT * FROM testtable;
额外扩展:如果需要展示层级路径
如果你想直观看到每个节点的层级路径,可以给CTE添加一个path列,方便查看节点的归属关系:
WITH testtable AS ( SELECT id, Name, parentId, CAST(Name AS VARCHAR(MAX)) AS node_path -- 根节点路径就是自身名称 FROM Categories WHERE parentId = -1 UNION ALL SELECT c.id, c.Name, c.parentId, CONCAT(tt.node_path, ' > ', c.Name) AS node_path -- 拼接父路径和当前节点名称 FROM Categories c INNER JOIN testtable tt ON tt.id = c.parentId ) SELECT * FROM testtable;
总结一下错误根源:
递归CTE的UNION ALL两边必须保证列数、列顺序、列类型完全一致,你原来的写法因为JOIN了CTE表导致列数翻倍,触发了SQL的语法检查错误。只要明确指定要返回的列,同时修正别名笔误,就能顺利遍历整个层级结构啦。
内容的提问来源于stack exchange,提问作者user3481441
相关产品推荐
相关产品推荐

