2011-06-03 9 views
6

Estoy trabajando con una tabla de grupos.Aplanamiento de un árbol de membresía grupal en SQL (con referencias cíclicas)

GroupMembers (nombre de grupo, MemberName)

Hay una fila presente para cada miembro del grupo y un grupo puede contener otros grupos y usuarios.

Me gustaría extraer una lista de pares de GroupName, MemberName donde MemberName es solo una lista de usuarios. Básicamente, aplanando el árbol. He hecho algo similar a esto antes y escribí manualmente las consultas que exportaban las hojas de cada nivel a una tabla separada y luego las consolidé una vez que había alcanzado el último nivel.

El árbol parece estar desbalanceado y no tiene ningún número fijo de niveles. He estado buscando ejemplos de consultas recursivas y no he tenido mucha suerte en su implementación.

¿Alguien tiene algún buen consejo sobre dónde puedo encontrar una solución elegante para esto?

¡Muchas gracias!

ps Si ayuda, estoy trabajando con SQL Server 2008.

ACTUALIZACIÓN: Me topé con CTE recursiva. Mi único problema es que hay referencias cíclicas en los datos :(

Este código que he usado para la consulta: -.

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) 

¿Hay una manera de excluir las referencias cíclicas/Clense los datos antes de la ejecución de la consulta anterior?

Gracias!

ejemplo cíclica/Circular referencia un ejemplo de una referencia cíclica sería donde el da ta contiene lo siguiente: -

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

Gracias por el consejo Mikael!

+2

Sería útil si se pudiera proporcionar algunos datos de entrada de la muestra con una referencia cíclica y lo que la esperada la salida debe ser. –

+0

Entonces, en el ejemplo anterior, los grupos 1, 2 y 3 deben tratarse como el mismo grupo, ¿no? Y tanto 'User1' como' User2' deberían pertenecer a todos los 'Group1',' Group2' y 'Group3'? –

+0

Hola JP, solo estoy volando esto, pero ¿podrías definir tu selección como distinta? No estoy seguro, pero eso podría detener la recursión. Solo un pensamiento –

Respuesta

1

Ésta es la forma en que se excluya a los ciclos

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

Hola Magnus, gracias por tu respuesta. Implementé tu solución y funcionó como un encanto. Utilicé el campo Ruta para extraer el Nombre del Usuario y Nombre de Grupo para el Grupo de Padres en la parte superior del árbol. De nuevo, muchas gracias por su aporte y gracias por su respuesta tan rápida. – JP1220

0

quisiera extraer una lista de pares NombreGrupo, MemberName donde el MemberName es sólo una lista de usuarios.

Probablemente no entienda su estructura aquí, pero a mí me parece que solo tiene que hacer esto.

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

Esto le dará todos los nodos de hoja. Si un grupo puede ser una hoja o si un usuario puede tener miembros, necesita algo más para distinguir entre usuarios y grupos.

resultado con los datos de la muestra:

GroupName MemberName 
--------- ---------- 
Group1  User1 
Group2  User2 
+0

Hola Mikael, gracias por tu respuesta. El problema que tuve fue que necesitaba una lista de grupos principales desde la parte superior del árbol y luego sus listas ampliadas de usuarios de hoja. Puedo ver a dónde te diriges con la sugerencia, pero creo que solo funcionaría si el anidamiento tuviera 1 nivel de profundidad. Después de usar la solución de Magnus, descubrí que la jerarquización variaba de 1 nivel a 8 niveles de profundidad en mis datos. Gracias por su aporte, es muy apreciado. – JP1220

Cuestiones relacionadas