выберите имя человека с самыми внуками - PullRequest
1 голос
/ 29 июля 2010

У меня есть простой стол с персонами, но есть дополнительный
Полевая ведьма хранит информацию (личность), кто отец / мать
этого человека, так что двумерный стол может содержать фамильное дерево

таблица

id first_name  last_name salary spouse_id father_id mother_id sex
100 Steven King 26400 101 (null) (null) m  
101 Neena Kochhar 18700 100 (null) (null) f  
102 Lex De Haan 18700 106 100 101 m  
103 Alexander Hunold 9900 (null) 100 101 m  
104 Bruce Ernst 6600 (null) 102 106 m  
105 David Austin 5280 (null) 102 106 m  
106 Valli Pataballa 5280 102 (null) (null) f  
107 Diana Lorentz 4620 (null) (null) (null) f  
108 Nancy Greenberg 13200 109 (null) (null) f  
109 Daniel Faviet 9900 108 115 116 m  
110 John Chen 9020 (null) 109 108 m  
111 Ismael Sciarra 8470 (null) 109 108 m  
112 Jose Manuel Urman 8580 (null) 109 108 m  
113 Luis Popp 7590 (null) 109 108 m  
114 Den Raphaely 12100 (null) 109 108 m  
115 Alexander Khoo 3410 116 (null) (null) m  
116 Shelli Baida 3190 115 (null) (null) f  

Задача - выбрать имя человека, у которого наибольшее количество внуков

Все, что мне удалось сделать, это:

select 
e1.first_name, e1.last_name
--,max (e3.first_name)
,count(e3.first_name) grandchilds
from empnew e1
inner join
empnew e2
on (e1.id = e2.father_id)
inner join
empnew e3
on (e2.id = e3.father_id)
group by e1.first_name, e1.last_name

и результат

first_name last_name grandchilds
Steven King 2
Alexander Khoo 5

пожалуйста, помогите :) PS: Я хотел бы получить RDBMS независимый ответ, если это возможно

Ответы [ 2 ]

0 голосов
/ 03 декабря 2011

Ниже приведено решение ANSI, за исключением функции strpos (которая специфична для PostgreSQL).Но не должно быть трудно найти правильную функцию, которая находит подстроку в другой строке.

with recursive person_tree as (
   select id, first_name, last_name, cast(id as varchar)||'/' as id_path, id as root_id
   from persons
   where father_id is null

   union all

   select c.id, c.first_name, c.last_name, id_path || cast(c.id as varchar)||'/', null
   from persons c 
     join person_tree p on c.father_id = p.id
),
group_flags as (
  select id_path, 
         id,
         first_name,
         last_name,
         substring(id_path, 0, strpos(id_path, '/')) as root_id
  from person_tree
)
select root_id, count(*) 
from group_flags
group by root_id
having count(*) = (select max(children_count)
                   from (select root_id,
                                count(*) as children_count
                         from group_flags
                         group by root_id
                   ) t) 

Я проверил это с PostgreSQL, но он также должен работать на Firebird, SQL Server, DB2, Oracle 11gR2и терадата.Не все из них принимают (согласно стандарту) обязательное ключевое слово recursive, поэтому вам может потребоваться удалить его в зависимости от целевой СУБД.

SQL Server нарушает стандарт, не используя || для строкиконкатенации.Вместо этого вы должны использовать +.

Редактировать :

Только что заметил, что он будет учитывать всех детей не только внуков, так что это не так100% что вы хотите.

0 голосов
/ 29 июля 2010

Я думаю, что сделал это, пожалуйста, посмотрите на мое решение и прокомментируйте его

SELECT 
e1.first_name
, e1.last_name
, count(e3.first_name) AS grandchilds
FROM empnew e1
INNER JOIN
empnew e2
ON (e1.id = e2.father_id)
INNER JOIN
empnew e3
ON (e2.id = e3.father_id)
GROUP BY e1.first_name, e1.last_name
HAVING COUNT(e3.first_name)
=
(SELECT MAX (grandchilds) FROM
(
SELECT 
e1.first_name
, COUNT(e3.first_name) AS grandchilds
FROM empnew e1
INNER JOIN
empnew e2
ON (e1.id = e2.father_id)
INNER JOIN
empnew e3
ON (e2.id = e3.father_id)
GROUP BY e1.first_name
) table_1);

редактировать: я исправил это как 'onedaywhen' сказал

...