6
votes

Récuission CTE SQL Server 2008

J'essaie d'effectuer ce que je crois que c'est une récursion difficile à l'aide d'un CTE est SQL Server 2008. Je n'arrive pas à envelopper ma tête autour de celui-ci.

Dans les exemples ci-dessous, vous pouvez assumer une profondeur fixe de 3 ... rien ne sera jamais inférieur à cela. Dans la vie réelle, la profondeur est "plus profonde" mais toujours corrigée. Dans l'exemple, j'ai essayé de le simplifier certains. P>

Mes données d'entrée sont comme ci-dessous. P>

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


4 commentaires

Je ne pouvais pas comprendre quelle logique vous postulez en regardant votre sortie. Je pense que la dernière ligne doit être / b / d car l'ID parent de d est 2 I.e. B B


vient de mettre à jour la question. Pardon.


Encore la même chose. Dans la rangée n ° 4, pourquoi avez-vous besoin de niveau1_id comme 1 lorsque son identifiant parent est 2?


Je pense que l'entrée et la sortie sont correctes maintenant. ID de 1 a parent_id de null.


3 Réponses :


9
votes

Pas vraiment tout ce difficile à faire: xxx pré>

me donne une sortie de: p> xxx pré>

comme une note latérale: le "Profondeur" pourrait être facilement calculé par le CTE et vous n'avez pas nécessairement besoin de stocker cela dans votre table (voir la colonne Niveau Code> J'ai ajouté): P>

;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


4 commentaires

C'est génial. Merci! J'ai changé la question un peu mais c'est excellent. Je peux certainement utiliser cet exemple.


Avec ce code, vous n'avez pas le problème de rejoindre les niveaux plusieurs fois? Par exemple, au cours de la 1ère exécution de la course récursive, vous rejoindrez les niveaux 1 avec les niveaux 2, au cours de la 2e exécution, vous rejoindrez à nouveau les niveaux 1 avec les niveaux 2 et les niveaux 2 avec les niveaux 3, etc. .. les lignes en double. sont "supprimés" B l'opérateur du syndicat, mais cela fera beaucoup de jointures en double.


@MUNISSOR: Non, SQL Server gérera cette version spécifique du CTE en tant que CTE récursive (Union tout est le mot clé requis pour cela) et fera tout le travail nécessaire nécessaire. Aucun niveau n'est joint à plusieurs fois.


Vous avez raison, le syndicat préservera toutes les valeurs dupliquées, le cas échéant.



0
votes

Je ne me souviens pas de toi peut faire une sous-requête dans un CTE.

Je n'ai pas de copie de SQL Server ici, mais vous pouvez essayer avec ce code: P>

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


2 commentaires

Je reçois seulement une tonne d'erreurs: MSG 207, niveau 16, état 1, ligne 6 Nom de colonne non valide "Niveau". MSG 207, niveau 16, état 1, ligne 4 Nom de colonne non valide "Niveau". MSG 253, niveau 16, État 1, ligne 1 Membre récursif d'une expression de table commune 'CTE' a plusieurs références récursives.


Ok donc tu ne peux pas utiliser de sous-requête;)



-1
votes
;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

0 commentaires