Viele Tabellen und eine Tabelle mit sich selbst verbunden
Kurz gesagt: Mehrere JOINs hintereinander verknüpfen eine Kette von Tabellen, und ein Self Join verknüpft eine Tabelle mit sich selbst, zum Beispiel eine Kategorie mit ihrer Elternkategorie.
Problem
Umsatz nach Kategorie
Die Inhaberin will wissen, aus welchen Kategorien das Geld kommt. Menge und Preis stehen in order_items. Ob die Bestellung storniert wurde, steht in orders. Die Kategorie des Produkts steht in products und der Name der Kategorie in categories.
Vier Tabellen für einen Bericht. JOIN hört nicht bei zwei auf.
Die Idee
Eine Kette von JOINs
Jeder weitere JOIN fügt dem, was schon zusammengesetzt ist, eine Tabelle hinzu. Bestellung 60 mit ihren Produkten und deren Kategorien:
Der Weg folgt den Fremdschlüsseln: orders → order_items (über order_id) → products (über product_id) → categories (über category_id). Jedes Glied ist ein eigener JOIN … ON.
Sowohl products als auch categories haben eine Spalte name. Deshalb benennen wir sie hier mit AS: product und category. Sonst hätte das Ergebnis zwei Spalten name.
Probier es aus
Wer hat was bewertet
Zeige für jede Bewertung den Namen des Kunden, den Namen des Produkts und die Note.
Lösung
SELECT cu.name AS customer, p.name AS product, r.rating
FROM reviews r
JOIN customers cu ON cu.id = r.customer_id
JOIN products p ON p.id = r.product_id;FROM reviews r JOIN customers cu ON cu.id = r.customer_id JOIN products p ON p.id = r.product_id. 16 Zeilen. Die Bewertung steht in der Mitte: Sie verweist sowohl auf den Kunden als auch auf das Produkt. Die Kaffeebohnen haben drei Bewertungen: 5, 4 und 1.
Sieh es dir an
Das verlorene Geld
Umsatz nach Kategorie, ohne die stornierten Bestellungen:
Sieht gut aus. Jetzt der gesamte Umsatz, ohne Kategorien:
Die sechs Kategorien ergeben 1.537 €, aber der Umsatz beträgt 1.697 €.
In einer Kette von JOINs kann jedes Glied unbemerkt Zeilen hinauswerfen. Für ein Produkt ohne Kategorie gibt es in categories keinen Partner. Mit einem LEFT JOIN zu den Kategorien bleiben die Verkäufe, und COALESCE gibt der fehlenden Kategorie einen Namen:
Sieben Zeilen, und die Summe ist 1.697 €. Wann immer ein Bericht Geld zählt, vergleiche seine Summe mit der Gesamtsumme. Der Unterschied zeigt die verlorenen Zeilen.
Probier es aus
Umsatz nach Stadt
Zeige den Umsatz nach Stadt des Kunden, ohne die stornierten Bestellungen.
Lösung
SELECT c.city, SUM(oi.quantity * oi.unit_price) AS revenue
FROM orders o
JOIN customers c ON c.id = o.customer_id
JOIN order_items oi ON oi.order_id = o.id
WHERE o.status <> 'cancelled'
GROUP BY c.city;FROM orders o JOIN customers c ON c.id = o.customer_id JOIN order_items oi ON oi.order_id = o.id, WHERE o.status <> 'cancelled' und GROUP BY c.city. Sieben Zeilen: Sofia führt mit 658,70 €. Die Zeile mit NULL ist Boris, der keine Stadt hat: 66,60 €. Hier geht nichts verloren, denn jede Bestellung hat einen Kunden.
Die Idee
Eine Tabelle mit sich selbst verbunden
In den Kategorien verweist parent_id auf id in derselben Tabelle. Um eine Kategorie neben ihrer Elternkategorie zu sehen, verbindest du categories mit sich selbst. Die Tabelle kommt zweimal vor, mit zwei verschiedenen kurzen Namen:
c ist die Kategorie, parent ist dieselbe Tabelle, gesehen als Elternteil. ON parent.id = c.parent_id sagt: Das Elternteil ist die Zeile, deren id gleich der parent_id der Kategorie ist. Das heißt Self Join. Hier sind die kurzen Namen Pflicht: Ohne sie lässt sich name aus den beiden Exemplaren nicht unterscheiden.
Es ist ein LEFT JOIN, damit „Lebensmittel“ und „Haushalt“, die kein Elternteil haben, bleiben.
Übung
Zwei Aufgaben
1. Der neue Katalog braucht alle 25 Produkte mit ihrer Kategorie und der Elternkategorie. Die Geschenkkarte muss auch auf der Liste stehen.
Das Produkt, seine Kategorie und die Elternkategorie, für alle Produkte:
Lösung
SELECT p.name AS product, cat.name AS category, parent.name AS parent
FROM products p
LEFT JOIN categories cat ON cat.id = p.category_id
LEFT JOIN categories parent ON parent.id = cat.parent_id;FROM products p LEFT JOIN categories cat ON cat.id = p.category_id LEFT JOIN categories parent ON parent.id = cat.parent_id. 25 Zeilen. Beide JOINs müssen LEFT sein: Ist der zweite ein einfacher JOIN, fällt die Geschenkkarte wieder weg, denn eine Kategorie NULL hat kein Elternteil.
2. Wie hoch ist der Umsatz der zwei obersten Kategorien, „Lebensmittel“ und „Haushalt“? Ohne die stornierten Bestellungen.
Umsatz nach oberster Kategorie:
Lösung
SELECT parent.name AS parent, SUM(oi.quantity * oi.unit_price) AS revenue
FROM order_items oi
JOIN orders o ON o.id = oi.order_id
JOIN products p ON p.id = oi.product_id
JOIN categories cat ON cat.id = p.category_id
JOIN categories parent ON parent.id = cat.parent_id
WHERE o.status <> 'cancelled'
GROUP BY parent.name;Füge der Kette aus dem Kategoriebericht JOIN categories parent ON parent.id = cat.parent_id hinzu und gruppiere nach parent.name. „Lebensmittel“ 824,60 €, „Haushalt“ 712,40 €. Zusammen sind das 1.537 €: Die Geschenkkarten, 160 €, stehen in keiner obersten Kategorie.
Genauer, für Neugierige
Die Reihenfolge einfacher JOINs in einer Abfrage ändert das Ergebnis nicht: Die Datenbank wählt selbst, mit welcher Tabelle sie beginnt. Bei LEFT JOIN zählt die Reihenfolge, denn „links“ ist alles, was davor zusammengesetzt wurde.
Eine Tabelle mit sich selbst verbunden ergibt nur eine Ebene nach oben. Ein Baum mit vielen Ebenen (eine Unterkategorie einer Unterkategorie) wird mit WITH RECURSIVE durchlaufen, im Modul über Unterabfragen.
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: GROUP BY: ein Bericht nach Gruppen · Primärschlüssel und Fremdschlüssel · JOIN: zwei Tabellen in einer Abfrage · LEFT JOIN: auch Zeilen ohne Partner
- Geht weiter in: UNION, INTERSECT, EXCEPT und CROSS JOIN · Eine Auswertung in Schritten: WITH · Bäume und Folgen: WITH RECURSIVE · Views
- Aufgaben zum Thema: Tabellen verbinden