SQL: "Liste aller Veranstaltungen samt nächstem Termin"?
snorri
- datenbank
Hi alle,
ich bastle gerade an einem komplexen SQL-Statement herum und komme auf keinen grünen Zweig; vielleicht kann mir ja hier jemand einen Tipp geben ...
Gesetzt den Fall, ich will das Programm eines Kinos ausgeben, und zwar als Liste aller aktuellen Filme, jeweils mit dem nächsten Vorstellungstermin. Ich habe also zwei Tabellen:
film (id, name, beschreibung ...)
vorstellung (id, id_film, beginn, preis, saal, ...)
Typischerweise wird es ja zu jedem Film mehrere Vorstellungen in der zweiten Tabelle geben. Mein Ansatz:
SELECT film.*,
vorstellung.*,
film.id AS fid
FROM film, vorstellung
WHERE
(film.id = vorstellung.id_film) AND
(vorstellung.beginn =
SELECT MIN(beginn)
FROM vorstellung
WHERE
(id_film = fid) AND
(beginn > NOW())
)
Ich hole mir also die Zeit der nächsten Vorstellung aus einem Subquery und schränke meinen Hauptquery auf Datensätze ein, die dieses Datum haben.
Anscheinend habe ich mir das aber zu einfach vorgestellt, denn das funktioniert nicht. Ich erhalte zwar keine Fehlermeldung, aber auch keine Ergebnisse. Wenn ich die Bedingung (id_film = fid) aus dem Subquery nehme, dann kommt etwas -- aber natürlich nicht das richtige. Muss ich noch etwas zusätzlich unternehmen, um das Feld des Hauptqueries im Subquery verwenden zu können, oder liegt mein Verständnisfehler an anderer Stelle?
Danke für alle sachdienlichen Hinweise!
-- snorri
film (id, name, beschreibung ...)
vorstellung (id, id_film, beginn, preis, saal, ...)
Ich würde das mit einem Join lösen.
Ich würde das mit einem Join lösen.
@Thorsten:
Was für ne tolle Idee!!!!. Es ist bereits mit einem Join gelöst, wenn auch nicht in/mit expliziter JOIN Notation sondern from tabelle1, tabelle2, ....
Ich würde das vielleicht besser so schreiben:
SELECT outerFilm.*,
outerVorstellung.*
-- film.id AS fid -- das kann weg, du hast ja film.id schon mittels outerFilm.*
FROM film outerFilm
INNER JOIN vorstellung outerVorstellung
ON outerFilm.id = outerVorstellung.id_film
WHERE vorstellung.beginn =
(SELECT MIN(innerVorstellung.beginn)
FROM vorstellung innerVorstellung
WHERE innerVorstellung.id_film = outerVorstellung.id_film -- rückreferenz zur korrelation
AND innerVorstellung.beginn > NOW())
Imho, hat snorri etwas komisch die Abfragen miteinander verbunden (korreliert), evt. die Klammern falsch gesetzt?
Hinweise an snorri:
Grüsse, Frank
Hallo Frank,
puh, in die Syntax muss ich mich erst einmal einarbeiten, so tief bin ich in SQL noch nicht eingestiegen. Danke!
Zur *-Angabe: Die Film-Datenbank war nur ein Beispiel. Aber auch in der realen Anwendung werde ich wohl nicht anders können, denn die Liste der einzelnen Felder wäre ellenlang. Mir ist aber klar, dass es vom Sicherheitsaspekt besser wäre.
-- snorri
'nabend!
puh, in die Syntax muss ich mich erst einmal einarbeiten, so tief bin ich in SQL noch nicht eingestiegen. Danke!
Wieso, ist doch nix bahnbrechend kompliziertes dabei
(1) SELECT für die Ausgabe
(2) JOIN um eine weitere Tabelle anzuk
(3) SELECT welches einen Skalarwert für den Vergleich zurückgibt
(1) ist trivial, du gibst das an Feldern/Spalten an, was du ausgeben/selektieren willst
(2) ist ne andere bessere Schreibweise für FROM tab1, tab2 WHERE tab1.x = tab2.x; WHERE wird zu ON .... daran gewöhnt man sich schnell
(3) ist allein einfach erstmal GIB MIR DAS KLEINSTE DATUM VON ALLEN DATENSÄTZEN DEREN DATUM > JETZT IST
da kommt dann nur die Verknüpfung mit einem Feld vom umgebenden SELECT dazu, fertig
Zur *-Angabe: Die Film-Datenbank war nur ein Beispiel. Aber auch in der realen Anwendung werde ich wohl nicht anders können, denn die Liste der einzelnen Felder wäre ellenlang.
Fiele Velder = sehr wahrscheinlich schlechtes (und damit dringend verbesserungswürdiges) Datenbankdesign.
Mir ist aber klar, dass es vom Sicherheitsaspekt besser wäre.
Vom Sicherheitsaspekt her? Wow, wie bitte? Das erläutere mal bitte.
Ciao, Frank
yo,
immer gut zu wissen, welche dbms und welche version du benutzt. was dein problem angeht, so hat dich frank schon darauf hingewiesen, besser explizite joins zu benutzen. auch die verwendung von * bei der ausgabe der spalten kann kritisch sein.
aber mein tipp an dich ist, warum eine korrelierte unterabfrage bentuzen, wenn du einfach über das datum in der veranstaltungstabelle gehen kannst ?
SELECT f.id.....
FROM film f
INNER JOIN vorstellung v ON v.id_film = f.id
WHERE v.begin >= NOW()
;
Ilja