TSQL根据条件递归

时间:2015-12-29 21:15:18

标签: sql sql-server sql-server-2008 tsql

我有一个查询来获取组中的成员列表,如下所示

;WITH CTE (GroupName, GroupMember, isMemberGroup)
     AS (SELECT ag.name,
                agm.Member,
                agm.MemberIsGroup
         FROM   tb1 ag
                LEFT JOIN tb2 agm
                  ON ag.ID = agm.ID
         WHERE  ag.name = 'somegroupame')
SELECT *
FROM   CTE 
Group Name   Group Member  IsMemberGroup
Admin        John          0
Admin        Sam           0
Admin        GDBA          1
xyz          Dan           0 
xyz          GXy           1

如果IsMemberGroup为1,我想写一个查询来获取子组的成员。请指导我如何实现这一目标。

预期结果是获取成员列表,包括给定组的子组成员。递归应该发生在所有子组中。团体也是如此:

结果:管理员

     Group              Group Member
     Admin              John
     Admin              Sam
     Admin(GDBA)        Mike
     Admin(GDBA)        June
     Admin(GDBA/Bcksdmin)Mark  

1 个答案:

答案 0 :(得分:1)

您可以使用recursive CTE来生成群组成员层次结构来解决此问题。

此示例使用以下数据:

/* Let's create some sample data to experiment with.
 */
DECLARE @Sample TABLE
    (
        GroupName            VARCHAR(50),
        GroupMember            VARCHAR(50),
        IsMemberGroup        BIT
    )
;

INSERT INTO @Sample
    (
        GroupName,
        GroupMember,
        IsMemberGroup
    )
VALUES
    ('Admin', 'John', 0),
    ('Admin', 'Sam', 0),
    ('Admin', 'GDBA', 1),
    ('GDBA', 'Mike', 0),
    ('GDBA', 'June', 0),
    ('GDBA', 'Bcksdmin', 1),
    ('Bcksdmin', 'Mark', 0)
;

查询使用CTE计算组层次结构。然后将其连接回原始数据,如下所示:

/* Using a recursive CTE we can build the group name
 * hierarchy.
 */
WITH [Group] AS
    (
            /* Anchor query returns all top level teams, ie
             * those that do not appear in the group member
             * field.
             */
            SELECT
                s1.GroupName,
                CAST(s1.GroupName AS VARCHAR(MAX))        AS Breadcrumb
            FROM
                @Sample AS s1
                    LEFT OUTER JOIN @Sample AS s2    ON s2.GroupMember = s1.GroupName
            WHERE
                s2.GroupName IS NULL
            GROUP BY
                s1.GroupName

        UNION ALL

            /* Using recursion, find all children.
             * (Sub groups are identified by the IsMemberGroup flag).
             */
            SELECT
                s.GroupMember                            AS GroupName,
                g.Breadcrumb + '/' + s.GroupMember
            FROM
                [Group] AS g
                    INNER JOIN @Sample AS s        ON s.GroupName = g.GroupName
            WHERE
                s.IsMemberGroup = 1                
    )
SELECT
    g.Breadcrumb,
    s.GroupMember        
FROM
    @Sample AS s
        INNER JOIN [Group] AS g        ON g.GroupName  = s.GroupName
WHERE
    s.IsMemberGroup = 0
;

虽然这个解决方案有效,但如果可能的话,我建议您重新访问表格设计。 GroupMember专栏通过存储团队和团队成员来实现双重任务。将其拆分为Group(带有父查找列)和GroupMember表可以简化任务。每个新表只需要描述一个真实世界对象,使得创建新列的位置更加清晰。