2010-05-11 1 views
3

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

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] 
+2

I LOL'd во время чтения «мама папа о маме». :( –

+0

@Robin, это прекрасно, если вы LOL'd на всех других перестановках, которые будут беспокоиться. – Unreason

ответ

2

Я хотел бы предложить вам взглянуть на рекурсии с использованием CTE (Common Таблица Expression) ,

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

0

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

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

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

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

1
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

Спасибо, но у меня проблемы с кодом. Я не знаком с CTE. Все примеры, которые я вижу на веб-старт у корня (президент) и работа над деревом. Я хочу рекурсировать в другом направлении. Что вы устанавливаете как @first_animal, @second_animal и откуда берется «уровень»? – simon831

+0

@simon: CTE начинайте с '@ first_animal' и' @ second_animal' (те, которые вы хотите найти для общего предка) и поднимитесь по дереву, а не вниз. Каждый CTE возвращает всех предков и их уровень ('1' для родителей,' 2) для бабушек и дедушек и т. Д. Затем запрос просто присоединяется к предкам и возвращает ближайший (тот, который имеет наименьший уровень). – Quassnoi