tags:

views:

121

answers:

3

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]
A: 

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 ;)

TomTom
A: 

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.

Robin Day
+1  A: 
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
Quassnoi
Thanks, but I am having trouble with the code. I am not familiar with CTEs. All the examples I see on the web start at a root (a president) and work down the tree. I want to recurse in the other direction. What are you setting as @first_animal, @second_animaland where does 'level' come from?
simon831
@simon: the CTEs start from the `@first_animal` and `@second_animal` (the ones which you want to find the common ancestor for) and go up the tree, not down. Each CTE returns all ancestors and their level (`1` for parents, `2` for grandparents etc). The query then just joins the ancestors and returns the closest one (the one with the least level).
Quassnoi