Reputation: 31
I need a query that will return the ancestry of a table given the information below. The source table is currently structured as described, and a recursive CTE doesn't work. I can't seem to wrap my mind around how the source table should be structured to make a CTE work.
Can someone please suggest a source table structure and query that will return the following? If there's a better way than recursion, that works too.
The source table contains information from my SQL Server database that reflects data lineage. In order to produce table T4, you'd execute procedures P1, P2, and P3.
There is a rule that a table can have only one 'parent' procedure, but a procedure can build multiple tables. So P3 can build T3 and T4, but T3 can only be built by one procedure (P3).
EXAMPLE:
If the query is fed 'T4', it should return this information:
referencing_ancestor referenced_ancestors
P3 T2, LOOKUP_TABLE
P2 T1
P1 staging
This is the source information in its current structure, but the structure can change. I just need the ancestry information of a given table.
declare @Dependencies table
(
id int identity(1,1),
referencing_name nvarchar(50) NOT NULL,
referenced_name nvarchar(50) NULL,
select_from int NULL,
insert_to int NULL
)
insert into @Dependencies
select 'P1', 'staging', 1, 0 --> P1 selects data from staging
union all
select 'P1', 'T1', 0, 1 --> P1 populates T1
union all
select 'P2', 'T1', 1, 0 --> P2 selects data from T1
union all
select 'P2', 'T2', 0, 1 --> P2 populates T2
union all
select 'P3', 'LOOKUP_TABLE', 1, 0 --> P3 selects data from LOOKUP_TABLE
union all
select 'P3', 'T2', 1, 0 --> P3 selects data from T2
union all
select 'P3', 'T3', 0, 1 --> P3 populates T3
union all
select 'P3', 'T4', 0, 1 --> P3 populates T4
This query doesn't work, not sure how to fix:
;with ancestors as
(
select referencing_name, referenced_name, Level = 0
from @Dependencies
where referenced_name = 'T4'
union all
select d.referencing_name, d.referenced_name, Level + 1
from @Dependencies d
inner join ancestors a on a.referenced_name = d.referenced_name
where insert_to = 0
)
select * from ancestors
Upvotes: 3
Views: 54
Reputation: 678
I think you might want to establish some sort of "level" column in the @Dependencies table itself, but in this example I simply ordered by the referencing_name in the DENSE_RANK function.
;WITH ancestors AS (
SELECT *, DENSE_RANK() OVER (ORDER BY referencing_name) AS tbl_level
FROM @Dependencies
)
SELECT a2.*
FROM ancestors a1
JOIN ancestors a2 ON a2.tbl_level <= a1.tbl_level
WHERE a1.referenced_name = 'T4'
AND a2.insert_to = 0
ORDER BY tbl_level DESC
Upvotes: 1