Sql server查询以展平记录层次结构

Jer*_*emy 2 sql-server sql-server-2000 hierarchy

我有一个描述层次结构的表:

Name    MemberName
A       B
A       C
B       D
D       E
F       G
Run Code Online (Sandbox Code Playgroud)

MemberName引用同一个表的Name列.从这张表中,我可以轻松查询B和C是A中的成员,D是B的成员,E是D的成员,G是F的成员.

基于这种结构,很难编写一个查询,表明D和E也间接成为A的成员.D和E也间接成为B的成员等等.所以我需要做的是建立一个新的表该节目显示了所有间接成员.所以对于上面的表数据,我最终会得到一个包含以下内容的表:

Name    MemberName
A       B
A       C
A       D
A       E
B       D
B       E
D       E
F       G
Run Code Online (Sandbox Code Playgroud)

我首先将所有不是其他记录(顶级)记录成员的记录放入临时表中:

CREATE TABLE #TMP
(
    [Name] varchar(20),
    [MemberName] varchar(20)
)

DECLARE @iRowsFound INT
INSERT INTO #TMP ([Name],[MemberName]) 
(SELECT * FROM [HierarchyData] WHERE [Name] NOT IN 
   (SELECT [MemberName] FROM [HierarchyData]))
SELECT @iRowsFound = @@ROWCOUNT

Name    MemberName
A       B
A       C
F       G
Run Code Online (Sandbox Code Playgroud)

然后我的理论是,在一个while循环中,将临时表交叉连接到heirachy表,并将来自交叉连接的适用记录插回到临时表中,并执行while循环,直到十字架中没有更多适用的记录加入以插入:

WHILE (@iRowsFound > 0)
BEGIN
    INSERT INTO #TMP ([Name],[MemberName]) 
    (
        SELECT 
            [NewName] = ??,
            [NewMember] = ??
        FROM
            [HierarchyData],[#TMP]
        WHERE
            ???        
    )
    SELECT @iRowsFound = @@ROWCOUNT
END
Run Code Online (Sandbox Code Playgroud)

我只是不确定我是否在正确的轨道上,因为我对交叉连接选择应该是什么感觉有点难过.有没有人做过这样的事情(在sql server 2000中)?

编辑:我想我可能已经得到它: - 虽然我很确定必须有一个更有效的方法来做到这一点......

WHILE (@iRowsFound > 0)
BEGIN
    INSERT INTO #TMP ([Name],[MemberName]) 
    (       
            SELECT
                --[#TMP].[Name],
                --[#TMP].[MemberName],
                [HierarchyData].[Name],
                [HierarchyData].[MemberName]
            FROM 
                [#TMP]
            JOIN 
                [HierarchyData] ON [#TMP].[MemberName] = [HierarchyData].[Name]
            --WHERE
            --  [#TMP].[MemberName] = [HierarchyData].[Name]
            AND NOT EXISTS (SELECT * FROM [#TMP] WHERE [#TMP].[Name] = [HierarchyData].[Name] AND [#TMP].[MemberName] = [HierarchyData].[MemberName])   
            UNION   
            SELECT
                [#TMP].[Name],
                --[#TMP].[MemberName],
                --[HierarchyData].[Name],
                [HierarchyData].[MemberName]
            FROM 
                [#TMP]
            JOIN 
                [HierarchyData] ON [#TMP].[MemberName] = [HierarchyData].[Name]     
            AND NOT EXISTS (SELECT * FROM [#TMP] WHERE [#TMP].[Name] = [#TMP].[Name] AND [#TMP].[MemberName] = [HierarchyData].[MemberName])    

    )
    SELECT @iRowsFound = @@ROWCOUNT
END
Run Code Online (Sandbox Code Playgroud)

Hog*_*gan 6

很遗憾你不是在SQL Server 2005或更高版本上,使用递归CTE很容易,代码在这里:

WITH Members AS
(
  Select Name, MemberName 
  FROM HierarchyData
  UNION ALL
  SELECT Name, Child.MemberName as [MemberName]
  FROM Members
  JOIN HierarchyData Child ON Members.MemberName = Child.Name
)
SELECT * FROM Members
Run Code Online (Sandbox Code Playgroud)

在2000年你可以基本上以相同的方式完成它(将最后一个选择的结果连接到原始表,直到你没有循环中最后一个集的结果),但它更难,因为你必须跟踪什么迭代你在柜台上.呸.

这有用吗,或者你想要一些sql 2000伪代码?

更好的是,升级!

  • @Jim:嗯...好像我说的是第一行.我的答案也是公认的答案.我在问题中留下了两个答案,因为如果有人读了这个问题谁有2005年(随着时间的推移我们可以期待越来越多),他们将知道如何在他们的SQL版本中做到这一点. (7认同)
  • +1帮助我找到我要找的东西. (4认同)