Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive CTE to find parent records

first i must admit that i'm not very familiar with sql server's recursive CTE's but i think this is the best approach.

I have a table tabData. Its PK is named idData and there is a self referencing FK fiData.

Schema

So fiData references the parent record and SELECT * FROM tabData WHERE idData=fiData returns all data of the parent. This is simple and fast. But how to get all parents from a given record in the natural order? Say there is one child(idData=4) with 3 parents (first parent is the record with idData=3):

idData    fiData 
 4          3     
 3          2     
 2          1    
 1          NULL    

I thought recursive CTE is the way to go, but i don't get along well with its syntax. So what is the correct way to implement the CTE which returns all parents?

I tried following, but it gives me the wrong result(3,4 instead of 3,2,1): (To test it i created a temporary table for me and you)

IF (NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'dbo' AND  TABLE_NAME = 'tabData_Temp'))
BEGIN
 CREATE TABLE [dbo].[tabData_Temp](
  [idData] [int] NOT NULL,
  [fiData] [int] NULL,
   CONSTRAINT [PK_tabData_Temp] PRIMARY KEY CLUSTERED 
  (
   [idData] ASC
  )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON)
 );

 ALTER TABLE [dbo].[tabData_Temp]  WITH CHECK ADD  CONSTRAINT [FK_tabData_Temp] FOREIGN KEY([fiData])
 REFERENCES [dbo].[tabData_Temp] ([idData]);
 ALTER TABLE [dbo].[tabData_Temp] CHECK CONSTRAINT [FK_tabData_Temp];

 INSERT INTO [dbo].[tabData_Temp](idData,fiData)VALUES(1,NULL);
 INSERT INTO [dbo].[tabData_Temp](idData,fiData)VALUES(2,1);
 INSERT INTO [dbo].[tabData_Temp](idData,fiData)VALUES(3,2);
 INSERT INTO [dbo].[tabData_Temp](idData,fiData)VALUES(4,3);
END

/* here comes the (not working) recursive CTE */
Declare @fiData int;
SET @fiData = 3;
WITH PreviousClaims(idData,fiData) 
AS(
     SELECT parent.idData,parent.fiData
     FROM tabData_temp parent
     WHERE parent.idData = @fiData

     UNION ALL

     SELECT child.idData,child.fiData
     FROM tabData_temp child
     INNER JOIN PreviousClaims parent ON parent.idData = child.fiData
)
SELECT idData
FROM PreviousClaims;
/* end of recursive CTE */


DROP TABLE [dbo].[tabData_Temp];

Thank you in advance.

like image 687
Tim Schmelter Avatar asked Oct 14 '10 15:10

Tim Schmelter


People also ask

How do you do recursive CTE?

Recursive CTE Syntax Again, at the beginning of your CTE is the WITH clause. However, if you want your CTE to be recursive, then after WITH you write the RECURSIVE keyword. Then it's business as usual: AS is followed by the parentheses with the CTE query definition.

How do I select parent/child records in SQL?

In other words, we know which node is a parent node to which child node and vice versa. Here, the column id shows the child's ID. To find out who that child's parent is, you have to look at the column parent_id , find the same ID number in the id column, and look in that row for the parent's name.

What does CTE do in SQL?

The common table expression (CTE) is a powerful construct in SQL that helps simplify a query. CTEs work as virtual tables (with records and columns), created during the execution of a query, used by the query, and eliminated after query execution.

How do you recursive data in SQL?

Recursion is achieved by WITH statement, in SQL jargon called Common Table Expression (CTE). It allows to name the result and reference it within other queries sometime later. Naming the result and referencing it within other queries.


2 Answers

Changing to:

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

Gave me the results you wanted.

like image 150
Kirk Woll Avatar answered Oct 09 '22 16:10

Kirk Woll


You have the join backward.

Change this

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

to this

INNER JOIN PreviousClaims parent ON parent.fiData = child.idData
like image 20
Gabriel McAdams Avatar answered Oct 09 '22 16:10

Gabriel McAdams