SQL Recursive Query on hirachical name - sql
New to MS SQL.
Having the table like as follows,
ID Name Parent ID
1 AA 0
2 BB 1
3 CC 2
4 DD 3
5 EE 3
6 FF 4
7 FG 6
8 AD 1
9 AC 2
My expected Result is showed in the Hierarchical Name
ID Name Parent ID Hirarchical Name
1 AA 0 AA
2 BB 1 AA.BB
3 CC 2 AA.BB.CC
4 DD 3 AA.BB.CC.DD
5 EE 3 AA.BB.CC.EE
6 FF 4 AA.BB.CC.DD.FF
7 FG 6 AA.BB.CC.DD.FF.FG
8 AD 1 AA.AD
9 AC 2 AA.BB.AC
Thanks for your help in advance.
Recursive CTEs are a bit tricky. This does what you want:
with cte as (
select id, name, convert(varchar(max), name) as hier, 1 as lev
from t
where parentid = 0
union all
select t.id, t.name, cte.hier + '.' + t.name, lev + 1
from cte join
t
on t.parentid = cte.id
where lev < 10
)
select *
from cte;
Here is a db<>fiddle.
Related
Select distinct fields from multiple table
Table 1 - ID VehicleID 1 A 2 A 3 A 1 B 1 C 4 C 2 D Table 2- ID VehicleID VehicleNo 1 A AA 2 A AA 3 A 1 B BB 1 C CC 4 C CC 2 D DD Output- VehicleId VehicleNo A AA B BB C CC D DD
This is how I understood it; read comments within code. SQL> with 2 -- calculate "RN" (so that you'd have something to match rows on) 3 a as 4 (select vehicleid, 5 row_number() over (order by vehicleid) rn 6 from (select distinct vehicleid from tab1) 7 ), 8 b as 9 (select vehicleno, 10 row_number() over (order by vehicleno) rn 11 from (select distinct vehicleno from tab2) 12 ) 13 -- final query 14 select a.vehicleid, b.vehicleno 15 from a left join b on a.rn = b.rn; VEHICLEID VEHICLENO ---------- ---------- A AA B BB C CC D DD SQL>
One simple method is aggregation: select VehicleId, max(VehicleNo) as VehicleNo from table2 group by VehicleId;
SQL - Query to identify the parentid in a hierarchy with some conditions
I have a table in SQL azure database with a hierarchy of parents and i want to identify in the total hierarchy of the parents the parent id for each item that meets some conditions. As an example this could be a great example categoryId parentId Typeid 1 null 1 2 1 2 3 2 3 4 3 4 5 3 4 6 null 5 7 6 1 8 7 2 9 8 3 10 9 4 11 9 4 And I want to find for each categoryID the ParentId in the hierarchy that the type is 1 and if this category is the type 1 put the same category, in order to receive something like this. categoryId parentId Typeid ParentSearch 1 null 1 1 2 1 2 1 3 2 3 1 4 3 4 1 5 3 4 1 6 null 5 null 7 6 1 7 8 7 2 7 9 8 3 7 10 9 4 7 11 9 4 7 As you can see all the categories from 1 to 5 the parent with type 1 is the category 1 and for the categories from 6 to 11, the 6 need to be null and the rest the parent is 7. It could be possible? Maybe creating a path or something. i have done doing several left joins at leves and it is fine but i dont want to create 500leves in order to be sure that we never have 500 levels childs. Thanks and regards!
A recursive CTE is your friend: WITH parents AS (SELECT categoryid, parentid, typeid , CASE WHEN typeid = 1 THEN categoryid ELSE NULL END AS parentsearch FROM mytable WHERE parentid IS NULL UNION ALL SELECT c.categoryid, c.parentid, c.typeid , coalesce(p.parentsearch, CASE WHEN c.typeid = 1 THEN c.categoryid ELSE null END) FROM mytable AS c JOIN parents AS p ON c.parentid = p.categoryid) SELECT * FROM parents ORDER BY categoryid; categoryid parentid typeid parentsearch ---------- ---------- ---------- ------------ 1 (null) 1 1 2 1 2 1 3 2 3 1 4 3 4 1 5 3 4 1 6 (null) 5 (null) 7 6 1 7 8 7 2 7 9 8 3 7 10 9 4 7 11 9 4 7 Sql Server db<>fiddle example.
Another solution that uses a recursive CTE. But this one seeds from the childs. WITH RCTE AS ( SELECT t.categoryId, t.parentId, t.typeId, 0 as lvl, t.categoryId as nextCategoryId, t.parentId as nextParentId, t.typeId as nextTypeId FROM CategoryRelations t UNION ALL SELECT c.categoryId, c.parentId, c.typeId, c.lvl + 1, t.categoryId, t.parentId, t.typeId FROM RCTE c JOIN CategoryRelations t ON t.categoryId = c.nextParentId WHERE c.typeId != 1 ) SELECT c.categoryId, c.parentId, c.typeId, (case when c.nextTypeId = 1 then c.nextCategoryId end) as ParentSearch FROM RCTE c WHERE (c.nextTypeId = 1 or c.parentId is null) ORDER BY categoryId; A test on rextester here
SQL Recursive CTE unexpectedly returns alternating sets
I am trying to get the use recursive CTE to repeat the same pattern over and over, resetting when "Scenario" increases in value. RowNumber repeats 1-21 (as desired), but whenever "Scenario" is an even number, there are too few items in the "Vals" column to feed into "Value". I can't figure out which part of the code is causing me to be 1 short for only even Scenarios. Below are the results of the code I'm using at the bottom. Scenario RowNumber Value Vals 1 1 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 2 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 3 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 4 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 5 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 6 A A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 7 A A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 8 A A,A,A,A,A,A,A,A,A,A,A,B,C 1 9 A A,A,A,A,A,A,A,A,A,A,B,C 1 10 A A,A,A,A,A,A,A,A,A,B,C 1 11 A A,A,A,A,A,A,A,A,B,C 1 12 A A,A,A,A,A,A,A,B,C 1 13 A A,A,A,A,A,A,B,C 1 14 A A,A,A,A,A,B,C 1 15 A A,A,A,A,B,C 1 16 A A,A,A,B,C 1 17 A A,A,B,C 1 18 A A,B,C 1 19 A B,C 1 20 B C 1 21 C 2 1 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 2 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 3 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 4 A A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 5 A A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 6 A A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 7 A A,A,A,A,A,A,A,A,A,A,B,B,C 2 8 A A,A,A,A,A,A,A,A,A,B,B,C 2 9 A A,A,A,A,A,A,A,A,B,B,C 2 10 A A,A,A,A,A,A,A,B,B,C 2 11 A A,A,A,A,A,A,B,B,C 2 12 A A,A,A,A,A,B,B,C 2 13 A A,A,A,A,B,B,C 2 14 A A,A,A,B,B,C 2 15 A A,A,B,B,C 2 16 A A,B,B,C 2 17 A B,B,C 2 18 B B,C 2 19 B C 2 20 C 2 21 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 3 1 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 2 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 3 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 4 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 5 A A,A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 6 A A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 7 A A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 8 A A,A,A,A,A,A,A,A,A,A,B,C,C 3 9 A A,A,A,A,A,A,A,A,A,B,C,C 3 10 A A,A,A,A,A,A,A,A,B,C,C 3 11 A A,A,A,A,A,A,A,B,C,C 3 12 A A,A,A,A,A,A,B,C,C 3 13 A A,A,A,A,A,B,C,C 3 14 A A,A,A,A,B,C,C 3 15 A A,A,A,B,C,C 3 16 A A,A,B,C,C 3 17 A A,B,C,C 3 18 A B,C,C 3 19 B C,C 3 20 C C 3 21 C 4 1 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 2 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 3 A A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 4 A A,A,A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 5 A A,A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 6 A A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 7 A A,A,A,A,A,A,A,A,A,B,B,B,C 4 8 A A,A,A,A,A,A,A,A,B,B,B,C 4 9 A A,A,A,A,A,A,A,B,B,B,C 4 10 A A,A,A,A,A,A,B,B,B,C 4 11 A A,A,A,A,A,B,B,B,C 4 12 A A,A,A,A,B,B,B,C 4 13 A A,A,A,B,B,B,C 4 14 A A,A,B,B,B,C 4 15 A A,B,B,B,C 4 16 A B,B,B,C 4 17 B B,B,C 4 18 B B,C 4 19 B C 4 20 C This is the code I used to generate the above sample. Where am I going wrong? CREATE TABLE #temp3 ( Scenario INT ,Vals VARCHAR(64) ,LEN INT ) ; WITH vals AS ( SELECT v.* FROM (VALUES ('A'), ('B'), ('C')) v(x) ), CTE AS ( SELECT CAST('A' AS VARCHAR(MAX)) AS STR, 0 AS LEN UNION ALL SELECT (CTE.STR + ',' + vals.x), CTE.LEN + 1 FROM CTE JOIN vals ON vals.x >= RIGHT(CTE.STR, 1) WHERE CTE.LEN < 19 ) INSERT INTO #temp3 SELECT ROW_NUMBER() OVER(ORDER BY STR + ',C') AS Scenario ,STR + ',C' AS Vals ,LEN FROM CTE WHERE STR + 'C' LIKE '%B%' AND LEN = 19 ; -- Split strings created above into individual characters WITH cte(Scenario, Value, Vals) AS ( SELECT Scenario ,CAST(LEFT(Vals, CHARINDEX(',',Vals+',')-1) AS VARCHAR(10)) AS Value ,STUFF(Vals, 1, CHARINDEX(',',Vals+','), '') AS Vals FROM #temp3 UNION ALL SELECT Scenario ,CAST(LEFT(Vals, CHARINDEX(',',Vals+',')-1) AS VARCHAR(10)) ,STUFF(Vals, 1, CHARINDEX(',',Vals+','), '') FROM cte WHERE Vals > '' ) SELECT Scenario ,ROW_NUMBER() OVER (PARTITION BY Scenario ORDER BY Scenario) RowNumber ,Value ,Vals FROM cte t
I'm not exactly sure what the problem you are describing is, but the ROW_NUMBER() should use an ORDER BY clause that completely orders the rows in each partition. When you use "PARTITION BY Scenario ORDER BY Scenario" the order in which the ROW_NUMBER() values are assigned is undefined. Try something like WITH cte(Scenario, depth, Value, Vals) AS ( SELECT Scenario, 0 depth ,CAST(LEFT(Vals, CHARINDEX(',',Vals+',')-1) AS VARCHAR(10)) AS Value ,STUFF(Vals, 1, CHARINDEX(',',Vals+','), '') AS Vals FROM #temp3 UNION ALL SELECT Scenario, depth+1 ,CAST(LEFT(Vals, CHARINDEX(',',Vals+',')-1) AS VARCHAR(10)) ,STUFF(Vals, 1, CHARINDEX(',',Vals+','), '') FROM cte WHERE Vals > '' ) SELECT Scenario ,depth ,ROW_NUMBER() OVER (PARTITION BY Scenario ORDER BY depth ) RowNumber ,Value ,Vals FROM cte t
SQL recursive hierarchy
I am struggling to get one recursive CTE to work as desired but still with no chance.. So, I have the following similar table structures: tblMapping: map_id | type_id | name | parent_id 1 1 A1 0 2 1 A2 0 3 1 A3 1 4 1 A4 3 5 2 B1 0 6 2 B2 5 7 2 B3 6 8 1 A5 4 9 2 B4 0 tblRoleGroup: role_group_id | type_id | map_id | desc_id 1 1 0 null 1 2 0 null 2 1 3 1 2 2 6 0 3 1 8 1 3 2 9 1 In tblRoleGroup, the desc_id field means: null - allow all (used only in combination with map_id=0) 0 - allow all from parent including parent 1 - allow only current node Still in tblRoleGroup if map_id=0 then the query should get all elements from same type_id The query result should look like this: role_group_id | type_id | map_id | path 1 1 1 A1 1 1 2 A2 1 1 3 A1.A3 1 1 4 A1.A3.A4 1 1 8 A1.A3.A4.A5 1 2 5 B1 1 2 6 B1.B2 1 2 7 B1.B2.B3 1 2 9 B4 2 1 3 A1.A3 2 2 6 B1.B2 2 2 7 B1.B2.B3 3 1 8 A1.A3.A4.A5 3 2 9 B4 The query below solves only a part of the expected result, but I wasn't able to make it work as the expected result.. WITH Hierarchy(map_id, type_id, name, Path) AS ( SELECT t.map_id, t.type_id, t.name, CAST(t.name AS varchar(MAX)) AS Expr1 FROM dbo.tblMapping AS t LEFT JOIN dbo.tblMapping AS t1 ON t1.map_id = t.parent_id WHERE (t1.parent_id=0) UNION ALL SELECT t.map_id, t.type_id, t.name, CAST(h.Path + '.' + t.name AS varchar(MAX)) AS Expr1 FROM Hierarchy AS h JOIN dbo.tblMapping AS t ON t.parent_id = h.map_id ) SELECT h.map_id, h.type_id, t.role_group_id, h.Path AS Path FROM Hierarchy AS h LEFT JOIN dbo.tblRoleGroup t ON t.map_id = h.map_id Could someone help me on this? Thank you
At first I create a function that brings all descendants of passed map_id: CREATE FUNCTION mapping (#map_id int) RETURNS TABLE AS RETURN ( WITH rec AS ( SELECT map_id, [type_id], CAST(name as nvarchar(max)) as name, parent_id FROM tblMapping WHERE map_id = #map_id UNION ALL SELECT m.map_id, m.[type_id], r.name+'.'+m.name, m.parent_id FROM rec r INNER JOIN tblMapping m ON m.parent_id = r.map_id ) SELECT * FROM rec ); GO Then run this: ;WITH rec AS ( SELECT map_id, [type_id], CAST(name as nvarchar(max)) as name, parent_id FROM tblMapping WHERE parent_id=0 UNION ALL SELECT m.map_id, m.[type_id], r.name+'.'+m.name, m.parent_id FROM rec r INNER JOIN tblMapping m ON m.parent_id = r.map_id ) SELECT t.role_group_id, r.[type_id], r.map_id, r.name as [path] FROM tblRoleGroup t CROSS JOIN rec r WHERE r.[type_id] = CASE WHEN t.desc_id IS NULL AND t.map_id = 0 THEN t.[type_id] ELSE NULL END OR r.map_id = CASE WHEN t.desc_id = 1 THEN t.map_id ELSE NULL END OR r.map_id IN ( SELECT map_id FROM dbo.mapping (CASE WHEN t.desc_id = 0 THEN t.map_id ELSE NULL END) ) ORDER BY role_group_id, r.[type_id], r.map_id Will give you: role_group_id type_id map_id path 1 1 1 A1 1 1 2 A2 1 1 3 A1.A3 1 1 4 A1.A3.A4 1 1 8 A1.A3.A4.A5 1 2 5 B1 1 2 6 B1.B2 1 2 7 B1.B2.B3 1 2 9 B4 2 1 3 A1.A3 2 2 6 B1.B2 2 2 7 B1.B2.B3 3 1 8 A1.A3.A4.A5 3 2 9 B4
Sum Amount, display full resultset where Groups of Column Values Match in Same Table Oracle SQL
I need to get the sum of all TOTAL fields where the ID, RECNO and DRCR fields have the same value, while also displaying these fields in the result set. eg ID RECNO SECRECNO DRCR TOTAL 1 9 5 D 25 1 9 12 D 22 1 9 6 C 33 1 9 5 D 50 1 8 2 D 12 1 8 2 C 23 2 9 5 D 100 So the results of the query should be ID RECNO SECRECNO DRCR SUM(TOTAL) 1 9 5 D 75 1 9 12 D 22 1 9 6 C 33 1 8 2 D 12 1 8 2 C 23 2 9 5 D 100 This query will give the results set, without the TOTAL: select distinct t1.recno, t1.secrecno from table t1, table t2 where t1.recno = t2.recno and t.id = '1' and t1.drcr = 'D' But I can't see how to SUM the TOTAL of these results. How to do this?
select t1.id, t1.recno, t1.secrecno, t1.drcr, SUM( TOTAL ) from table t1 INNER JOIN table t2 ON ( t1.recno = t2.recno ) WHERE t1.id = '1' AND t1.drcr = 'D' GROUP BY t1.id, t1.recno, t1.secrecno, t1.drcr