2017-10-03 18 views
0

Patと 'Family'のすべての人物を返すクエリを作成しようとしています。私はSQL Serverのループに慣れていませんが、少し読んで、結果が見つからなくなってから次の行に移動するまでループを繰り返す必要がある複数の行があるときにループを構成する方法がわかりません。ここで私が作業しているデータセットがあります。各再帰レベルで複数行のSQL Server再帰クエリ

Acquaintanceテーブル:

AcquaintanceID Type 
------------------------------ 
1     Family 
2     Friend 
3     Colleague 

Peopleテーブル:

PersonID Name 
--------------------------- 
1   Pat 
2   Michael 
3   Sarah 
4   Barry 
5   David 
6   Chloe 
7   Margaret 
8   Jack 
9   Jennifer 
10   Daniel 
11   Mary 

Relationsテーブル:

RelationID Person1ID Person2ID AcquaintanceID 
--------------------------------------------------- 
1   1   3   1 
2   1   2   1 
3   1   4   2 
4   2   5   2 
5   2   8   3 
6   2   6   1 
7   3   6   3 
8   3   9   2 
9   3   4   3 
10   4   7   3 
11   4   10   3 
12   4   11   2 

私は最初の一歩を取得するために実行しているクエリがある

SELECT 
    Relations.Person1ID, P1.Name, Relations.Person2ID, P2.Name, 
    Relations.AcquaintanceID, Acquaintance.Type 
FROM 
    Relations 
INNER JOIN 
    People P1 ON Relations.Person1ID = P1.PersonID 
INNER JOIN 
    People P2 ON Relations.Person2ID = P2.PersonID 
INNER JOIN 
    Acquaintance ON Relations.AcquaintanceID = Acquaintance.AcquaintanceID 
WHERE 
    P1.Name = 'Pat' AND Acquaintance.Type = 'Family' 

これは私が持つ家族/親戚であるすべての人々のリストを取得しようとしています...私は、そのPERSONIDでなく、ために同じクエリを実行する必要があること

をPerson2IDからIDを返します。すべてが言われて終わったら、パット。

Name 
---------- 
Sarah 
Michael 
Chloe 

のように私は連合の使用とサブクエリと自分でこの問題を解決するために管理が、それでも、これは再帰で設定される方法に興味があります。クエリは以下のとおりです。

SELECT 
    P2.Name AS Name 
FROM 
    Relations 
INNER JOIN 
    People P1 ON Relations.Person1ID = P1.PersonID 
INNER JOIN 
    People P2 ON Relations.Person2ID = P2.PersonID 
INNER JOIN 
    Acquaintance ON Relations.AcquaintanceID = Acquaintance.AcquaintanceID 
WHERE 
    P1.Name = 'Pat' AND Acquaintance.Type = 'Family' 
UNION ALL 
SELECT 
    P2.Name 
FROM 
    Relations 
INNER JOIN 
    People P1 ON Relations.Person1ID = P1.PersonID 
INNER JOIN 
    People P2 ON Relations.Person2ID = P2.PersonID 
INNER JOIN 
    Acquaintance ON Relations.AcquaintanceID = Acquaintance.AcquaintanceID 
INNER JOIN (
    SELECT 
     Relations.Person2ID, P2.Name AS P2Name, Acquaintance.Type 
    FROM 
     Relations 
    INNER JOIN 
     People P1 ON Relations.Person1ID = P1.PersonID 
    INNER JOIN 
     People P2 ON Relations.Person2ID = P2.PersonID 
    INNER JOIN 
     Acquaintance ON Relations.AcquaintanceID = Acquaintance.AcquaintanceID 
    WHERE 
     P1.Name = 'Pat' AND Acquaintance.Type = 'Family' 
    ) A ON Relations.Person1ID = A.Person2ID 
WHERE Acquaintance.Type = 'Family' 

出力:再帰CTEを使用して、これを行うには多くの方法があります

Name 
---------- 
Sarah 
Michael 
Chloe 
+1

サンプルテーブルとクエリを提供してくれてうれしいです。希望の出力を持つテーブルが評価されます。 – Simon

+0

再帰的なCTEでこれを行うことができるはずです。ここにたくさんの例があります – SQLBadPanda

答えて

0

、ここで多くの一つである:

;with cte1 
as 
(select p.Name, r.Person2ID, r.AcquaintanceID 
from Relations r 
inner join People p on p.PersonID in (r.Person1ID, r.Person2ID) 
inner join Acquaintance a on a.AcquaintanceID = r.AcquaintanceID 
where r.Person1ID = 1 and r.AcquaintanceID = 1), 

cte2 
as 
(select r.Person2ID 
from Relations r 
inner join cte1 on cte1.AcquaintanceID = r.AcquaintanceID) 

select p.Name 
from cte2 
left join People p on p.PersonID = cte2.Person2ID 
group by p.Name 

私はあなたが一緒にプレイすることができますrextester例を作りましたhere

1

再帰CTEを使用できます。アンカーと再帰部分の2つの部分があります。

WITH cte (Lvl, Person1ID, Person1Name, Person2ID, Person2Name) 
AS (
    -- Anchor part: Start with 'Pat' 
    SELECT 0 AS Lvl, p.PersonID, p.Name, (SELECT PersonID FROM People WHERE Name = 'Pat'), CAST('' AS VARCHAR(50)) 
    FROM Relations r 
    JOIN People p ON p.PersonID = r.Person1ID 
    WHERE p.PersonID = (SELECT PersonID FROM People WHERE Name = 'Pat') 
    UNION ALL 
    -- Recursive part: 
    SELECT Lvl + 1, p.PersonID, p.Name, a.PersonID, CAST(a.Name AS VARCHAR(50)) 
    FROM Relations r 
    JOIN People p ON p.PersonID = r.Person1ID 
    JOIN People a ON a.PersonID = r.Person2ID 
    JOIN cte c ON c.Person2ID = r.Person1ID 
    WHERE r.AcquaintanceID = (SELECT AcquaintanceId FROM Acquaintance WHERE Type = 'Family') 
) 
SELECT DISTINCT * FROM cte 
+0

それはまさに私が意味していたものです:) – SQLBadPanda