我将类别存储在一个表中。
child 的数量没有限制。
我想为提供的类别 ID 获取所有链接的子类别:
获取层次结构的原因是我需要为新创建或更新的每个类别更新路径字段。我需要维护路径字段
表名:类别
id parentId name path
A1 null Cat 1 Cat 1
A2 A1 Cat 2 Cat 1 > Cat 2
A3 A2 Cat 3 Cat 1 > Cat 2 > Cat 3
A4 null Cat A Cat A
A5 A4 Cat B Cat A > Cat B
现在我想获取 id: 1
到目前为止我尝试过的是:
with recursive cte (id, name, parentId) AS (
select
id,
name,
parentId
from
categories
where
parentId = 'A1'
union
all
select
c.id,
c.name,
c.parentId
from
categories c
inner join cte on c.parentId = cte.id
)
select
*
from
cte;
上面的查询返回:
[
{
id: A1,
parentId: null,
name: Cat 1,
path: Cat 1
},
{
id: A2,
parentId: A1,
name: Cat 2,
path: Cat 1 > Cat 2
}
]
但我想要这个:
[
{
id: A2,
parentId: A1,
name: Cat 2,
path: Cat 1 > Cat 2
},
{
id: A3,
parentId: A2,
name: Cat 3,
path: Cat 1 > Cat 2 > Cat 3
}
]
如果我提供 id: 2
,那么我期望:
[
{
id: A3,
parentId: A2,
name: Cat 3,
path: Cat 1 > Cat 2 > Cat 3
}
]
我在查询中做错了什么,任何人都可以识别吗?
这是重现的场景:https://dbfiddle.uk/Beefs-UH
重要说明: 主键即 id 是唯一标识符字符串而不是整数。所以记录不能按id排序。
最佳答案
要获取上层结构,请尝试以下操作:
with recursive cte (id, name, parentId, path, ord) as
(
select id, name, parentId, path, 1 as ord
from categories
where id = 'A2'
union all
select c.id, c.name, c.parentId, c.path, t.ord+1
from categories c join cte t
on t.parentId = c.id
)
select * from cte
order by ord desc;
在这里,我们按生成的 'ord' 值对结果进行排序,您不需要按 id 排序。
要获得向下层次结构,请使用以下内容:
with recursive cte (id, name, parentId, path, ord) as
(
select id, name, parentId, path, 1 as ord
from categories
where id = 'A2'
union all
select c.id, c.name, c.parentId, c.path, t.ord+1
from categories c join cte t
on c.parentId = t.id
)
select * from cte
order by ord;
要获得完整的层次结构(向上和向下),您可以合并两个递归查询的结果,如下所示:
with recursive cte(id, name, parentId, path, ord) as
(
select id, name, parentId, path, 1 as ord
from categories
where id = 'A2'
union all
select c.id, c.name, c.parentId, c.path, t.ord+1
from categories c join cte t
on t.parentId = c.id
),
cte2(id, name, parentId, path, ord) as
(
select id, name, parentId, path,0 as ord
from categories
where id = 'A2'
union all
select c.id, c.name, c.parentId, c.path, ord-1
from categories c join cte2 t
on c.parentId = t.id
)
select id, name, parentId, path from
(
select * from cte
union all
select * from cte2
) T
where ord <> 0 /*to avoid id = 'A2' duplication (one from cte and one from cte2)*/
order by ord desc
由于您要存储每个 ID 的完整路径,您可以尝试使用以下自连接的另一种方法:
对于上层:
select C1.id, C1.parentId, C1.name, C1.path
from categories C1 join categories C2
on C2.path like CONCAT('%', C1.name, '%')
where C2.id='A2'
order by length(C1.path)
这里,我们使用length(path)
对结果进行排序,这样可以保证最上层的父节点先出现,最低的子节点最后出现。
对于向下层次结构,在 C1.path 上使用 ,如 CONCAT('%', C2.name, '%')
。
对于完整的层次结构,在 C1.path 上使用 like CONCAT('%', C2.name, '%') 或 C2.path like CONCAT('%', C1.name, '%')
.
查看 demo on MySQL .
查看 demo on SQL Server (稍作修改)。
关于mysql - 检索所有子类别 - sql 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74404771/