我有一组这样的数据:
ID NAME PARENT
---- ------ -------
1 Obj #1 NULL
2 Obj #2 1
3 Obj #3 4
4 Obj #4 2
5 Obj #5 3
6 Obj #6 NULL
7 Obj #7 6
所以,如果我想用他们最古老的祖先来获得它们,我会得到这样的结果:
ID NAME OLDEST
---- ------ -------
1 Obj #1 NULL
2 Obj #2 1
3 Obj #3 1
4 Obj #4 1
5 Obj #5 1
6 Obj #6 NULL
7 Obj #7 6
如何进行查询?
答案 0 :(得分:0)
由于时间不够,我只会向您展示一个解决方案(这不是最好的解决方案,但是使用重复自连接的逻辑,并且只有在知道上限时才会使用您的层次结构树)。
这是一个有效的SQL Fiddle.
测试数据生成(与您的一样,没有"名称"列):
create table tbl(id int, parent int);
insert into tbl values (1,null),(2,1),(3,4),(4,2),(5,3),(6,null),(7,6);
查询以在层次结构树中找到深度为5的最早的祖先:
select
t1.id, coalesce(t5.id, t4.id, t3.id, t2.id) as oldest
from tbl t1
left join tbl t2 on t1.parent = t2.id
left join tbl t3 on t2.parent = t3.id
left join tbl t4 on t3.parent = t4.id
left join tbl t5 on t4.parent = t5.id
order by 1;
答案 1 :(得分:0)
一些评论推荐“嵌套集”模型,该模型在Joe Celko的SQL书籍中得到了普及。但我发现数据模型很难维护,修改数据很复杂。
我更喜欢我称之为“闭包表”的设计,我在这个广受欢迎的Stack Overflow回答中描述了这个设计:What is the most efficient/elegant way to parse a flat table into a tree?
您的查询将如下所示:
SELECT c.ID, c.NAME, a.ID AS OLDEST
FROM MyTable AS t
JOIN ClosureTable AS c ON t.ID = c.descendant
JOIN MyTable AS a ON a.ID = c.ancestor
WHERE a.PARENT IS NULL;
我还在演示文稿Models for Hierarchical Data中介绍了这个模型(以及其他解决方案)。
以下是我发送此演示文稿的视频录制内容:Models for Hierarchical Data。
我还在我的书SQL Antipatterns: Avoiding the Pitfalls of Database Programming中写了一篇关于分层数据的章节。
如果您需要一个可以在当前存储时使用数据的查询,请参阅Quassnoi在此处的聪明解决方案:https://stackoverflow.com/a/8111762/20860
但不可否认,这不是一个稳定的解决方案,因为它依赖于MySQL的无证行为。我会远离它。
如果您无法更改代码或表结构,并且今天需要它,那么您将不得不接受来自Kamil G.的答案,即使它仅限于固定的深度层次结构。对不起,没有其他解决方案。
答案 2 :(得分:0)
我通常在 MySQL 中重新设计它,以便表格如下所示:
id name
10 Obj#1
1010 Obj#2 -- parent = 10
101020 Obj#6 -- parent = 1010 -- grandparent = 10 ... etc
我的当前设计有一个懒惰的SQL :( 6级嵌套,如果你有更深的嵌套,你可以添加更多)
SELECT a.id, a.NAME,
ifnull(p6.PARENT, ifnull(p5.PARENT, ifnull(p4.PARENT, ifnull(p3.PARENT, ifnull(p2.PARENT, ifnull(p.PARENT, p.id)))))) AS PARENT
FROM 0_a2 AS a
LEFT JOIN 0_a2 AS p ON a.PARENT = p.id
LEFT JOIN 0_a2 AS p2 ON p.PARENT = p2.id
LEFT JOIN 0_a2 AS p3 ON p2.PARENT = p3.id
LEFT JOIN 0_a2 AS p4 ON p3.PARENT = p4.id
LEFT JOIN 0_a2 AS p5 ON p4.PARENT = p5.id
LEFT JOIN 0_a2 AS p6 ON p5.PARENT = p6.id
ORDER BY a.id