Recursive Cte to Find Parent Records

Recursive CTE to find Total for all children parent and depth

One option is to use the data type hierarchyid

Example

;with cteP as (
Select ID
,parentid
,Name
,HierID = convert(hierarchyid,concat('/',ID,'/'))
From #Temp
Where parentid is null
Union All
Select ID = r.ID
,parentid = r.parentid
,Name = r.Name
,HierID = convert(hierarchyid,concat(p.HierID.ToString(),r.ID,'/'))
From #Temp r
Join cteP p on r.parentid = p.ID)
Select ID
,parentid
,Name
,Path = HierID.ToString()
,Depth = ( Select max(HierID.GetLevel() ) from cteP where HierID.ToString() like A.HierID.ToString()+'%') - HierID.GetLevel()
,Lvl = HierID.GetLevel()
,ChildCnt = ( Select count(*) from cteP where HierID.ToString() like A.HierID.ToString()+'%') -1
,ParentCnt = len(HierID.ToString()) - len(replace(HierID.ToString(),'/','')) - 2
From cteP A
Order By A.HierID

Results

Sample Image

Recursive CTE to find parent records

Changing to:

INNER JOIN PreviousClaims parent ON parent.fiData = child.idData

Gave me the results you wanted.

How to write a recursive CTE query to find the parent record?

Instead of trying to verify values after the fact, ensure there can never be invalid ParentIDs with a foreign key :

CREATE TABLE csx
(
id INT PRIMARY KEY,
cd VARCHAR(11),
category VARCHAR(20),
lvl INT,
parent_id INT references csx(id)
)

If you wanted to ensure there are no invalid ParentIDs in an existing table, a simple LEFT JOIN would be enough to find all problems:

SELECT t1.*
from csx t1 left join csx t2 on t1.ParentID=t2.ID
where t2.ID is null

This will return all rows with a non-existent ParentID. The FOREIGN KEY on the other hand ensures there won't be any invalid values in the first place.

To calculate levels and paths you can use a recursive CTE. A CTE is more-or-less a subquery that can be referenced by name and used in multiple places. A recursive CTE is a CTE that refers to itsel.

To get all root items and their children, the following CTE first selects all roots, then joins the actual table with itself to retrieve the children :

with cte as (
select csx.* ,
1 as Level,
cast(ID as varchar(200)) as Path
from csx
where parent_id is null
union all
select csx.* ,
cte.Level+1 as Level,
cast(CONCAT_WS('/',cte.Path, csx.ID) as varchar(200)) As Path
from csx inner join cte on cte.ID=csx.parent_id
)
select * from cte
order by path









































































































idcdcategorylvlparent_idLevelPath
1ab-00-00-00ab1NULL11
2ac-00-00-00ac1NULL12
3ac-01-00-00ac2222/3
4ac-01-00-01ac3332/3/4
5ac-01-00-02ac3332/3/5
6ac-03-00-00ac2222/6
7ac-03-00-01ac3632/6/7
8ac-03-00-02ac3632/6/8
9ac-02-00-00ac2222/9
10ac-02-00-01ac3932/9/10

RECURSIVE QUERY - PARENT/CHILD

This is Pseudo SQL terms, but you only need 2 CTEs, and no DISTINCT to get what you are after. Transversing hierachical data, that doesn't use the hierachyid datatype is never going to be as effecient as it could be, as you need recursion.

Anyway, you would effectively just want this:

USE Sandbox;
GO

CREATE TABLE dbo.YourTable (ID int, ParentID int);

INSERT INTO dbo.YourTable (ID,
ParentID)
VALUES(1,NULL),
(2,NULL),
(3,1),
(4,1),
(5,2),
(6,3),
(7,4),
(8,4),
(9,7),
(10,8);
GO
DECLARE @ID int = 4;

WITH Parents AS(
SELECT YT.ID,
YT.ParentID
FROM dbo.YourTable YT
WHERE YT.ID = @ID
UNION ALL
SELECT YT.ID,
YT.ParentID
FROM Parents P
JOIN dbo.YourTable YT ON P.ParentID = YT.ID),
Children AS(
SELECT YT.ID,
YT.ParentID
FROM dbo.YourTable YT
WHERE YT.ID = @ID
UNION ALL
SELECT YT.ID,
YT.ParentID
FROM Children C
JOIN dbo.YourTable YT ON C.ID = YT.ParentID)
SELECT ID, ParentID
FROM Parents P
UNION ALL
SELECT ID, ParentID
FROM Children C
WHERE C.ID != @ID --Stops the initial row being displayed twice
ORDER BY ID ASC;

GO

DROP TABLE dbo.YourTable;

CTE Recursive Query to Grandparents

You need to add the same isdeleted = 0 AND isinedit = 0 predicate to the INNER JOIN childParent CP source.

...but if you do that you make your CTE query very fiddly and if you have to repeat the same thing over-and-over there's probably a better way to do it.

...and there is! A SELECT query can have multiple CTE expressions:

;
WITH filtered AS
(
SELECT
a.id,
a.name,
a.parent_id,
FROM
dbo.Table
WHERE
IsDeleted = 0
AND
IsInEdit = 0
)

WITH cte AS
(
SELECT
a.id,
a.name,
a.parent_id
FROM
filtered

UNION ALL

SELECT
a.id,
a.name,
a.parent_id
FROM
filtered
INNER JOIN cte ON a.parent_id = cte.id
)
SELECT
*
FROM
cte
ORDER BY
id

CTE to get all children and nested children of every parent

In first part of cte select all the rows with ownid as root id. Then in second part (after union all) select parentid as rootid.

Schema and insert statements:

 create table users (UserID int,  ParentID int);
insert into users values (1, NULL);
insert into users values (2, 1);
insert into users values (3, 1);
insert into users values (4, 2);
insert into users values (5, 2);
insert into users values (6, 5);
insert into users values (7, 6);
insert into users values (8, 6);
insert into users values (9, NULL);

Query:

 with cte as
(
select userid rootid, userid, parentid from users
union all
select cte.rootid rootid, users.userid, users.parentid from users
inner join cte on users.parentid=cte.userid
)
select rootid parentid,userid from cte
order by rootid ,userid
option (maxrecursion 0)

Output:



















































































































parentiduserid
11
12
13
14
15
16
17
18
22
24
25
26
27
28
33
44
55
56
57
58
66
67
68
77
88
99

Find Top level Parent and With Recursive CTE

I think this solves your problem. The idea is to force the start on the child rather than doing a lookup initially:

WITH RCTE AS
(
SELECT @childID as parentId, NULL as childid, 1 AS Lvl

UNION ALL

SELECT rh.*, Lvl+1 AS Lvl FROM dbo.RelationHierarchy rh
INNER JOIN RCTE rc ON rh.CHildId = rc.ParentId
)
SELECT TOP 1 id, Name
FROM RCTE r
inner JOIN dbo.Person p ON p.id = r.ParentId
ORDER BY lvl DESC;

Recursive CTE for parent and child relationship in SQL Server

You could move the start condition inside the CTE:

; with  parents as
(
select child_product_id
, parent_product_id
from product
where child_product_id = 392193
and parent_product_id = 392193
union all
select e.child_product_id
, e.parent_product_id
from parents m
join product e
on e.parent_product_id = m.child_product_id
)
select *
from parents
option (maxrecursion 0)

An index on (parent_product_id, child_product_id) would help.

Usually, a child record refers to the primary key of its parent record. In your case, there's something unusual going on, with the parent having a "child_product_id". Some more information on this construct would clarify your question.

Recursive CTE - Compute Parent Value based on child values

This was a bit tricky, anyhow common table expression do miracles.
The idea I'm using is first to select all the leafs (records with prices only) then go step by step upwards each step I take the price multiplied by the coef, and then again till then end. after that, I will use a sum with a group by to get the final result,

My result match your expected output.

 ;with leafs as (
select *,ins.Coef*ins.price [total] from Instances ins where price is not null
union all
select ins.*,leafs.total*ins.Coef [total] from leafs
inner join Instances ins on ins.ID=leafs.ParentID

)
select ID,sum(total) Totalprice from leafs
group by ID
order by ID

The result of the query above is as below:-

ID  Totalprice
1 187.5
2 12.5
3 50
4 10
5 15
6 12
7 13

Hope this helps.



Related Topics



Leave a reply



Submit