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
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 ParentID
s 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
id | cd | category | lvl | parent_id | Level | Path |
---|---|---|---|---|---|---|
1 | ab-00-00-00 | ab | 1 | NULL | 1 | 1 |
2 | ac-00-00-00 | ac | 1 | NULL | 1 | 2 |
3 | ac-01-00-00 | ac | 2 | 2 | 2 | 2/3 |
4 | ac-01-00-01 | ac | 3 | 3 | 3 | 2/3/4 |
5 | ac-01-00-02 | ac | 3 | 3 | 3 | 2/3/5 |
6 | ac-03-00-00 | ac | 2 | 2 | 2 | 2/6 |
7 | ac-03-00-01 | ac | 3 | 6 | 3 | 2/6/7 |
8 | ac-03-00-02 | ac | 3 | 6 | 3 | 2/6/8 |
9 | ac-02-00-00 | ac | 2 | 2 | 2 | 2/9 |
10 | ac-02-00-01 | ac | 3 | 9 | 3 | 2/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:
parentid | userid |
---|---|
1 | 1 |
1 | 2 |
1 | 3 |
1 | 4 |
1 | 5 |
1 | 6 |
1 | 7 |
1 | 8 |
2 | 2 |
2 | 4 |
2 | 5 |
2 | 6 |
2 | 7 |
2 | 8 |
3 | 3 |
4 | 4 |
5 | 5 |
5 | 6 |
5 | 7 |
5 | 8 |
6 | 6 |
6 | 7 |
6 | 8 |
7 | 7 |
8 | 8 |
9 | 9 |
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
How to Migrate Datetime Values to Datetimeoffset in SQL Server
Swap Values for Two Rows in the Same Table in SQL Server
Should a Composite Primary Key Be Clustered in SQL Server
Spark Dataframe Nested Case When Statement
Sqlite3 (Or General SQL) Retrieve Nth Row of a Query Result
Xml Query() Works, Value() Requires Singleton Found Xdt:Untypedatomic
How to Group by and Return Sum Row in Postgres
Insert into a Row at Specific Position into SQL Server Table with Pk
How to Create Xml Schema from an Existing Database in SQL Server 2008
Interesting Tree/Hierarchical Data Structure Problem
Differencebetween Join Keyword and Inner Join Keyword in Oracle SQL
Find First Non-Null Values for Multiple Columns
How to Determine the Primary Key for a Table in SQL Server
Get Top 10 Products for Every Category
SQL Sum Field When Column Values Match
SQL Server's Isnumeric Function
Testing Postgresql Functions That Consume and Return Refcursor