【问题标题】:Multiple parents tree (or digraph) implementation sql server 2005多父树(或有向图)实现 sql server 2005
【发布时间】:2009-05-13 03:36:48
【问题描述】:

我需要在 SQL Server 2005 上实现多父树(或有向图)。 我读过几篇文章,但大多数都使用具有唯一根的单亲树,如下所示。

-My PC
   -Drive C
      -Documents and Settings
      -Program Files
         -Adobe
         -Microsoft
      -Folder X
   -Drive D
      -Folder Y
      -Folder Z

在这个中,一切都源自根元素(我的电脑)。

在我的例子中,一个孩子可能有多个父母,如下所示:

G  A
 \ /
  B
 / \ 
X   C
  /  \
  D   E
  \ /
   F

所以我有以下代码:

create table #ObjectRelations
(
    Id varchar(20),
    NextId varchar(20)
)

insert into #ObjectRelations values ('G', 'B')
insert into #ObjectRelations values ('A', 'B') 
insert into #ObjectRelations values ('B', 'C')
insert into #ObjectRelations values ('B', 'X')
insert into #ObjectRelations values ('C', 'E') 
insert into #ObjectRelations values ('C', 'D') 
insert into #ObjectRelations values ('E', 'F') 
insert into #ObjectRelations values ('D', 'F') 

declare @id varchar(20)
set @id = 'A';

WITH Objects (Id, NextId) AS
( -- This is the 'Anchor' or starting point of the recursive query
  SELECT rel.Id,
         rel.NextId
    FROM #ObjectRelations rel
   WHERE rel.Id = @id
   UNION ALL -- This is the recursive portion of the query
  SELECT rel.Id,
         rel.NextId
    FROM #ObjectRelations rel
   INNER JOIN Objects -- Note the reference to CTE table name (Recursive Join)
      ON rel.Id = Objects.NextId
)
SELECT  o.*
FROM    Objects o

drop table #ObjectRelations

返回以下 SET:

Id                   NextId
-------------------- --------------------
A                    B
B                    C
B                    X
C                    E
C                    D
D                    F
E                    F

预期结果集:

Id                   NextId
-------------------- --------------------
G                    B
A                    B
B                    C
B                    X
C                    E
C                    D
D                    F
E                    F

请注意,缺少关系 G->B,因为它要求一个起始对象(这对我也不起作用,因为我从一开始就不知道根对象)并使用 A 作为开始点将忽略 G->B 关系。

因此,此代码在我的情况下不起作用,因为它要求一个起始对象,这在单父树中很明显(将始终是根对象)。但是在多父树中,您可能有多个“根”对象(如在示例中,G 和 A 是“根”对象,其中根是没有父对象(祖先)的对象)。

所以我有点卡在这里......我需要修改查询以不要求起始对象并递归遍历整个树。 我不知道 (Id, NextId) 实现是否有可能...可能我需要使用某种关联矩阵、邻接矩阵或其他任何方式将其存储为图形(请参阅http://willets.org/sqlgraphs.html)。

有什么帮助吗?你们觉得怎么样? 非常感谢您的宝贵时间 =)

干杯!

来源: Source 1 Source 2 Source 3

【问题讨论】:

    标签: sql-server-2005 tsql tree parent-child hierarchy


    【解决方案1】:

    好吧,我终于想出了以下解决方案。 这是我发现支持多根树和循环有向图的方式。

    create table #ObjectRelations
    (
        Id varchar(20),
        NextId varchar(20)
    )
    
    /* Cycle */
    /*
    insert into #ObjectRelations values ('A', 'B')
    insert into #ObjectRelations values ('B', 'C') 
    insert into #ObjectRelations values ('C', 'A')
    */
    
    /* Multi root */
    
    insert into #ObjectRelations values ('G', 'B')
    insert into #ObjectRelations values ('A', 'B') 
    insert into #ObjectRelations values ('B', 'C')
    insert into #ObjectRelations values ('B', 'X')
    insert into #ObjectRelations values ('C', 'E') 
    insert into #ObjectRelations values ('C', 'D') 
    insert into #ObjectRelations values ('E', 'F') 
    insert into #ObjectRelations values ('D', 'F') 
    
    
    declare @startIds table
    (
        Id varchar(20) primary key
    )
    
    ;WITH 
        Ids (Id) AS
        (
            SELECT  Id
            FROM    #ObjectRelations
        ),
        NextIds (Id) AS
        (
            SELECT  NextId
            FROM    #ObjectRelations
        )
    INSERT INTO @startIds
    /* This select will not return anything since there are not objects without predecessor, because it's a cyclic of course */
    SELECT DISTINCT
        Ids.Id
    FROM
        Ids
    LEFT JOIN
        NextIds on Ids.Id = NextIds.Id
    WHERE
        NextIds.Id IS NULL
    UNION
    /* So let's just pick anyone. (the way I will be getting the starting object for a cyclic doesn't matter for the regarding problem)*/
    SELECT TOP 1 Id FROM Ids
    
    ;WITH Objects (Id, NextId, [Level], Way) AS
    ( -- This is the 'Anchor' or starting point of the recursive query
      SELECT rel.Id,
             rel.NextId,
             1,
             CAST(rel.Id as VARCHAR(MAX))
        FROM #ObjectRelations rel
       WHERE rel.Id IN (SELECT Id FROM @startIds)
    
       UNION ALL -- This is the recursive portion of the query
    
      SELECT rel.Id,
             rel.NextId,
             [Level] + 1,
             RecObjects.Way + ', ' + rel.Id
        FROM #ObjectRelations rel
       INNER JOIN Objects RecObjects -- Note the reference to CTE table name (Recursive Join)
          ON rel.Id = RecObjects.NextId
       WHERE RecObjects.Way NOT LIKE '%' + rel.Id + '%'
    
    )
    SELECT  DISTINCT 
            Id,
            NextId,
            [Level]
    FROM    Objects
    ORDER BY [Level]
    
    drop table #ObjectRelations
    

    可能对某人有用。这是给我的=P 谢谢

    【讨论】:

      【解决方案2】:

      如果要将所有根对象用作起始对象,则应首先更新数据以包含有关根对象(和叶子)的信息。您应该添加以下插入:

      insert into #ObjectRelations values (NULL, 'G')
      insert into #ObjectRelations values (NULL, 'A')
      insert into #ObjectRelations values ('X', NULL)
      insert into #ObjectRelations values ('F', NULL)
      

      当然,您也可以编写锚查询,选择具有Id 而不是NextId 的记录作为根节点,但这更容易。

      接下来,将您的锚查询修改为如下所示:

      SELECT rel.Id,
             rel.NextId
      FROM #ObjectRelations rel
      WHERE rel.Id IS NULL
      

      如果您运行此查询,您会看到有很多重复项,很多弧线多次出现。这是因为您现在有两个来自锚查询的结果,因此树被遍历了两次。

      这可以通过将您的选择语句更改为这个来解决(注意DISTINCT):

      SELECT DISTINCT o.*
      FROM   Objects o
      

      【讨论】:

        【解决方案3】:

        如果你不想做 Ronald 建议的插入,这会做!。

        WITH CTE_MultiParent  (ID, ParentID) 
        AS 
        (
            SELECT ID, ParentID FROM #ObjectRelations
            WHERE ID NOT IN 
            (
                SELECT DISTINCT ParentID FROM #ObjectRelations
            )
            UNION ALL
            SELECT ObjR.ID, ObjR.ParentID FROM #ObjectRelations ObjR INNER JOIN CTE_MultiParent
            ON CTE_MultiParent.ParentID = ObjR.Id
        )
        
        SELECT DISTINCT * FROM CTE_MultiParent
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-05-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多