Suppose I have a hierarchical structure like this.
Father ID | Child ID |
---|---|
1 | 2 |
1 | 3 |
1 | 7 |
3 | 4 |
3 | 5 |
3 | 6 |
In my case, those are production orders, that demand from (father) or supply to (child) each other. I need to bring those orders to a structure like this:
Master Father | Hierarchy | Child |
---|---|---|
1 | 001.001 | 2 |
1 | 001.002 | 3 |
1 | 001.002.001 | 4 |
1 | 001.002.002 | 5 |
1 | 001.002.003 | 6 |
1 | 001.003 | 7 |
Afterwards I have to join the components to the child orders, that were used to create the master father. The target is, to trace the origin of the components, that were used to create a certain product.
The big problem is, that I can't predict, how deep those tree structures will become in the future. But I want to create a report, that won't break, when they get deeper.
So far I counted the depth manually. If the Master Father is 0 then I have 2 Levels in my example case. The (pseudo) code for the transformation would look like this:
Select
L.Father_ID as Level0
, '001' as Hierarchy0
, L.Child_ID as Level1
, Dense_Rank() over (partition by L.Father_ID) as Hierarchy1
, R1.Child_ID as Level2
, Dense_Rank() over (partition by L.Father_ID, L.Child_ID) as Hierarchy2
Into #exploded_table
From Table as L
Left Join Table as R1
on L.Child_ID = R1.Father_ID
Select distinct
Level0 as Master_Father
, Concat(Hierarchy0,'.',format(Hirarchy1, '000')) as Hierarchy
, Level1 as Child
From #exploded_table
Union all
Select distinct
Level0 as Master_Father
, Concat(Hierarchy0,'.',format(Hirarchy1, '000'),'.',format(Hirarchy2, '000')) as Hierarchy
, Level2 as Child
From #exploded_table
I have two problems with this code.
- It gets longer with every level
- It will break if more levels will be added in the future
Therefore I started to write dynamic code. It first counts the depth of the deepest tree and then it dynamically creates the code with as much levels as are needed.
When you execute this code the amount of columns is (as far as I understand it) called "Non-Deterministic". And MS SQL hates "Non-Deterministic" things. To be allowed to store this as a temp table I have to create a temp table outside of the scope of the EXEC sp_executesql
function. And then I have to dynamically modify the columns of this table to fit exactly to the result of the dynamic SQL statement that I pass to the Exec function. I won't use global temp tables since this will lead to chaos when multiple reports have the same names for their temp tables.
The above described method is complicated and unreadable! I can do it, but it feels like the opposite of good practice.
So I want to ask the community whether this can't be done in a simpler way. I came from a company that used PySpark where this was easily doable and now I am here and all I have is SQL Server and the SQL Server Reporting Services.