Ниже приведено решение 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% что вы хотите.