Kodokon kodokon.com

Unterabfragen: WHERE, FROM, IN und EXISTS

Verschachtle eine Abfrage in einer anderen, um mit einem Aggregat zu vergleichen, nach einer Menge zu filtern oder auf Existenz zu prüfen.

9 Min. · 3 Fragen

Diese Lektion in Kodokon öffnen

Eine Unterabfrage ist eine Abfrage, die in Klammern innerhalb einer anderen steht. In einer einzigen Anweisung beantwortet sie Fragen wie "die Bestellungen über dem Durchschnitt" oder "die Kunden mit mindestens einer Bestellung". Führe dieses Skript in sqliteonline.com oder sqlite3 aus, bevor du beginnst.

SQL
CREATE TABLE customers (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL
);

CREATE TABLE orders (
  id INTEGER PRIMARY KEY,
  customer_id INTEGER NOT NULL,
  amount REAL NOT NULL
);

INSERT INTO customers (id, name) VALUES
  (1, 'Alice'), (2, 'Karim'),
  (3, 'Mina'), (4, 'Paulo');

INSERT INTO orders (id, customer_id, amount)
VALUES
  (1, 1, 49.90), (2, 1, 15.00),
  (3, 2, 120.50), (4, 2, 80.00),
  (5, 3, 9.90), (6, 1, 200.00);
Datensatz: vier Kunden, sechs Bestellungen.

In WHERE platziert, muss eine skalare Unterabfrage einen einzigen Wert zurückgeben: eine Zeile, eine Spalte. Die Engine berechnet sie zuerst und verwendet sie dann wie jede andere Konstante. Mit einem einfachen WHERE amount > AVG(amount), das in SQL verboten ist, geht das nicht.

SQL
SELECT id, customer_id, amount
FROM orders
WHERE amount > (
  SELECT AVG(amount) FROM orders
);
Die Bestellungen über dem durchschnittlichen Warenkorb (79.22).

IN vergleicht eine Spalte mit der Menge der Werte, die die Unterabfrage zurückgibt. EXISTS prüft, ob die korrelierte Unterabfrage (sie verweist auf c.id, eine Spalte der äußeren Abfrage) mindestens eine Zeile zurückgibt: Die Engine hält an, sobald die erste Übereinstimmung gefunden ist.

SQL
SELECT name FROM customers
WHERE id IN (
  SELECT customer_id FROM orders
  WHERE amount > 100
);

SELECT c.name FROM customers AS c
WHERE EXISTS (
  SELECT 1 FROM orders AS o
  WHERE o.customer_id = c.id
);
IN: die großen Käufer. EXISTS: die aktiven Kunden.

In FROM verhält sich eine Unterabfrage wie eine temporäre Tabelle, abgeleitete Tabelle genannt, und muss ein Alias erhalten. Sie ist das klassische Werkzeug, um in zwei Schritten zu aggregieren: zuerst eine Summe pro Kunde, dann der Durchschnitt dieser Summen.

SQL
SELECT ROUND(AVG(t.total), 2) AS avg_basket
FROM (
  SELECT customer_id, SUM(amount) AS total
  FROM orders
  GROUP BY customer_id
) AS t;
Durchschnittlicher Gesamtwarenkorb pro aktivem Kunden: 158.43.

Wissenscheck

Stelle sicher, dass du die wichtigsten Punkte dieser Lektion behalten hast.

  1. Wie viele Werte muss eine in amount > (...) verwendete Unterabfrage zurückgeben?
    • Genau einen
    • Einen pro Zeile der äußeren Tabelle
    • So viele wie sie möchte
  2. Was ist der Hauptvorteil von EXISTS gegenüber IN?
    • Es kann mehrere Spalten zurückgeben
    • Es hält bei der ersten gefundenen Zeile an, ohne die gesamte Menge zu materialisieren
    • Es funktioniert ohne Unterabfrage
  3. Was muss eine in FROM platzierte Unterabfrage immer tragen, um überall portabel zu sein?
    • Ein Alias, etwa AS t
    • Eine ORDER BY-Klausel
    • Ein internes Semikolon