SQL Loop over a family tree
-
25-09-2019 - |
Question
Using SQL server 2008. I have a family tree of animals stored in a table, and want to give some information on how 'genetically diverse' (or not) the offspring is. In SQL how can I produce sensible metrics to show how closely related the parents are? Perhaps some sort of percentage of shared blood, or a number of generations to go back before there is a shared ancestor?
AnimalTable
Id
Name
mumId
dadId
select * from AnimalTable child
inner join AnimalTable mum on child.[mumId] = mum.[Id]
inner join AnimalTable dad on child.[dadId] = dad.[Id]
inner join AnimalTable mums_mum on mum.[mumId] = mums_mum.[Id]
inner join AnimalTable mums_dad on mum.[dadId] = mums_dad.[Id]
inner join AnimalTable dads_mum on dad.[mumId] = dads_mum.[Id]
inner join AnimalTable dads_dad on dad.[dadId] = dads_dad.[Id]
Solution
I would suggest you look at recursion using a CTE (Common Table Expression).
This will allow you to recursively look through the parents until a common ancestor is found whilst maintaining a value for this.
OTHER TIPS
WITH hier1(parent, level) AS
(
SELECT mum, 1
FROM AnimalTable a
WHERE a.id = @first_animal
UNION ALL
SELECT dad, 1
FROM AnimalTable a
WHERE a.id = @first_animal
UNION ALL
SELECT mum, level + 1
FROM q
JOIN AnimalTable a
ON a.id = q.parent
UNION ALL
SELECT dad, level + 1
FROM q
JOIN AnimalTable a
ON a.id = q.parent
),
hier2(parent, level) AS
(
SELECT mum, level
FROM AnimalTable a
WHERE a.id = @second_animal
UNION ALL
SELECT dad, level
FROM AnimalTable a
WHERE a.id = @second_animal
UNION ALL
SELECT mum, level + 1
FROM q
JOIN AnimalTable a
ON a.id = q.parent
UNION ALL
SELECT dad, level + 1
FROM q
JOIN AnimalTable a
ON a.id = q.parent
)
SELECT TOP 1
h1.parent,
CASE WHEN h1.level < h2.level THEN h1.level ELSE h2.level END AS minlevel
FROM hier1 h1
JOIN hier2 h2
ON h1.parent = h2.parent
ORDER BY
2
That can not be answered in a realistic fasion - ignore the SQL part for a moment, but you dont even know what you want. "perhaps" - well, think it through again. What if you have multiple partial ancestors? What do you do then?
Finding all ancestors of a given offspring is trivial (temp table, fill with it's of parents recursively, adding "generation away" as field).
Then you can join the two temporary tables. Nice so far (and sorry, that basically has to be, because your hierarchiy can go many generations back).
But from there you STILL have to find actually a sensible algorithm on what that is supposed to mean - in non-trivial scenarios ;)