【问题标题】:How to get all children of a node in tree structure ? SQL query?如何获取树结构中节点的所有子节点? SQL查询?
【发布时间】:2011-09-10 14:56:52
【问题描述】:

表-用户

列 - (userId ,name, managerId)

行 -

(1,nilesh,0)
(2,nikhil,1)    
(3,nitin ,2)  
(4,Ruchi,2)

如果我给出用户 ID,它应该列出所有向他报告的人。 如果我给 userId = 2 它应该返回 3,4。

这个查询是否正确

SELECT ad3.userId
FROM user au , user  au2 , user  au3
WHERE 
    ad.managerId = ad2.managerId AND 
    ad3.managerId = ad2.userId AND
    ad.userId=2

是否有任何有效的方法来管理 DB 中的树结构? 左右叶方式怎么样?

【问题讨论】:

  • 你使用什么样的数据库?
  • 如果您正在寻找在关系数据库中实现层次结构的替代方法,您可以查看此演示文稿。 slideshare.net/billkarwin/models-for-hierarchical-data
  • 了解数据库引擎非常重要。您想要的是“WITH”子句,但它并未得到普遍支持。
  • “WITH”子句称为“递归公用表表达式”,PostgreSQL、Firebird、Oracle、DB2、SQL Server、Sybase和H2都支持

标签: sql database tree


【解决方案1】:

我使用文本字段来处理 SQL 中的树。它比使用左/右值更容易。

让我们以 MySQL 文章中的示例为例:

+-----------------------+
| name                  |
+-----------------------+
| ELECTRONICS           |
|  TELEVISIONS          |
|   TUBE                |
|   LCD                 |
|   PLASMA              |
|  GAME CONSOLES        |
|  PORTABLE ELECTRONICS |
|   MP3 PLAYERS         |
|    FLASH              |
|   CD PLAYERS          |
|   2 WAY RADIOS        |
|    FRS                |
+-----------------------+

它会产生这样的表格:

Id      ParentId        Lineage     Name

1       null            /1/         ELECTRONICS
2       1               /1/2/       TELEVISIONS
3       2               /1/2/3/     TUBE
4       2               /1/2/4/     LCD
5       2               /1/2/5/     PLASMA
6       6               /1/6/       GAME CONSOLES
7       1               /1/7/       PORTABLE ELECTRONICS
8       7               /1/7/8/     MP3 PLAYERS
9       8               /1/7/8/9/   FLASH
10      7               /1/7/10/    CD PLAYERS
11      1               /1/11/      2 WAY RADIOS
12      11              /1/11/12/   FRS

请务必从便携式设备中找到您只需使用 Lineage 的所有便携式设备:

SELECT * FROM theTable WHERE Lineage LIKE '/1/7/%'

缺点:

  • 您需要在每次 INSERT 后执行 UPDATE 以将 PK 附加到 Lineage

建议:

我通常添加另一列,将路径作为文本放入(例如'electronics/televisions/tube'

【讨论】:

  • 它处理 sql 中的通配符,这不是那么可靠。效率不高。在深树的情况下这是一个问题 :) 通配符字符串搜索总是会影响性能。
  • a) 不可靠?究竟什么是不可靠的? b) 我并不是说这是适用于所有场景的通用解决方案。您的员工树可以有多深?这几乎不是问题。 c) 在您的情况下,我很难看出它会如何影响性能。听起来像是过早的优化。
  • 伙计,您使用通配符和比较数字在 SQL 中运行查询。查询通配符将需要更多时间。因此,所有孩子的检索时间都更长。我第一次采取像你这样的方法,但它是效率不高。
  • 我并不是说你的方法是错误的,我是说它没有那么有效。;)
  • 令人惊叹的解决方案我知道性能,但对我来说根本没有更好的方法,因为我处理现有的表并且在数千行上运行得非常快并使用实体框架
【解决方案2】:

类似这样的东西(ANSI SQL):

WITH RECURSIVE emptree (userid, name, managerid) AS (
    SELECT userid, 
           name, 
           managerid
    FROM the_table 
    WHERE userid = 2

    UNION ALL

    SELECT c.userid, 
           c.name,
           c.managerid
    FROM the_table c
       JOIN emptree p ON p.userid = c.managerid
)
SELECT *
FROM emptree

【讨论】:

  • 大卫斯蒂尔的回答比你的更有效率!不错的尝试:)
  • 但前提是树不经常变化。
  • a_horse_with_no_name 是正确的,但如果这真的是针对经理和员工的,那么每天更改一次以上的可能性不大。
  • @David Steele:绝对。但了解所有选项总是好的;)
  • 你是对的。这个模型在频繁检索节点而不是更新节点时很好:)
【解决方案3】:

在我看来,邻接表模型的问题在于它很难在 SQL 中处理,尤其是当您不知道树结构的嵌套深度时。

你提到的'左右叶子方式'可能是嵌套集合模型,允许你存储这样的东西

LFT   RGT   Name
1     8      nilesh
2     7      nikhil
3     4      nitin
5     6      Ruchi

那么你可以通过简单的方式找到任何人的所有下属

SELECT Name FROM Hierarchy WHERE LFT BETWEEN @LFT AND @RGT

我认为查询更容易处理,但树修改更难处理。如果您的数据没有太大变化,那么我认为这是一个更好的解决方案。 (虽然不是每个人都会同意我的观点)

有一个Very good Tutorial here

【讨论】:

  • 如果 DBMS 支持分层查询(现在几乎所有主要 DBMS 都支持),则邻接模型很容易处理
  • @David Steele 老兄,你太棒了!我期待这个答案:)
  • 好点,我确实需要查一下。但是我仍然认为,如果数据没有太大变化,NS 通常是要走的路,因为读取数据的查询更容易编写和理解。
  • 谢谢尼莱什。很高兴你喜欢它。
  • 根据您使用的数据库,邻接列表模式可以更快。见explainextended.com/2009/09/24/…
【解决方案4】:

我对这个问题有一个简单的答案:

表创建:

   Create Table #AllChilds(id int)

列表项:

   Declare @ParentId int; 
   set @ParentId=(Select Id from Employee Where id=1)   
   -- Here put the id as the record for which you want all childs
   While(@ParentId is not null ) 
   begin 
   set @ParentId=(Select Id from Employee Where ParentId=@ParentId) 
   insert into #AllChilds values(@ParentId) 
   end 

查看结果:

   Select Id from #AllChilds 

清理:

Drop table #AllChilds

【讨论】:

    【解决方案5】:
    SELECT user.id FROM user WHERE user.managerid = 2
    

    这是你想要的吗?

    【讨论】:

    • 看起来不像树状结构。
    • 不,这里是树结构,我给出父 ID,然后我应该得到所有直接或间接节点的 ID。
    • 如果你给 userid = 1 它应该返回 2, 3 ,4 还是只返回 2 ?
    • 此查询非常适合此目的)))如果您只需要来自 userid = 1 的 2 )))
    • 如果您需要构建具有所有节点和叶子的树,最好的方法是选择所有行按 parent_id 排序并通过您的 prog lang 构建它......但无论如何如果表很大它不会很快起作用,因为不可能将大象隐藏在火柴盒中)))
    猜你喜欢
    • 1970-01-01
    • 2010-12-12
    • 1970-01-01
    • 2011-05-04
    • 2010-10-02
    • 1970-01-01
    • 2013-01-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多