2
votes

CTE - obtenir le parent

Je sais qu'il y avait beaucoup de questions sur le CTE, mais je ne sais toujours pas comment faire. J'ai des messages de table avec des colonnes: id et previousMessageId. Comment puis-je obtenir le parent pour id = 957 - il devrait être: 950.

957
958

Voici ma requête:

WITH previous AS 
( 
    SELECT id  
    FROM Messages 
    WHERE id = 957 

    UNION ALL 

    SELECT cur.id 
    FROM Messages cur
    INNER JOIN previous ON cur.previousMessageID = previous.id
) 
SELECT * FROM previous 

Cela donne moi:

table Messages
--------------
id  | previousMessageId
957 | 956
956 | 950
950 | NULL

Mais le résultat devrait être: 950


2 commentaires

Fascinant. Vous n'avez même pas 955 dans les données, et la requête est censée renvoyer cela?


Mon erreur, bien sûr 950, très désolé.


3 Réponses :


0
votes

Vous pouvez utiliser une deuxième colonne pour désigner l'ID parent. Le calque parent aura une colonne nulle, le calque enfant référencera alors le calque parent.

WITH previous AS 
( 
SELECT id, null as parentid  
FROM Messages 
WHERE id = 957 

UNION ALL 

SELECT cur.id, cur.previousMessageID 
FROM Messages cur
INNER JOIN previous ON cur.previousMessageID = previous.id
) 
SELECT ParentID FROM previous where ParentID is not null 


2 commentaires

il donne: id parentid 957 NULL 958957


J'ai modifié la requête pour afficher uniquement le parentid là où il n'est pas nul.



4
votes

Vous pouvez essayer comme suit.

declare @table table(id int,   previousMessageId int)
insert into @table select 957 , 956
insert into @table select 956 , 950
insert into @table select 950 , NULL
insert into @table select 999 , 998
insert into @table select 998 , 997
insert into @table select 997 , NULL

;WITH previous 
     AS (SELECT id, 
                previousmessageid 
         FROM   @table 
         WHERE  id = 957
         UNION ALL 
         SELECT cur.id, 
                cur.previousmessageid 
         FROM   @table cur 
                INNER JOIN previous 
                        ON cur.id = previous.previousmessageid) 
SELECT ID 
FROM   previous 
WHERE  previousmessageid IS NULL 

Dans l'exemple ci-dessus, pour l'ID 957, vous obtiendrez 950 et pour l'ID 999, vous obtiendrez 997


1 commentaires

Merci beaucoup. :)



0
votes
declare @table table(id int,   previousMessageId int)
insert into @table select 957 , 956
insert into @table select 956 , 950
insert into @table select 950 , NULL
insert into @table select 999 , 998
insert into @table select 998 , 997
insert into @table select 997 , NULL;

with cte as (
    -- base case - get all records with no parent
    select *, 
        cast(concat('/', id, '/') as varchar(max)) as [path],
        id as [root]
    from @table
    where previousMessageId is null

    union all

    -- recursive step
    select child.*, 
        concat(parent.path, child.id, '/'),
        parent.root
    from @table as child
    join cte as parent
        on parent.id = child.previousMessageId
)
select *
from cte
where id = 957;
The root column in the final output is the first in the line of ancestors that ends with that particular ID. As to how I accomplished it, the trick is essentially always carrying the parent.root forward through the recursion step. 

0 commentaires