Brett Kaiser (x002548) Blog

Not Just a Number - Brett Kaiser

Because you're mine, I walk the line

....ummm, well, that "line" would be walking through a line in a family tree.  I saw a post the other the day that asked, if I know a relative somewhere in a families "lineage", how can I find the entire family tree from top to bottom.

Well here's a hack to do that...don't ask for effecienciey.  This for SQL Server 2000.  I have to determine if CTE's in 2k5 can come up with a better solution, but here it is for now.

CREATE TABLE Parent (
   ID_PK int IDENTITY(1,1)
 , [Name] varchar(20)
 , PhoneNum varchar(20)
 , Address varchar(30))

CREATE TABLE Child (
   ID_PK int
 , ParentID_FK int)
GO

INSERT INTO Parent([Name],PhoneNum, Address)
SELECT 'Annie',     '111-111-1111', '1st Street' UNION ALL
SELECT 'Bob',       '222-222-2222', '2nd Street' UNION ALL
SELECT 'Cathy',     '333-333-3333', '3rd Street' UNION ALL
SELECT 'Don',       '444-444-4444', '4th Street' UNION ALL
SELECT 'Emily',     '555-555-5555', '5th Street' UNION ALL
SELECT 'Frank',     '666-666-6666', '6th Street' UNION ALL
SELECT 'Georgette', '777-777-7777', '7th Street' UNION ALL
SELECT 'Harry',     '888-888-8888', '8th Street'

INSERT INTO Child(ID_PK, ParentID_FK)
SELECT 1, null UNION ALL
SELECT 2, 1    UNION ALL
SELECT 3, 2    UNION ALL
SELECT 4, 3    UNION ALL
SELECT 5, null UNION ALL
SELECT 6, 5    UNION ALL
SELECT 7, 6    UNION ALL
SELECT 8, 7
GO

SELECT * FROM Parent p LEFT JOIN Child c ON p.ID_PK = c.ID_PK
GO


CREATE FUNCTION udf_FindTree (@Child varchar(20))
RETURNS varchar(8000)
AS
BEGIN
DECLARE @p int, @p_save int, @rs varchar(8000)
SELECT @p = 0, @p_save = 0
SELECT @p = ParentID_FK FROM Child c JOIN Parent p ON c.ParentID_FK = p.ID_PK
 WHERE [Name] = @Child
--Loop Until @@rowcount = 0
WHILE Exists (SELECT ParentID_FK FROM Child c WHERE ID_PK = @p)
  BEGIN
 SELECT @p_save = @p
 SELECT @p = ParentID_FK FROM Child c WHERE ID_PK = @p_save
-- The Last assignement is the top Parent
  END
--Now Walk from the top Down until @@rowcount = 0
SELECT @p = @p_save
SELECT @rs = [Name] + ' ' + PhoneNum + ' ' + Address FROM Parent WHERE ID_PK = @p
WHILE EXISTS (SELECT ID_PK FROM Child WHERE ParentID_FK = @p)
  BEGIN
 SELECT @rs = @rs + ' ' + COALESCE([Name],'') FROM Parent WHERE ID_PK = @p
 SELECT @p = ID_PK FROM Child WHERE ParentID_FK = @p
  END
RETURN @rs
END
GO

SELECT dbo.udf_FindTree('Cathy')
GO

SELECT * FROM Child c JOIN Parent p ON c.ParentID_FK = p.ID_PK
 WHERE [Name] = 'Cathy'
GO

CREATE PROC usp_FindTree @Child varchar(20)
AS
SET NOCOUNT ON
DECLARE @p int, @p_save int, @rs varchar(8000)
SELECT @p = 0, @p_save = 0
SELECT @p = ParentID_FK FROM Child c JOIN Parent p ON c.ParentID_FK = p.ID_PK
 WHERE [Name] = @Child
--Loop Until @@rowcount = 0
WHILE Exists (SELECT ParentID_FK FROM Child c WHERE ID_PK = @p)
  BEGIN
 SELECT @p_save = @p
 SELECT @p = ParentID_FK FROM Child c WHERE ID_PK = @p_save
-- The Last assignement is the top Parent
  END
--Now Walk from the top Down until @@rowcount = 0
SELECT @p = @p_save
SELECT @rs = [Name] + ' ' + PhoneNum + ' ' + Address FROM Parent WHERE ID_PK = @p
WHILE EXISTS (SELECT ID_PK FROM Child WHERE ParentID_FK = @p)
  BEGIN
 SELECT @rs = @rs + ' ' + COALESCE([Name],'') FROM Parent WHERE ID_PK = @p
 SELECT @p = ID_PK FROM Child WHERE ParentID_FK = @p
  END
SELECT @rs AS rs
SET NOCOUNT OFF
GO

EXEC usp_FindTree 'Cathy'
GO

DROP PROC usp_FindTree
DROP Function udf_FindTree
DROP TABLE Parent, Child
GO

Legacy Comments


Siva G
2007-07-27
re: Because you're mine, I walk the line
This is how you do it.

CREATE PROC usp_CTEFindTree @Child varchar(20)
AS
SET NOCOUNT ON;
WITH FamTree ( ID_PK, ParentID_FK, LVL)
AS
(
SELECT ID_PK, ParentID_FK, 1 Lvl
FROM child
WHERE ID_PK IN ( SELECT ID_PK FROM Parent
WHERE [Name] = @Child)
UNION ALL
SELECT Child.ID_PK, Child.ParentID_FK, 1 + Lvl Lvl
FROM child JOIN FamTree
ON Famtree.ParentID_FK = child.ID_PK
)
SELECT Parent.*
FROM Parent JOIN FamTree
ON Parent.ID_PK = FamTree.ID_PK
ORDER BY Lvl DESC
GO

EXEC usp_CTEFindTree 'Cathy'
go

Erick Ligeyi Litswa
2007-07-30
re: Because you're mine, I walk the line
The script from Siva G produces the error message:
"Incorrect syntax near the keyword 'WITH'."

angelia
2007-07-30
re: Because you're mine, I walk the line
2005's recursive common table expression - maybe you get an error if compatibility < 90 - otherwise, it works.

Valter Borges
2007-08-12
re: Because you're mine, I walk the line
Look up Joe Celko SQL Trees