Entwickler-Ecke

Datenbanken - zwei JOINs auf die gleiche Referenz-Tabelle ausführen


Narses - Mo 22.06.09 14:17
Titel: zwei JOINs auf die gleiche Referenz-Tabelle ausführen
Moin!

Ich hab mal wieder ein (MySQL-)Problem und steh auf´m Schlauch... :roll:

Hier das abstrakte Problem: Ich habe zwei Tabellen, t1 (id,a,b,c) und t2 (id,name), wobei t1.a auf t2.id verweist, allerdings t1.b zeigt auch auf t2.id. Zum besseren Verständnis: t1 enthält einen Vorgang, der von zwei Leuten bearbeitet wird (a,b), deren Details in t2 vorgehalten werden.

Wie formuliere ich nun ein SELECT, dass mir die Datensätze aus t1 mit den Namen aus t2 ergänzt abliefert?! :gruebel:

cu
Narses


BenBE - Mo 22.06.09 14:24


SQL-Anweisung
1:
SELECT t.*, pa.*, pb.* FROM t1 AS t INNER JOIN t2 AS pa ON t1.a = pa.id INNER JOIN t2 AS pb ON t1.b = pb.id WHERE 42                    


Alternativ auch möglich:

SQL-Anweisung
1:
SELECT t.*, pa.*, pb.* FROM t1 AS t, t2 AS pa, t2 AS pb WHERE t1.a = pa.id AND t1.b = pb.id AND 42                    


Rest sollte logisch folgen ...


Narses - Mo 22.06.09 14:27

Moin!

user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:

SQL-Anweisung
1:
SELECT t.*, pa.*, pb.* FROM t1 AS t INNER JOIN t2 AS pa ON t1.a = pa.id INNER JOIN t2 AS pb ON t1.b = pb.id WHERE 42                    
Ich hab aber nur eine Personen-Tabelle, das ist ja mein Problem... :?

cu
Narses


BenBE - Mo 22.06.09 14:34

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
Moin!

user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:

SQL-Anweisung
1:
SELECT t.*, pa.*, pb.* FROM t1 AS t INNER JOIN t2 AS pa ON t1.a = pa.id INNER JOIN t2 AS pb ON t1.b = pb.id WHERE 42                    
Ich hab aber nur eine Personen-Tabelle, das ist ja mein Problem... :?

cu
Narses

Siehe hinten im JOIN die beiden AS-Klauseln ... Damit wird die Nachschlagetabelle t2 zweimal eingebunden; kann also bei großen Datenmengen zu recht großen Kreuzprodukten führen. Hier bedarf es einem recht aktuellen MySQL, damit das sauber optimiert wird.

Alternativ kann man das aber auch in 2 Abfragen lösen, muss dann aber das Lookup selber regeln:

SQL-Anweisung
1:
SELECT t2.* FROM t2 WHERE t2.id IN (SELECT t1.a FROM t1 WHERE 42 UNION SELECT t1.b FROM t1 WHERE 42)                    


Ist zwar nicht ideal, spart dafür aber grad bei großen Tabellen sehr viel Speicher. In der Regel dürfte aber obige Variante mit dem Cross Join wesentlich performanter laufen, da im Gegensatz zur UNION SELECT-Variante durch einen guten Optimierer nur einmal auf t2 SELECTED werden muss.


Narses - Mo 22.06.09 14:40

Moin!

Ah, OK. :idea: Ich probier das mal aus, danke erstmal. ;)

cu
Narses


Delete - Mo 22.06.09 14:57

Sind die Felder a, b und c für die Personen-IDs gedacht? Dann stimmt Deine Normalisierung nicht.


BenBE - Mo 22.06.09 15:09

user profile iconDeddyH hat folgendes geschrieben Zum zitierten Posting springen:
Sind die Felder a, b und c für die Personen-IDs gedacht? Dann stimmt Deine Normalisierung nicht.

Solange überhaupt normalisiert ist, passt's doch :P Außerdem ist das Beispiel rein fiktiv - Ähnlichkeiten zu real existierenden Datenbanken sind sicherlich REIN ZUFÄLLIG! :mrgreen:


Delete - Mo 22.06.09 15:11

Wer's glaubt, wird selig ;)


Narses - Mo 22.06.09 16:21

Moin!

user profile iconDeddyH hat folgendes geschrieben Zum zitierten Posting springen:
Sind die Felder a, b und c für die Personen-IDs gedacht? Dann stimmt Deine Normalisierung nicht.
Zumindest c ist keine Personen-ID, sondern einfach eine zusätzliche Info des Vorgangs. Kannst du das mal etwas erläutern? :?

cu
Narses


Delete - Mo 22.06.09 16:50

Wenn ich das richtig verstanden habe, können einem Vorgang bis zu 2 Personen zugeordnet sein, wohingegen vermutlich jede Person mehreren Vorgängen zugeordnet sein kann, ist das so richtig? Das wäre ja dann die klassische m:n-Beziehung, die man über eine Zwischentabelle auflöst. Wenn es später mal mehr mögliche Personen je Vorgang werden sollten, musst Du bei Deiner bisherigen Variante die Tabellenstruktur ändern, was bei meiner nicht nötig ist.


Narses - Mo 22.06.09 17:40

Moin!

user profile iconDeddyH hat folgendes geschrieben Zum zitierten Posting springen:
Wenn ich das richtig verstanden habe, können einem Vorgang bis zu 2 Personen zugeordnet sein, wohingegen vermutlich jede Person mehreren Vorgängen zugeordnet sein kann, ist das so richtig?
Im Prinzip ja, es sind allerdings immer genau 2 Personen einem Vorgang zugeordnet (kann sich auch nicht ändern), also 2:n. :nixweiss:

user profile iconDeddyH hat folgendes geschrieben Zum zitierten Posting springen:
Das wäre ja dann die klassische m:n-Beziehung, die man über eine Zwischentabelle auflöst.
Wenn es n:m wäre, hätte ich eine weitere Tabelle, ja. ;)

user profile iconDeddyH hat folgendes geschrieben Zum zitierten Posting springen:
Wenn es später mal mehr mögliche Personen je Vorgang werden sollten, musst Du bei Deiner bisherigen Variante die Tabellenstruktur ändern, was bei meiner nicht nötig ist.
Welche Version meinst du? Habe in deinen Beiträgen keinen Vorschlag gesehen? :lupe:

Und kannst du nochmal erläutern, was du mit "Normalisierung" bezogen auf den Beitrag oben meinst? :gruebel:

cu
Narses


Delete - Mo 22.06.09 17:46

Gut, wenn es immer genau 2 Personen sind, ist das kein Problem. Ich hatte hingegen angenommen, dass es bis zu 2 Personen sein könnten, da wäre die Variante mit Zwischentabelle (die ich mit "meiner" meinte) die bessere Lösung gewesen, da man sonst mit INNER JOINs kein Ergebnis bekommt, wenn auch nur eins der beiden Felder NULL ist.


Narses - Mo 22.06.09 18:51

Moin!

Alles klar, funktioniert. ;) Vielen Dank an alle "Mitarbeiter". :zustimm:

cu :wave:
Narses