2017-10-03 2 views
0

Ich versuche, eine Abfrage zu schreiben, um alle Personen zurückzugeben, die 'Familie' mit Pat sind. Ich bin nicht sehr vertraut mit Schleifen in SQL Server, habe aber etwas darüber gelesen und bin mir nicht sicher, wie ich die Schleife strukturieren soll, wenn ich mehrere Zeilen habe, die ich rekursiv durchlaufen muss, bis keine Ergebnisse gefunden werden, dann zur nächsten Zeile wechseln. Hier ist der Datensatz, mit dem ich arbeite.SQL Server Rekursive Abfrage für mehrere Zeilen auf jeder Rekursionsebene

Acquaintance Tabelle:

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

People Tabelle:

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 Tabelle:

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 

Die Abfrage ich den ersten Schritt zu bekommen leite ist

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' 

Damit werden die IDs von Person2ID zurückgibt, die ich brauche, um dann die gleiche Abfrage laufen, aber für diesen PersonID ...

Ich versuche, eine Liste aller Personen zu erhalten, die mit Familie/Großfamilie sind Pat, wenn alles gesagt und getan ist.

Wie

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

Ich schaffte es gerade dies mit der Verwendung einer Union auf eigene Faust zu lösen und ein SubQuery aber bin immer noch neugierig, wie dies würde mit Rekursion eingerichtet werden. Die Abfrage ist unten.

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' 

Ausgang:

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

Großartige Arbeit bei der Bereitstellung von Beispieltabellen und Abfragen. Eine Tabelle mit gewünschten Ausgaben wäre wünschenswert. – Simon

+0

Sie sollten dies mit einem rekursiven CTE tun können. Es gibt viele Beispiele hier – SQLBadPanda

Antwort

0

Es gibt viele Möglichkeiten, dies mit Hilfe eines rekursiven CTE zu tun, hier ist eine von vielen:

;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 

ich ein rextester Beispiel hat Sie mit spielen können here

1

Sie können rekursive CTE verwenden. Sie werden 2 Teile: der Anker und der rekursive Teil.

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

Das ist genau das, was ich meinte :) – SQLBadPanda