查找子树中具有0或1个子节点的所有节点

时间:2013-09-08 12:31:09

标签: mysql sql

在我需要处理的事情中,在给定的时间,我需要找到具有0或1个子节点的树的所有节点(使用物化路径+相邻节点制作)。 列类似于:

id int  
parent_node int  
treepath VARCHAR(255)  
deepness int

当我尝试提出解决方案时,我只能想到使用太多子查询或表连接的非常复杂的查询。

对于有0个孩子的节点,我一直在考虑搜索未被parent_id引用并且在子树内的所有节点。

SELECT *
FROM user_tree
WHERE
    node_id NOT IN (
        SELECT parent_id
        FROM user_tree
        WHERE parent_id IS NOT NULL
    )
    AND
    treepath LIKE 
        (
            SELECT CONCAT(treepath, '/%')
            FROM user_tree
            WHERE node_id = 4
        ) 

使用EXPLAIN,这似乎对数据库有点痛苦,因为它需要多长时间才能获得节点列表。

是否有一种非常痛苦的方式(在性能上)来创建一个查找我想要的内容?

编辑:
根据要求,这里有一些表格的样本格式:

id      parent_id   treepath    deepness
1       NULL        1           0
2       NULL        2           0
3       1           1/3         1
4       1           1/4         1
5       4           1/4/5       2
7       3           1/3/7       2
8       3           1/3/8       2
9       7           1/3/7/11    3

4 个答案:

答案 0 :(得分:2)

没有样本数据,这只是一个猜测:

SELECT t1.*, t2.numchildren
FROM user_tree t1
LEFT JOIN ( SELECT parent_id, COUNT(*) AS numchildren
            FROM user_tree
            GROUP BY parent_id ) t2
ON t1.id = t2.parent_id
WHERE t2.numchildren IS NULL
OR t2.numchildren = 1;

SQL-Fiddle from sample data

答案 1 :(得分:1)

查询

SELECT parent_id, COUNT(id) AS n FROM user_tree GROUP BY parent_id HAVING n = 1

找到有一个孩子的父母。您可能想要添加INDEX(parent_id)。

查询

SELECT id FROM user_tree WHERE id NOT IN (SELECT DISTINCT parent_id FROM user_tree)

找到树叶。相同的索引会有所帮助。

答案 2 :(得分:0)

您的查询逻辑是正确的。我会将条件移到from子句,因为这通常会更好地优化:

SELECT ut.*
FROM user_tree ut join
     (select CONCAT(treepath, '/%') as treepath4
      FROM user_tree
      WHERE node_id = 4
     ) node4 
     on ut.treepath LIKE node4.treepath4 left outer join
     user_tree child
     on child.parent_id = ut.node_id
WHERE ut.treepath LIKE node4.treepath4 and
      child.node_id is null;

对于0或1个孩子:

SELECT ut.*
FROM user_tree ut join
     (select CONCAT(treepath, '/%') as treepath4
      FROM user_tree
      WHERE node_id = 4
     ) node4
     on ut.treepath LIKE node4.treepath4 left outer join
     user_tree child
     on child.parent_id = ut.node_id
GROUP BY ut.node_id
HAVING count(child.node_id) in (0, 1);

答案 3 :(得分:0)

或者,您可以向表中添加新字段children_count。这将大规模优化此特定查询。但是你会在添加/删除节点上浪费一些时间。

相关问题