Reputation: 771
I know there were plenty of question of CTE but I still don't know how to do that. I have table Messages with columns: id and previousMessageId. How can I get the parent for id = 957 - it should be: 950.
table Messages
--------------
id | previousMessageId
957 | 956
956 | 950
950 | NULL
This is my query:
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
It gives me:
957
958
But the result should be: 950
Upvotes: 2
Views: 954
Reputation: 32737
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.
Upvotes: 0
Reputation: 17953
You can try like following.
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
In above example, for Id 957 you will get 950 and for Id 999 you will get 997
Upvotes: 4
Reputation: 960
You can use a second column to denote the parent id. The parent layer will have a null column the child layer will then reference the parent layer.
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
Upvotes: 0