此bounty已结束。回答此问题可获得+250声望奖励。奖励宽限期将在12小时后结束。StormTrooper希望吸引更多人关注此问题。
我将类别存储在单个表中。
对孩子的数量没有限制。
我想获取所提供类别ID的所有链接子类别:
获取层次结构的原因是,我需要更新每个新创建或更新的类别的路径字段。
表名:categories
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对记录进行排序。
3条答案
按热度按时间rlcwz9us1#
要获取上层次结构,请尝试以下操作:
这里,我们按生成的'ord'值对结果进行排序,不需要按id排序。
若要取得下层阶层,请使用下列程式码:
要获得完整的层次结构(向上和向下),可以将两个递归查询的结果合并为:
由于要存储每个ID的完整路径,因此可以尝试使用自连接的另一种方法,如下所示:
对于上层:
这里,我们使用
length(path)
对结果进行排序,这将保证最上面的父节点首先出现,最下面的子节点最后出现。对于下层,请使用
on C1.path like CONCAT('%', C2.name, '%')
。对于完整层次结构,请使用
on C1.path like CONCAT('%', C2.name, '%') or C2.path like CONCAT('%', C1.name, '%')
。请参见demo on MySQL。
请参阅demo on SQL Server(具有较小修改)。
6jjcrrmo2#
通过对“parentId”列应用筛选器,您从结果集中遗漏了根节点。(您的根没有父节点。)
下面是一个行之有效的方法:
1.使用所需的id过滤初始步骤。(我使用了第一个示例,id = 3)
1.沿着“父链”直到到达根。(Cat 3的父链是Cat 2,Cat 2的父链是Cat 1,Cat 1没有父链:已到达根目录。)
1.运行一个简单的选择。
但是,由于您希望维护“path”字段,因此使用递归CTE计算所有路径,然后检查是否存在不匹配,这样可能更容易:
编辑后问题的解决方案:
https://dbfiddle.uk/agO_kNXf
1dkrff033#
categories
表中的数据表示由节点(类别)连接的树形结构:1.节点可以具有零个或多个子节点;和
1.节点可以具有零个或一个父节点。
步骤1.创建表模式(稍作修改)
步骤2.生成测试数据,每个节点可以有0到3个子节点(请随意修改CTE以包括更多的
union all
。我的测试数据看起来像这样(YMMV,因为兰德()函数):
树的可视化如下所示:
步骤3.检索所有链接的父节点和子节点(即ID=12)
结果: