我有一个MySQL表,如下所示:
id |
name |
parent_id |
19 |
category1 |
0 |
20 |
category2 |
19 |
21 |
category3 |
20 |
22 |
category4 |
21 |
... |
... |
... |
现在,我想有一个单一的MySQL查询,我只是提供id[例如说id=19],然后我应该得到它的所有子id[即结果应该有id '20,21,22']....
孩子们的等级尚不清楚;它可以变化....
我知道如何使用for循环…但是如何使用一个MySQL查询来实现相同的功能呢?
如果需要快速读取速度,最好的选择是使用闭包表。闭包表为每个祖先/后代对包含一行。在你的例子中,闭包表是这样的
ancestor | descendant | depth
0 | 0 | 0
0 | 19 | 1
0 | 20 | 2
0 | 21 | 3
0 | 22 | 4
19 | 19 | 0
19 | 20 | 1
19 | 21 | 3
19 | 22 | 4
20 | 20 | 0
20 | 21 | 1
20 | 22 | 2
21 | 21 | 0
21 | 22 | 1
22 | 22 | 0
一旦有了这个表,分层查询就变得非常简单和快速。获取类别20的所有子类:
SELECT cat.* FROM categories_closure AS cl
INNER JOIN categories AS cat ON cat.id = cl.descendant
WHERE cl.ancestor = 20 AND cl.depth > 0
当然,无论何时使用这样的非规格化数据都有一个很大的缺点。您需要在类别表旁边维护闭包表。最好的方法可能是使用触发器,但是正确跟踪闭包表的插入/更新/删除有点复杂。与任何事情一样,您需要查看您的需求,并决定哪种方法最适合您。
编辑:请参阅问题:在关系数据库中存储层次数据的选项是什么?更多选项。不同的情况有不同的最佳解决方案。
这是一个分类表。
SELECT id,
NAME,
parent_category
FROM (SELECT * FROM category
ORDER BY parent_category, id) products_sorted,
(SELECT @pv := '2') initialisation
WHERE FIND_IN_SET(parent_category, @pv) > 0
AND @pv := CONCAT(@pv, ',', id)
输出:
我发现更容易做到:
1)创建一个函数,检查一个项目是否在另一个项目的父层次结构中的任何地方。就像这样(我不会写函数,用WHILE DO):
is_related(id, parent_id);
在你的例子中
is_related(21, 19) == 1;
is_related(20, 19) == 1;
is_related(21, 18) == 0;
2)使用子选择,就像这样:
select ...
from table t
join table pt on pt.id in (select i.id from table i where is_related(t.id,i.id));