[SQL] Bedingung: XX soll nicht erfüllt sein

Stex

Zeta Sagittarii
ID: 54415
L
11 Mai 2006
937
185
Hi,

Entschuldigt den etwas merkwürdigen Thread-Titel, aber mir ist einfach keine Formulierung eingefallen, weshalb ich auch Google nicht viel Erfolg hatte.

Die Sache ist folgende:

Ich habe eine Tabelle "bookings". Jedes Booking hat mehrere "booking_extras" (in der booking_extras-tabelle existiert ein feld "booking_id").

Über ein Include der Tabelle booking_extras kann ich jetzt schon nur bookings anzeigen lassen, die ein bestimmtes extra haben. Was ich allerdings haben möchte ist, nach bookings zu suchen, die kein extra haben, also keinen eintrag in der tabelle booking_extras mit ihrer booking_id.
Ist das irgendwie ohne eine rechenintensive subquery möglich?

Danke schonmal im voraus!
 
Im Prinzip hast Du drei Möglichkeiten:

1) Outer Join
2) uncorrelated subquery
3) correlated subquery:

1) Outer Join

SELECT daten
FROM bookings B LEFT JOIN booking_extras BE
ON B.id = BE.booking_id
WHERE BE.booking_id IS NULL

2) uncorrelated subquery

SELECT daten
FROM bookings
WHERE id NOT IN (
SELECT booking_id
FROM booking_extras
WHERE booking_id IS NOT NULL )

3) correlated subquery

SELECT daten
FROM bookings B
WHERE NOT EXISTS
( SELECT * FROM booking_extras BE
WHERE B.id = BE.booking_ID )


welche dieser drei Möglichkeiten in Deinem Fall die beste/performanteste ist, hängt von verschiedenen Faktoren ab, z.B. von der Grösse der einzelnen Tabellen, der Indexunterstützung der Queries usw. ) Im allgemeinen sollte der Join die bevorzugte Variante sein
 
Super, das war genau das, was ich meinte :)
Ich musste sogar nur eine Bedingung anfügen (booking_extras.booking_id IS NULL) und es lief, wie es sollte.

Danke!

edit:
@transversalis: Ich habe jetzt die oberste Version genutzt, eine Subquery wäre glaube ich weniger effizient.
 
wie bereits erwähnt ist der Join im allgemeinen die erste Wahl ( nicht zuletzt deshalb, weil der Optimizer mehrere Strategien zur Wahl hat, wie er den Join auflöst )

Die uncorrelated subquery würde ich ggf wählen, wenn die bookings-Tabelle sehr gross wäre, die booking_extras klein wäre und die Spalte booking.id nicht indexiert wäre.

Die correlated subquery käme in Frage bei einer kleinen bookings-Tabelle, einer grossen booking_extra Tabelle mit einem effektiven Index auf booking_extras.booking_id
 

Jemand der sein Fach versteht :biggrin:

Stex, je nach Größe der Datenbanken (ich weiß ja nicht von wieviel wir hier reden) kann es durchaus Sinn machen und die Daten zu denormalisieren, so dass du in booking ein extra Feld "booking_extras_count" einfügst damit du dir die Subquerys oder Joins sparen kannst, denn bei Gigabyteweise Daten in beiden Tabellen mit vielen Beziehungen werden sowohl Join als auch Subquery alles andere als eine aktzeptable Performance erreichen.
 
Auf Joins wird es hier wohl immer hinauslaufen, da die Query von Rails erstellt wird. Ich könnte auch eine eigene Query erstellen, aber Rails wählt z.B. basierend auf den Conditions selbst aus, ob der Join überhaupt gemacht werden muss, daher ist das letztendlich vermutlich schneller.

Das mit dem Extras-Count-Feld ist natürlich theoretisch gut, aber wenn man die Extras über eine spezielle Tablelle erreicht, die über eine Model-Abhängigkeit :)has_many) abgerufen wird, scheidet das hier mehr oder weniger aus (denke ich).
 
Das mit dem Extras-Count-Feld ist natürlich theoretisch gut, aber wenn man die Extras über eine spezielle Tablelle erreicht, die über eine Model-Abhängigkeit :)has_many) abgerufen wird, scheidet das hier mehr oder weniger aus (denke ich).

tut es nicht, du musst eben nur beim verändern in deiner Extras-Tabelle (hinzufügen, löschen) die Datensätze in der Bookmarking-Tabelle aktualisieren.

Also wenn du für booking = 1 ein neues extra einfügen willst, machst du es wie vorher dass du einfach nen insert die extra-tabelle machst, im 2. schritt musst du aber eben noch in der booking-tabelle ein count++ für den booking = 1 Datensatz machen.
 
Da sollte man jetzt erstmal klären :

a) wie oft diese spezielle Abfrage gemacht werden soll
b) Wie zeitkritisch sie ist im Vergleich zu den anderen Zugriffen
c) wie viele Sätze in die Tabelle booking_extras eingefügt oder aus ihr insgesamt gelöscht werden
d) wie viele Sätze in die Tabelle booking_extras eingefügt/gelöscht werden OHNE den zugehörigen bookings-Satz einzufügen/zu löschen

usw. usw.

Ohne detailliertere Informationen über die Gesamtanwendung zu haben kann keine seriöse Aussage getroffen werden, ob Denormalisierung hier zielführend ist
 
Ohne detailliertere Informationen über die Gesamtanwendung zu haben kann keine seriöse Aussage getroffen werden, ob Denormalisierung hier zielführend ist

Ich habe auch nie gesagt, dass es das tut, ich habe es nur als Ergänzung erwähnt, dass es KANN. Wenn seine Datenbank nicht groß genug ist, lohnt das sowieso nicht, habe ich ja auch gesagt.
 
Mein letzter Kommentar war auch eher an Stex gerichtet.

Wenn die Query einmal im Jahr ausgeführt wird und ein "nice to have" Ergebnis liefert, dann brauche ich über eine Denormalisierung nicht nachzudenken. Wenn die Query zeitkritisch ist, siehts ganz anders aus.
 
Die Abfrage befindet sich auf einer Seite, die die bisherigen Bookings eines Hotels nach bestimmten Kriterien gefiltert anzeigt, somit passiert das ziemlich oft.
Bookings werden es sehr schnell sehr viele, da es unter anderem auch um Ticketverkaufende Systeme geht.
Allerdings hat die Abfrage eine Limitbegrenzung von 30 Datensätzen, somit werden nie zu viele auf einmal abgerufen.
Die Joins werden zudem nur ausgeführt, wenn sie auch wirklich aufgrund der Conditions benötigt werden.
 

Ähnliche Themen