2010-11-22 8 views
2

Ich habe drei Tabellen:T-SQL-Außen über drei Tabellen beitreten

CREATE TABLE person 
    (id int, 
    name char(50)) 

CREATE TABLE eventtype 
    (id int, 
    description char(50)) 

CREATE TABLE event 
    (person_id int, 
    eventtype_id int, 
    duration int) 

Was ich will, ist eine einzelne Abfrage, die mir eine Liste der Gesamtdauer der einzelnen Eventtype für jede Person gibt, einschließlich aller Null-Einträge . Z.B. Wenn 10 Personen und 15 verschiedene Ereignistypen vorhanden sind, sollten unabhängig vom Inhalt der Ereignistabelle 150 Zeilen zurückgegeben werden.

Ich kann eine äußere Verbindung zwischen zwei Tabellen (z. B. Dauer für alle Ereignistypen) arbeiten, aber nicht mit einer zweiten äußeren Verknüpfung.

Danke!

Antwort

2

Sie müssen eine CROSS APPLY zu der Mischung hinzufügen, um die nicht vorhandenen Beziehungen zu erhalten.

SELECT q.name, q.description, SUM(q.Duration) 
FROM (
      SELECT p.Name, et.description, Duration = 0 
      FROM person p 
        CROSS APPLY eventtype et 
      UNION ALL   
      SELECT p.Name, et.description, e.duration 
      FROM person p 
        INNER JOIN event e ON e.person_id = p.id 
        INNER JOIN eventtype et ON et.id = e.eventtypeid   
     ) q 
GROUP BY 
     q.Name, q.description   
+0

Das funktionierte perfekt, danke! – meepmeep

+0

Gern geschehen. –

1

Sie überqueren Person und eventtype beitreten können, und dann kommen nur das Ergebnis an die Ereignistabelle:

SELECT 
    p.Name, 
    et.Description, 
    COALESCE(e.duration,0) 
FROM 
    person p 
     cross join 
    eventtype et 
     left join 
    event e 
     on 
     p.id = e.person_id and 
     et.id = e.eventtype_id 

Ein Cross-Join ist eine, wo für jede Zeile in der linken Tabelle, es verbunden ist zu jeder Zeile in der rechten Tabelle.

1

Wenn Sie eine Zeile für jede Kombination von person und eventtype möchten, schlägt das eine CROSS JOIN vor. Um die Dauer zu erhalten, müssen wir uns an event anschließen, aber das muss ein OUTER Join sein, da es nicht immer eine Zeile gibt. Ihre Verwendung von "total" deutet darauf hin, dass dort mehr als eine event für eine gegebene Kombination von person und event sein könnte, also brauchen wir auch eine SUM darin.

Beispieldaten:

insert person values (1, 'Joe') 
insert person values (2, 'Bob') 
insert person values (3, 'Tim') 

insert eventtype values (1, 'Cake') 
insert eventtype values (2, 'Pie') 
insert eventtype values (3, 'Beer') 

insert event values (1, 1, 10) 
insert event values (1, 2, 10) 
insert event values (1, 2, 5) 
insert event values (2, 1, 10) 
insert event values (2, 2, 7) 
insert event values (3, 2, 8) 
insert event values (3, 3, 16) 
insert event values (1, 1, 10) 

Die Abfrage:

SELECT 
    PET.person_id 
    , PET.person_name 
    , PET.eventtype_id 
    , PET.eventtype_description 
    , ISNULL(SUM(E.duration), 0) total_duration 
FROM 
    (
    SELECT 
     P.id person_id 
     , P.name person_name 
     , ET.id eventtype_id 
     , ET.description eventtype_description 
    FROM 
     person P 
     CROSS JOIN eventtype ET 
    ) PET 
    LEFT JOIN event E ON PET.person_id = E.person_id 
        AND PET.eventtype_id = E.eventtype_id 
GROUP BY 
    PET.person_id 
    , PET.person_name 
    , PET.eventtype_id 
    , PET.eventtype_description 

Ausgang:

person_id person_name eventtype_id eventtype_description total_duration 
----------- ----------- ------------ --------------------- -------------- 
1   Joe   1   Cake     20 
1   Joe   2   Pie     15 
1   Joe   3   Beer     0 
2   Bob   1   Cake     10 
2   Bob   2   Pie     7 
2   Bob   3   Beer     0 
3   Tim   1   Cake     0 
3   Tim   2   Pie     8 
3   Tim   3   Beer     16 
Warning: Null value is eliminated by an aggregate or other SET operation. 

(9 row(s) affected) 
+0

Danke - das funktioniert auch und hat mir den Prozess auch sehr deutlich gemacht - Outer Joins waren nicht das was ich wollte. – meepmeep