2010-07-29 4 views
1

J'ai une table simple avec des personnes, mais il y a une sorcière champ
supplémentaire contient des informations (personne id) qui est un père/mère
de cette personne, de sorte que le 2 table de dimensions peut contenir un arbre famillialechoisir le nom d'une personne avec le plus petits-enfants

la table est

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 

la tâche est de sélectionner le nom de la personne qui a le plus grand nombre de petits-enfants

Tout ce que je réussis à faire est:

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 

et le résultat est

first_name last_name grandchilds 
Steven King 2 
Alexander Khoo 5 

s'il vous plaît aider :) ps: s'il est possible que je voudrais obtenir SGBDR réponse indépendante

+0

Vous oubliez les mères. (Lequel, puisque vous n'avez pas de parents seuls, ne vous préoccupe peut-être pas trop). – Tobiasopdenbrouw

+0

S'il s'agit de devoirs, veuillez le marquer comme tel. –

+0

Vous pouvez oublier les mères (mother_id) - ce sera plus facile et je peux le faire sans elle. – Marecky

Répondre

0

Je pense que je l'ai fait, s'il vous plaît jeter un oeil à ma solution et le commenter

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

edit: je l'ai fixé comme 'onedaywhen dit

+0

Ne fonctionne pas sur SQL Server (l'un des produits SQL les plus utilisés) mais peut être corrigé en attribuant à votre table dérivée un nom de corrélation, par ex. remplacer '))' par ') AS DT1)'. – onedaywhen

+3

... pour être honnête, si vous voulez une réponse indépendante du produit SQL, pourquoi n'écrivez-vous pas SQL avec la norme SQL-92: mots-clés majuscules ('SELECT' plutôt que' select'), en utilisant le Le mot-clé 'AS' pour les noms de corrélation (' empnew AS e1' plutôt que 'empnew e1' et' COUNT (e3.first_name) AS petitchilds' plutôt que 'count (e3.first_name) petitchilds'), les instructions de fin avec un point-virgule'; '. – onedaywhen

+0

être honset je ne savais pas ça! :) – Marecky

0

Ce qui suit est une solution ANSI, sauf pour la fonction strpos (qui est PostgreSQL spécifique). Mais il ne devrait pas être difficile de trouver la fonction correcte qui trouve une sous-chaîne dans une autre chaîne.

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) 

J'ai testé cela avec PostgreSQL, mais il faut aussi travailler sur Firebird, SQL Server, DB2, Oracle 11gR2 et Teradata. Tous n'acceptent pas le mot-clé obligatoire (selon la norme) recursive, vous devrez peut-être supprimer cela en fonction du SGBD cible. SQL Server enfreint la norme en n'utilisant pas || pour la concaténation de chaînes. Vous devez utiliser + à la place.

Modifier:

juste remarqué que cela comptera tous enfants non seulement les petits-enfants, il est donc pas à 100% ce que vous voulez.

Questions connexes