Сглаживание дерева членства в группах в SQL (с циклическими ссылками) - PullRequest
6 голосов
/ 03 июня 2011

Я работаю со столом гупс.

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

Спасибо за отзыв, Микаэль!

Ответы [ 2 ]

1 голос
/ 03 июня 2011

Так вы исключаете циклы

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
0 голосов
/ 03 июня 2011

Я хотел бы извлечь список Пары GroupName, MemberName, где MemberName - это только список пользователей.

Я, вероятно, не понимаю вашу структуру здесь, но мне кажется, что вам нужно только сделать это.

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

Это даст вам все листовые узлы. Если группа может быть конечной, или если у пользователя могут быть участники, вам нужно что-то еще, чтобы различать пользователей и группы.

Результат с данными образца:

GroupName   MemberName
---------   ----------
Group1      User1
Group2      User2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...