在SQL中展平组成员资格树(使用循环引用)

时间:2011-06-03 08:09:57

标签: sql tsql

我正在使用一张goups表。

GroupMembers(GroupName,MemberName)

每个组成员都有一行,一个组可以包含其他组和用户。

我想提取一个GroupName,MemberName对的列表,其中MemberName只是一个用户列表。基本上,扁平化树。我之前做过类似的事情并手动编写查询,将每个级别的叶子导出到一个单独的表中,然后在达到最后一级后合并这个。

树似乎不平衡,并且没有任何固定数量的级别。我一直在寻找递归查询的例子,并且没有太多运气来实现它们。

有没有人有任何好的指示我可以去哪里为这个提供优雅的解决方案?

非常感谢!

ps如果有帮助,我正在使用SQL Server 2008。

更新:我偶然发现了递归CTE。我唯一的问题是数据中存在循环引用:(。

这是我用于查询的代码: -

    WITH Members AS
    (
    --Init
    SELECT GroupName, MemberName
    FROM GroupMembers
    WHERE MemberName NOT IN (Select GroupName from GroupMembers)
    UNION ALL

    --Recursive Exe
    SELECT h.GroupName, h.MemberName
    FROM GroupMembers h INNER JOIN Members m
    ON h.MemberName = m.GroupName
    )
    Select * into GroupMembersFlattened from Members OPTION (MAXRECURSION 1500)

有没有办法在执行上述查询之前排除循环引用/清除数据?

谢谢!

循环/循环参考示例 循环引用的一个示例是数据包含以下内容: -

    GroupMember,     MemberName
    Group1,     Group2
    Group1,     User1
    Group2,     Group3
    Group2,     User2
    Group3,     Group1

感谢小费Mikael!

2 个答案:

答案 0 :(得分:1)

这是排除周期的方法

WITH Members AS
(
--Anchor
SELECT 
    GroupName, 
    MemberName,
    0 As isCycle,
    '.' + CAST(MemberName As varchar(max)) + '.' As [path]
FROM GroupMembers
WHERE 
    MemberName NOT IN (Select GroupName from GroupMembers)

UNION ALL

--Recursive call
SELECT 
    h.GroupName, 
    h.MemberName,
    CASE WHEN m.[path] like  '%.' + CAST(h.MemberName as varchar(max)) + '.%' THEN 1 ELSE 0 END As isCycle,
    m.[path] + CAST(h.MemberName as varchar(max)) + '.' As [path]
FROM GroupMembers h 
    JOIN Members m
        ON h.MemberName = m.GroupName
WHERE
    m.isCycle = 0
)
SELECT  
    * 
FROM 
    Members
WHERE
    Members.isCycle = 0

答案 1 :(得分:0)

  

我想提取一份清单   GroupName,MemberName对在哪里   MemberName只是一个用户列表。

我可能不明白你的结构,但对我而言,你似乎只需要这样做。

SELECT GroupName, MemberName
FROM GroupMembers
WHERE MemberName NOT IN (Select GroupName from GroupMembers)

这将为您提供所有叶节点。如果一个组可以是一个叶子,或者如果用户可以拥有成员,则需要其他东西来区分用户和组。

您的样本数据的结果:

GroupName   MemberName
---------   ----------
Group1      User1
Group2      User2