Цикл SQL над родословной - PullRequest
3 голосов
/ 11 мая 2010

Использование SQL Server 2008. У меня есть семейное древо животных, хранящееся в таблице, и я хочу дать некоторую информацию о том, насколько «генетически разнообразно» (или нет) потомство. В SQL, как я могу создать разумные метрики, чтобы показать, насколько тесно связаны родители? Может быть, какой-то процент общей крови или количество поколений, которые можно использовать, прежде чем появится общий предок?

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]

Ответы [ 3 ]

2 голосов
/ 11 мая 2010

Я бы посоветовал вам взглянуть на рекурсию, используя CTE (Common Table Expression).

Это позволит вам рекурсивно просматривать родителей, пока не будет найден общий предок, при этом сохраняя значение для этого.

1 голос
/ 11 мая 2010
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
0 голосов
/ 11 мая 2010

На это невозможно ответить в реалистической моде - игнорируйте часть SQL на мгновение, но вы даже не знаете, чего хотите. «возможно» - подумайте еще раз. Что если у вас есть несколько частичных предков? Что ты тогда делаешь?

Поиск всех предков данного потомства тривиален (временная таблица, рекурсивно заполняйте ее родителями, добавляя в качестве поля «вывоз»)

Тогда вы можете объединить две временные таблицы. Пока хорошо (и извините, так и должно быть, потому что ваш иерарх может вернуться на много поколений назад).

Но оттуда вам все равно придется найти действительно разумный алгоритм для того, что это должно означать - в нетривиальных сценариях;)

...