Using this sample table:
drop table Population
CREATE TABLE [dbo].[Population](
[PersonId] [int] NOT NULL,
[Name] [varchar](50) NOT NULL,
[MotherId] [int] NULL,
[FatherId] [int] NULL
) ON [PRIMARY]
insert Population (PersonId, [Name], MotherId, FatherId) values (1, 'Baby', 2, 3)
insert Population (PersonId, [Name], MotherId, FatherId) values (2, 'Mother', 4, 5)
insert Population (PersonId, [Name], MotherId, FatherId) values (3, 'Father', 6, 7)
insert Population (PersonId, [Name], MotherId, FatherId) values (4, 'Mothers Mother', 8, 9)
insert Population (PersonId, [Name], MotherId, FatherId) values (5, 'Mothers Father', 99, 99)
insert Population (PersonId, [Name], MotherId, FatherId) values (6, 'Fathers Mother', 99, 99)
insert Population (PersonId, [Name], MotherId, FatherId) values (7, 'Father Father', 99, 99)
insert Population (PersonId, [Name], MotherId, FatherId) values (8, 'Mothers GrandMother', 99, 99)
insert Population (PersonId, [Name], MotherId, FatherId) values (9, 'Mothers GrandFather', 99, 99)
I can return all the correct people I needed for a family tree using this SQL
;WITH FamilyTree
AS
(
SELECT *, CAST(NULL AS VARCHAR(50)) AS childName, 0 AS Generation
FROM Population
WHERE [PersonId] = '1'
UNION ALL
SELECT Fam.*, FamilyTree.[Name] AS childName, Generation + 1
FROM Population AS Fam
INNER JOIN FamilyTree
ON Fam.[PersonId] = FamilyTree.[motherId]
UNION ALL
SELECT Fam.*, FamilyTree.[Name] AS childName, Generation + 1
FROM Population AS Fam
INNER JOIN FamilyTree
ON Fam.[PersonId] = FamilyTree.[fatherId]
)
SELECT childName, space(generation*2)+name, generation FROM FamilyTree
It gives me:
-baby
--mother
--father
---fathers mother
---fathers father
---mothers mother
---mothers father
But how can I (just using sql) put the tree in the correct order - so that I get:
-baby
--mother
---mothers mother
---mothers father
--开发者_如何学Gofather
---fathers mother
---fathers father
NB: This answer was written after an extremely superficial glance at the Hierarchies chapter in the book "Inside Microsoft SQL Server T-SQL Querying" Hopefully I didn't miss any vital caveats!
;WITH FamilyTree
AS
(
SELECT *, CAST(NULL AS VARCHAR(50)) AS childName, 0 AS Generation, '.' + CAST([PersonId] AS VARCHAR(max)) + '.' as Path
FROM Population
WHERE [PersonId] = '1'
UNION ALL
SELECT Fam.*, FamilyTree.[Name] AS childName, Generation + 1, Path + '0.' + CAST(Fam.[PersonId] AS VARCHAR(max)) + '.' as Path
FROM Population AS Fam
INNER JOIN FamilyTree
ON Fam.[PersonId] = FamilyTree.[MotherId]
UNION ALL
SELECT Fam.*, FamilyTree.[Name] AS childName, Generation + 1, Path + '1.' + CAST(Fam.[PersonId] AS VARCHAR(max)) + '.' as Path
FROM Population AS Fam
INNER JOIN FamilyTree
ON Fam.[PersonId] = FamilyTree.[FatherId]
)
SELECT childName, space(Generation*2)+Name, Generation, Path
FROM FamilyTree
ORDER BY Path
;WITH FamilyTree
AS
(
SELECT *, CAST(NULL AS VARCHAR(50)) AS childName, 0 AS Generation, CAST(RIGHT('0000000000' + CAST(PersonId as varchar(10)),10) as varchar(max)) as Descendents
FROM Population
WHERE [PersonId] = '1'
UNION ALL
SELECT Fam.*, FamilyTree.[Name] AS childName, Generation + 1,FamilyTree.Descendents + '|' + RIGHT('0000000000' + CAST(Fam.PersonId as varchar(10)),10)
FROM Population AS Fam
INNER JOIN FamilyTree
ON Fam.[PersonId] = FamilyTree.[motherId]
UNION ALL
SELECT Fam.*, FamilyTree.[Name] AS childName, Generation + 1,FamilyTree.Descendents + '|' + RIGHT('0000000000' + CAST(Fam.PersonId as varchar(10)),10)
FROM Population AS Fam
INNER JOIN FamilyTree
ON Fam.[PersonId] = FamilyTree.[fatherId]
)
SELECT childName, space(generation*2)+name, generation FROM FamilyTree order by Descendents
Basically, you build up a big sort key, ensuring all Ids at the same level differ at the same position within the string.
精彩评论