Listen aus Unterabfragen: IN
In Lektion 3 hast du IN mit einer Liste von Werten benutzt: WHERE id IN (1, 3, 5). Die Liste muss nicht von Hand getippt sein: Eine Unterabfrage kann sie erzeugen. Welche Spiele haben mindestens eine Bewertung mit fünf Sternen? Die IDs dieser Spiele stehen in der Tabelle bewertungen:
SELECT spiel_id FROM bewertungen WHERE sterne = 5;| spiel_id |
|---|
| 1 |
| 1 |
| 3 |
| 6 |
| … |
Setze diese Abfrage in Klammern hinter IN, und die äußere Abfrage findet die Titel der Spiele:
SELECT titel
FROM spiele
WHERE id IN (SELECT spiel_id FROM bewertungen WHERE sterne = 5)
ORDER BY titel;| titel |
|---|
| Cube Logic |
| Dragon Forge |
| Knight's Oath |
| Moon Farm |
| Star Pilots |
| Turbo Karts |
| Zombie Town |
Die Unterabfrage läuft zuerst und liefert eine Liste: 1, 1, 3, 6, 7, 10, 14, 15. Dann prüft IN jedes Spiel: Ist seine id in der Liste? Dragon Forge (1) steht zweimal in der Liste, aber das spielt keine Rolle: IN fragt nur, ob der Wert vorkommt, also steht jedes Spiel höchstens einmal im Ergebnis.
Anders als die Unterabfragen der vorigen Übung darf eine Unterabfrage nach IN beliebig viele Zeilen liefern, sogar keine (dann findet IN nichts). Sie muss aber genau eine Spalte liefern, denn IN vergleicht einen Wert mit einer Liste von Werten:
SELECT titel
FROM spiele
WHERE id IN (SELECT spiel_id, sterne FROM bewertungen);Error on line 1: sub-select returns 2 columns - expected 1Du könntest die Spiele auch mit einem Join finden:
SELECT s.titel
FROM spiele AS s
JOIN bewertungen AS bw ON bw.spiel_id = s.id
WHERE bw.sterne = 5
ORDER BY s.titel;| titel |
|---|
| Cube Logic |
| Dragon Forge |
| Dragon Forge |
| Knight's Oath |
| Moon Farm |
| Star Pilots |
| Turbo Karts |
| Zombie Town |
Ein Join macht eine Zeile für jede passende Bewertung, also steht Dragon Forge mit seinen zwei Fünf-Sterne-Bewertungen zweimal darin, und du bräuchtest DISTINCT. Was nimmst du? Wenn du Spalten der anderen Tabelle im Ergebnis brauchst, etwa die Sterne oder den Kommentar, brauchst du einen Join. Wenn die andere Tabelle nur entscheidet, welche Zeilen bleiben, sagt IN mit einer Unterabfrage genau, was du meinst: „die Spiele, deren ID unter diesen ist“.
Typischer Fehler: = statt IN. WHERE id = (SELECT spiel_id FROM bewertungen WHERE sterne = 5) ist in SQLite kein Fehler, aber wie du in der vorigen Übung gesehen hast, nimmt es nur den ersten Wert der Liste, findet also nur Dragon Forge.
So schreibst du es:
Anweisungen
- 1
Die Abfrage im Editor findet die Spiele, die jemand gekauft hat, mit einem Join und
DISTINCT. Schreibe sie ohne den Join um: Zeige die Titel der Spiele, derenidin der Liste derspiel_id-Werte vonpositionensteht. BenutzeINmit einer Unterabfrage. Das Ergebnis bleibt gleich:titel Bakery Story Castle Siege Cube Logic … - 2
Zeige darunter den Namen und die Stadt der Kunden, die in einem Dezember eine Bestellung aufgegeben haben, in irgendeinem Jahr. Die Unterabfrage findet die IDs dieser Kunden in
bestellungen; der Monat eines Datums iststrftime('%m', bestellt_am). Sortiere nach dem Namen:name stadt Emma Becker Hamburg Noah Winter Dresden Olivia Braun Hamburg Oskar Klein Berlin - 3
Eine Unterabfrage kann eine weitere Unterabfrage enthalten. Zeige den Namen und die E-Mail-Adresse der Kunden, die Dragon Forge bewertet haben: Eine Unterabfrage findet die IDs der Bewerter in
bewertungen, und darin findet eine weitere Unterabfrage die ID des Spiels über seinen Titel. Sortiere nach dem Namen:name email Anna Fischer anna.fischer@mail.de Emma Becker emma.becker@mail.de Leon Wagner leon.wagner@mail.de Lukas Neumann lukas.neumann@mail.de