2017-01-05 5 views
0

私はSQLを使用して、家系図の情報を格納しています。 生まれの人物の名前を入力して、に生まれたすべての子孫の名前を生年月日Zで出力しますが、の場合は、これらの子孫が兄弟姉妹の場合にのみ )。私は似たような解決策を見つけましたが、これらの解決策が(エイリアシングのために)階層構造では機能しないことが判明しました。また、世代Yで生まれた親とその子供がいるかもしれないので、階層の深さは名前を決定するために信頼できません。階層構造のGROUP BY列と異なるSELECT列

+----+----------+-----------+------------+--------+ 
| ID | Name  | Parent_ID | Generation | Gender | 
+----+----------+-----------+------------+--------+ 
| 1 | John  | NULL  | X   | Male | 
| 2 | Jill  | 1   | Y   | Female | 
| 3 | Andy  | 2   | Z   | Male | 
| 4 | Ralph | 2   | Z   | Male | 
| 5 | Lisa  | NULL  | X   | Female | 
| 6 | Steve | 5   | Y   | Male | 
| 7 | Sean  | 6   | Y   | Male | 
| 8 | Sarah | 6   | Y   | Female | 
| 9 | Emily | 7   | Z   | Female | 
| 10 | Matt  | 7   | Z   | Male | 
+----+----------+-----------+------------+--------+ 

所望の出力:(SET @GenX = 'Lisa';場合)

+-------+ 
| Name | 
+-------+ 
| Emily | 
| Matt | 
+-------+ 

これは、これまでの私のコードです。

SET @GenX = 'Lisa'; 

SELECT t2.name AS Kids 
FROM (SELECT name, Parent_ID 
    FROM FamilyTree 
    WHERE Gender = 'Male' OR Gender = 'Female') t1 
LEFT JOIN FamilyTree t2 ON t2.ID = t1.Parent_ID 
LEFT JOIN FamilyTree t3 ON t3.ID = t2.Parent_ID 
LEFT JOIN FamilyTree t4 ON t4.ID = t3.Parent_ID 
WHERE t3.name = '@GenX' OR t4.name - '@GenX' 
GROUP BY t2.name 
HAVING SUM(t1.Gender) > 0 AND SUM(t1.Gender) > 0; 

これは正しい親の名前を返しますが、子供の名前は返しません。もし私がSELECTGROUP BY子供の名前、私は子供が姉/兄弟を持っている見つけることができません。助けてくれてありがとう。私は本当にこれに固執しています。

名前が重複していたり​​、重複していると思われることはありません。

+0

唯一の世代は3つ以上ですか?テーブルや特定の世代に存在する世代の名前が必要ですか? –

+0

世代が増えているかもしれません。だから、世代Zは重要な停止地点ですが、世代Xよりもずっと大きな木が存在する可能性があります。世代間に生まれた家族系列の人数は可変です(親と子は両方とも生まれるかもしれません – blobberman

答えて

0
;with cte 
as 
(
Select id,name,Parent_id,generation,gender from family_tree where name [email protected] and generation='x' 
Union All 
Select t.id, t.name,t.Parent_id,t.generation,t.gender from family_tree t   
join cte c on c. id=t.parent_id 
) 
,condition 
as 
(
select Parent_id,COUNT(*) cnt from cte Where generation='z' Group by parent_id having COUNT(*)>1 
) 
,sibling 
as 
(
select parent_id,Count(gender) cntg from 
     (select distinct c.parent_id,c.gender from cte c join condition co on co.parent_id=c.parent_id) a 
       group by parent_id having count(gender)>1 

)   
select c.name from cte c join sibling s on c.parent_id=s.parent_id 
+0

FWIW、MySQLはまだ開発中のMySQL 8までCTE構文をサポートしていません。 –

+0

ユーザはmysqlについて言及していません。 – anjali

+0

質問はtagged [tag:mysql]です。タグは伝統的にOPが使用している技術のブランドを伝える手段です。 –

0

そのより多くのあなたが持っているが、より多くの内側のクエリを追加した場合のみ3世代 彼らのであれば、あなたは次のクエリの結果が得られます問い合わせの上

SELECT NAME FROM FamilyTree WHERE PARENT_ID IN 
    (SELECT ID FROM FamilyTree WHERE PARENT_ID IN 
     (SELECT ID FROM FamilyTree WHERE PARENT_ID = 
      (SELECT ID FROM FamilyTree WHERE NAME = 'Lisa') 
     ) 
    ) AND 
    (SELECT COUNT(ID) FROM 
     (SELECT ID FROM FamilyTree WHERE PARENT_ID IN 
      (SELECT ID FROM FamilyTree WHERE PARENT_ID IN 
       (SELECT ID FROM FamilyTree WHERE PARENT_ID = 
        (SELECT ID FROM FamilyTree WHERE NAME = 'Lisa') 
       ) 
      ) 
     )T2 
    )=2 AND GENARATION = 'Z' 

で行くことができる唯一の3世代を持っていると仮定すると、パフォーマンスに影響します。

+0

入れ子になった 'SELECT'ステートメントで' IN'演算子を使うと私に解決策が与えられました。私は 'IN'演算子が前にサブクエリーで使用できることを認識しませんでした。ありがとう。 – blobberman

0

私の元の試みは、兄弟/姉妹ジェネレーションZ子供の各親のID(名前)を返しました。 IN演算子を使用して子の名前を、最初にネストされたSELECTステートメントの親IDに関連付ける必要がある。

SET @GenX = 'Lisa'; 

SELECT name FROM FamilyTree WHERE Parent_ID IN 
    (SELECT t2.id AS Kids 
    FROM 
     (SELECT name, Parent_ID 
     FROM FamilyTree 
     WHERE Gender = 'Male' OR Gender = 'Female') t1 
    -- Iterate through hierarchy   
    LEFT JOIN FamilyTree t2 ON t2.ID = t1.Parent_ID 
    LEFT JOIN FamilyTree t3 ON t3.ID = t2.Parent_ID 
    LEFT JOIN FamilyTree t4 ON t4.ID = t3.Parent_ID 
    WHERE t3.name = '@GenX' OR t4.name - '@GenX' 
    GROUP BY t2.id 
    HAVING SUM(t1.Gender) > 0 AND SUM(t1.Gender) > 0); -- includes only brother/sister siblings