我有一个自我参考表:
ID|NAME|PARENT_ID
1 |P |NULL
2 |C1 | 1
3 |C2 | 1
4 |C3 | 2
5 |C4 | 4
我试图编写一个查询来获取ID的所有子级(无限级别) 例如: 当输入为1时,我希望所有的行都是1的后代,即
ID|NAME|PARENT_ID
1 |P |NULL
2 |C1 | 1
3 |C2 | 1
4 |C3 | 2
5 |C4 | 4
当输入为2时:
ID|NAME|PARENT_ID
4 |C3 | 2
请检查此SQL Fiddle。
到目前为止我到过这里:
select id as productid,name,@pv:=parent_id
from products
join (select @pv:=1)tmp
where parent_id=@pv
但它只给我两个级别的记录,我需要无限级别的记录。
谢谢你, 窗扇
答案 0 :(得分:1)
您可以使用以下查询来实现此目的:
select id,
name,
parent_id
from (select * from products
order by parent_id, id) base,
(select @pv := '1') tmp
where find_in_set(parent_id, @pv) > 0
and @pv := concat(@pv, ',', id)
这是基于问题中提供的fiddle。
@pv := '1'
中指定的值应设置为您要选择所有后代的父级的ID。
如果父母有多个孩子,这也会有效。但是,要求每条记录parent_id < id
,否则结果将不完整。
另请注意,对于非常大的数据集,此解决方案可能会变慢,因为find_in_set
操作不是在列表中查找数字的最理想方式,当然不是在达到大小的列表中与返回的记录数量相同的数量级。
注意:如果您希望父节点本身也包含在结果集中,那么在上述SQL
前面加上id
感兴趣的where
值前面的前缀子句:
select id,
name,
parent_id
from products
where id = '1'
union
...
备选方案1:CONNECT BY
其他一些数据库具有分层查找的特定语法,例如Oracle数据库上可用的CONNECT BY
子句。 MySql不提供这样的语法。
备选方案2:更智能的标识符
如果您要分配包含分层信息的id
值,事情会变得容易多了。例如,在您的情况下,这可能如下所示:
ID | NAME
1 | P
1-1 | C1
1-2 | C2
1-1-1 | C3
1-1-1-1 | C4
然后您的选择将如下所示:
select id,
name
from products
where id like '1-%'
备选方案3:重复自我加入
如果您知道层次结构树的深度可以达到上限,则可以使用标准sql
,如下所示:
select p5.parent_id as parent5_id,
p4.parent_id as parent4_id,
p3.parent_id as parent3_id,
p2.parent_id as parent2_id,
p1.parent_id as parent_id,
p1.id as product_id,
p1.name
from products p1
left join products p2 on p2.id = p1.parent_id
left join products p3 on p3.id = p2.parent_id
left join products p4 on p4.id = p3.parent_id
left join products p5 on p5.id = p4.parent_id
left join products p6 on p6.id = p5.parent_id
where 1 in (p1.parent_id,
p2.parent_id,
p3.parent_id,
p4.parent_id,
p5.parent_id)
order by 1, 2, 3, 4, 5, 6;
请参阅此fiddle
where
条件指定要检索哪个父级的父级。您可以根据需要使用更多级别扩展此查询。