left join ??
matthias
- datenbank
Hallo,
ich habe (verkürztes Beispiel) zwei Tabellen "Fahrer" und "Auto" sowie eine Relation "FahrerAuto".
"Auto":
ID | Name
---------
1 | Audi
2 | Benz
3 | BMW
4 | VW
"Fahrer"
ID | Name
---------
1 | Müller
2 | Meier
"FahrerAuto"
FahrerID | AutoID
-----------------
1 | 1
1 | 2
2 | 2
2 | 3
Nun möchte ich alle Autos angezeigt bekommen, die der Fahrer 1 (Müller) nocht nicht fährt. Das ist hier Auto 3(BMW) und Auto 4(VW).
Mein Versuch war:
SELECT Auto.Name FROM Auto LEFT JOIN FahrerAuto ON Auto.ID = FahrerAuto.AutoID WHERE FahrerAuto.FahrerID != 1 OR FahrerAuto.AutoID IS NULL
ohne die Bedingung " FahrerAuto.FahrerID != 1 OR " liefert mir mysql nur Auto 4 - weil das nicht in der Relation steht. Mit dieser Bedingung bekomme ich aber Auto 3, Auto 4 UND Auto 2 (welches ich aber nicht will) - weil Fahrer 2 dieses Auto fährt.
Meine anderen Versuche sind bislang auch gescheitert. Kennt jemand eine Lösung?
Matthias
Halihallo matthias
Nun möchte ich alle Autos angezeigt bekommen, die der Fahrer 1 (Müller) nocht nicht fährt. Das ist hier Auto 3(BMW) und Auto 4(VW).
Dazu brauchst du keinen LEFT OUTER JOIN. Subtrahiere einfach die Menge (alle Autos) mit
der Menge (Autos, die Fahrer 1 (Müller) fährt). Stichwort: MINUS und Subtraktion von
Mengen, informiere dich dazu in der Doku deiner RDBMS.
Viele Grüsse
Philipp
Hallo Philipp,
Subtrahiere einfach die Menge (alle Autos) mit
der Menge (Autos, die Fahrer 1 (Müller) fährt). Stichwort: MINUS und Subtraktion von
Mengen, informiere dich dazu in der Doku deiner RDBMS.
»»
das hiesse doch sowas wie:
SELECT auto.id FROM auto
- MINUS -
SELECT fahrerauto.autoID FROM fahrerauto WHERE fahrerauto.fahrerID = 1
ich benutze leider MySQL 3.2. Da gibts wohl sowas wie MINUS nicht. Und auch keine geschachtelten Select-Statements.. (Ärger)
Matthias
Halihallo Matthias
ich benutze leider MySQL 3.2. Da gibts wohl sowas wie MINUS nicht. Und auch keine geschachtelten Select-Statements.. (Ärger)
Stimmt. Ich glaube das dieses Problem mit MySQL 3.2 in einem Query nicht zu lösen ist.
Wohl aber mit zwei queries, welche du über eine Programmiersprache selber "verbindest".
Hast du diese Möglichkeit?
Viele Grüsse
Philipp
Hallo Philipp,
Wohl aber mit zwei queries, welche du über eine Programmiersprache selber "verbindest".
Hast du diese Möglichkeit?
Ja, mit PHP, ich hole die Ergebnisse der Queries, schreibe beide in seperate Arrays und mache eine Array-Differenz aus beiden. Das geht dann schon, ist aber nicht gerade sehr performant (um nicht zu sagen - *****langsam). Wie gesagt, ist das oben ja nur ein Beispiel, weil es viiiel mehr Daten gibt...
Viele Grüsse Matthias
Halihallo Matthias
Ja, mit PHP, ich hole die Ergebnisse der Queries, schreibe beide in seperate Arrays und mache eine Array-Differenz aus beiden. Das geht dann schon, ist aber nicht gerade sehr performant (um nicht zu sagen - *****langsam). Wie gesagt, ist das oben ja nur ein Beispiel, weil es viiiel mehr Daten gibt...
Meiner Meinung nach der falsche Ansatz. Du selektierst zuerst alle auto_id, welche der
Lenker 1 fährt (dies dürften weniger sein, als wenn du alle selektierst, die eben von
anderen Lenkern gefahren werden, somit hast du hier schon eine Reduktion der Eingabe-
Datenmenge). Diese kleine Anzahl auto_id's selektierst du negativ (NOT) über die Auto-
Tabelle, alla
SELECT name
FROM auto
WHERE id NOT IN ([liste-mit-auto_ids])
Dies dürfte ziemlich performant und speicherschonend sein.
Viele Grüsse
Philipp
Hallo Philipp,
SELECT name
FROM auto
WHERE id NOT IN ([liste-mit-auto_ids])
Vielen Dank für den Tip. Das geht wirklich gleich schneller :)
Viele Grüsse Matthias
P.S. ich war grade dabei mir die neue Version von MySQL auf meine SuSE 8.2 zu spielen. Dort gibt es Subselects. Damit habe ich noch nicht gearbeitet. Wie müsste dort - im Prinzip - so ein Statement aussehen? So vielleicht: "SELECT * FROM Auto WHERE auto.id NOT IN(SELECT * FROM fahrerauto WHERE fahrer = 1)" ?? Kann ich leider noch nicht überprüfen, da SuSE mit der neuen Version noch nicht klarkommt.
use Mosche;
P.S. ich war grade dabei mir die neue Version von MySQL auf meine SuSE 8.2 zu spielen. Dort gibt es Subselects. Damit habe ich noch nicht gearbeitet. Wie müsste dort - im Prinzip - so ein Statement aussehen? So vielleicht: "SELECT * FROM Auto WHERE auto.id NOT IN(SELECT * FROM fahrerauto WHERE fahrer = 1)" ?? Kann ich leider noch nicht überprüfen, da SuSE mit der neuen Version noch nicht klarkommt.
Jedenfalls bei anderen Datenbanken funktioniert es so (Postgres zB).
use Tschoe qw(Matti);
Hallo,
"SELECT * FROM Auto WHERE Auto.id NOT IN(SELECT * FROM fahrerauto WHERE fahrerID = 1)"
So hab ichs nun ausprobiert.Und bekomme Fehlermeldungen.
Jedenfalls bei anderen Datenbanken funktioniert es so (Postgres zB).
Dann muss ich nun auf Postgres umsteigen??
Funktioniert mit Postgres auch die PHP-Anbindung so reibungslos wie MySQL?
Viele Grüsse Matthias
Hallo Matthias,
"SELECT * FROM Auto WHERE Auto.id NOT IN(SELECT * FROM fahrerauto WHERE fahrerID = 1)"
So hab ichs nun ausprobiert.Und bekomme Fehlermeldungen.
Dann versuch's mal so:
SELECT * FROM Auto WHERE Auto.id NOT IN(SELECT autoID FROM fahrerauto WHERE fahrerID = 1)
Select * in der zweiten Abfrage liefert Dir ja die Werte (autoID, fahrerID) aus fahrerauto, in der Liste willst Du aber nur die AutoID haben.
Grüße
Andreas
Hi Matthias
Mein Versuch war:
SELECT Auto.Name FROM Auto LEFT JOIN FahrerAuto ON Auto.ID = FahrerAuto.AutoID WHERE FahrerAuto.FahrerID != 1 OR FahrerAuto.AutoID IS NULLohne die Bedingung " FahrerAuto.FahrerID != 1 OR " liefert mir mysql nur Auto 4 - weil das nicht in der Relation steht. Mit dieser Bedingung bekomme ich aber Auto 3, Auto 4 UND Auto 2 (welches ich aber nicht will) - weil Fahrer 2 dieses Auto fährt.
Das müsste klappen (ungetestet):
SELECT Auto.Name
FROM Auto
LEFT JOIN FahrerAuto
ON (Auto.ID = FahrerAuto.AutoID
AND FahrerAuto.FahrerID = 1)
WHERE FahrerAuto.FahrerID IS NULL
FahrerAuto.FahrerID = 1 muss in die Join-Klausel mit rein, damit nur solche verbunden werden und du für alle anderen NULL kriegst, sonst passiert genau das was dein Problem war.
Gruss Daniela