2010-07-01 21 views
6

Estoy tratando de realizar lo que creo que es una recursión difícil utilizando un CTE es SQL Server 2008. Parece que no puedo entender esto.SQL Server 2008 CTE Recursion

En los ejemplos a continuación, puede suponer una profundidad fija de 3 ... nada será menor que eso. En la vida real, la profundidad es "más profunda" pero aún fija. En el ejemplo traté de simplificarlo.

Mis datos de entrada son como los de abajo.

ID  PARENT_ID  NAME   DEPTH 
------------------------------------------ 
1  NULL   A    1 
2  1    B    2 
3  2    C    3 
4  1    D    2 

La salida de mi CTE debe ser la siguiente tabla.

LEVEL1_ID LEVEL2_ID LEVEL3_ID LEVEL1_NAME LEVEL2_NAME LEVEL3_NAME 
-------------------------------------------------------------------------------- 
1   NULL   NULL   A    NULL   NULL 
1   2   NULL   A    B    NULL 
1   2   3   A    B    C 
1   4   NULL   A    D    NULL 

Si puedo conseguir las columnas con un diámetro en la salida Ciertamente puedo asignar a los nombres en una tabla de consulta.

Estoy abierto a otras formas de lograr esto también, incluido el uso de SSIS.

+0

que no podía entender lo que la lógica que está solicitando al mirar en su salida. Creo que la última línea debe ser '/ B/D' porque la identificación principal de' D' es 2, es decir, 'B' – IsmailS

+0

acaba de actualizar la pregunta. lo siento. – thomas

+0

De nuevo lo mismo. En la fila # 4, ¿Por qué necesita Level1_ID como '1' cuando su ID padre es 2? – IsmailS

Respuesta

9

No es realmente tan difícil de hacer:

;WITH cte AS 
(
    SELECT CAST('/' + Name AS VARCHAR(50)) as 'CteName', ID 
    FROM dbo.YourTable 
    WHERE parent_id IS NULL 

    UNION ALL 

    SELECT CAST(cte.CteName + '/' + Name AS VARCHAR(50)), t.ID 
    FROM dbo.YourTable t 
    INNER JOIN cte ON t.parent_id = cte.id 
) 
SELECT cteName FROM cte 
ORDER BY ID 

me da una potencia de:

/A 
/A/B 
/A/B/C 
/A/D 

Como nota lateral: la "profundidad" podría ser fácilmente calculada por el CTE y que no necesariamente tienen que almacenar en la tabla (ver la columna de la Level he añadido):

;WITH cte AS 
(
    SELECT 
     CAST('/' + Name AS VARCHAR(50)) as 'CteName', ID, 
     1 AS 'Level' 
    FROM dbo.YourTable 
    WHERE parent_id IS NULL 

    UNION ALL 

    SELECT 
     CAST(cte.CteName + '/' + Name AS VARCHAR(50)), t.ID, 
     cte.Level + 1 AS 'Level' 
    FROM dbo.YourTable t 
    INNER JOIN cte ON t.parent_id = cte.id 
) 
SELECT cteName FROM cte 
ORDER BY Level, ID 
+1

esto es asombroso. ¡Gracias! Cambié la pregunta un poco, pero esto es excelente. Ciertamente puedo usar este ejemplo. – thomas

+0

¡Grandes marc_s! ¡¡¡¡Tan rápido!!!! – IsmailS

+0

Con este código, ¿no tienes el problema de unir los niveles varias veces? Por ejemplo, durante la primera carrera de la carrera recursiva, unirás los niveles 1 con los niveles 2, durante la segunda carrera volverás a unir los niveles 1 con los niveles 2 y los niveles 2 con los niveles 3, y así sucesivamente ... las filas duplicadas son "eliminados" por el operador de UNIÓN, pero hará muchas combinaciones duplicadas. – munissor

0

No recuerdo que puedas hacer una subconsulta en un cte.

que no tienen una copia del servidor SQL aquí pero se puede tratar con este código:

WITH cte(id, path, level) 
AS 
(
    SELECT id, '/' + name, level 
    FROM yourtable 
    WHERE level = 1 

    UNION ALL 

    SELECT y.id, c.name + '/' + y.name, y.level 
    FROM yourtable y INNER JOIN 
    cte c ON c.id = y.parent_id 
    WHERE level = (SELECT max(level)+1 from cte) 
) 
SELECT path from cte 
+0

Solo recibo un montón de errores: Msg 207, nivel 16, estado 1, línea 6 Nombre de columna inválido 'nivel'. Msg 207, nivel 16, estado 1, línea 4 Nombre de columna no válida 'nivel'. Msg 253, nivel 16, estado 1, línea 1 miembro recursivo de una expresión de tabla común 'cte' tiene múltiples referencias recursivas. –

+1

Ok, así que no puedes usar una subconsulta;) – munissor

-1
;WITH Vals AS (
     SELECT CASE DEPTH WHEN 1 THEN ID ELSE NULL END 'LEVEL1_ID ', 
       CASE DEPTH WHEN 2 THEN ID ELSE NULL END 'LEVEL2_ID ', 
       CASE DEPTH WHEN 3 THEN ID ELSE NULL END 'LEVEL3_ID ', 
       CASE DEPTH WHEN 1 THEN NAME ELSE NULL END 'LEVEL1_NAME', 
       CASE DEPTH WHEN 2 THEN NAME ELSE NULL END 'LEVEL2_NAME', 
       CASE DEPTH WHEN 3 THEN NAME ELSE NULL END 'LEVEL3_NAME', 
       ID 'PRMID'     
     FROM #Table1 
     WHERE parentId IS NULL 
     UNION ALL 
     SELECT CASE DEPTH WHEN 1 THEN ID ELSE LEVEL1_ID END 'LEVEL1_ID ', 
       CASE DEPTH WHEN 2 THEN ID ELSE LEVEL2_ID END 'LEVEL2_ID ', 
       CASE DEPTH WHEN 3 THEN ID ELSE LEVEL3_ID END 'LEVEL3_ID ', 
       CASE DEPTH WHEN 1 THEN NAME ELSE LEVEL1_NAME END 'LEVEL1_NAME', 
       CASE DEPTH WHEN 2 THEN NAME ELSE LEVEL2_NAME END 'LEVEL2_NAME', 
       CASE DEPTH WHEN 3 THEN NAME ELSE LEVEL3_NAME END 'LEVEL3_NAME', 
       ID 'PRMID'        
     FROM #Table1 inner join Vals on #Table1.parentId=PRMID 

) 

SELECT * from Vals 
Cuestiones relacionadas