SQL-Interviewfragen, mit Antworten, die du ausführen kannst

Die meisten SQL-Interviews wiederholen dieselben etwa ein Dutzend Ideen. Unten stehen die üblichen, mit einer kurzen Antwort und einer Abfrage, die in PostgreSQL funktioniert. Die Beispiele verwenden eine kleine Bäckerei-Datenbank (customers, products, orders und order_items), damit du jede davon in einer Lektion auf dieser Seite ausprobieren kannst.

Den zweithöchsten Wert finden

Eine einfache Antwort: absteigend sortieren und eine Zeile überspringen. Es kommt genau eine Zeile zurück, auch wenn mehrere Zeilen den zweiten Preis teilen.

Wenn Gleichstände wichtig sind, rangiere mit DENSE_RANK und behalte Rang 2. DENSE_RANK lässt nach Gleichständen keine Lücken, daher ist Rang 2 immer der zweite verschiedene Wert.

SELECT name, unit_price
FROM (
  SELECT name, unit_price, DENSE_RANK() OVER (ORDER BY unit_price DESC) AS r
  FROM products
) AS ranked
WHERE r = 2;

Ergebnis: Das Stück Chocolate cake zu 4.20.

Duplikate finden

Gruppiere nach der Spalte, die eindeutig sein sollte, und behalte die Gruppen mit mehr als einer Zeile.

SELECT order_date, COUNT(*) AS orders
FROM orders
GROUP BY order_date
HAVING COUNT(*) > 1
ORDER BY order_date;

Ergebnis: Drei Datumswerte mit je zwei Bestellungen: der 1., 2. und 6. September.

Zeilen ohne Treffer finden

Verwende einen LEFT JOIN und behalte die Zeilen, bei denen die rechte Seite NULL ist, oder verwende NOT EXISTS. Beides beantwortet die Frage „Welche Kunden haben nie bestellt?“.

Vermeide NOT IN mit einer Unterabfrage, die NULL liefern kann: ein einziges NULL macht die ganze Bedingung unbekannt, und du erhältst keine Zeilen.

SELECT c.first_name, c.last_name
FROM customers AS c
LEFT JOIN orders AS o ON o.customer_id = c.customer_id
WHERE o.order_id IS NULL
ORDER BY c.customer_id;

Ergebnis: Grace Kim und Hugo Meyer.

Oberste Zeile pro Gruppe

Rangiere innerhalb jeder Gruppe mit PARTITION BY und behalte in einer äußeren Abfrage den Rang 1. Verwende RANK, um Gleichstände zu behalten, oder ROW_NUMBER, um genau eine Zeile pro Gruppe zu behalten.

SELECT category, name, units
FROM (
  SELECT p.category, p.name, SUM(oi.quantity) AS units,
         RANK() OVER (PARTITION BY p.category ORDER BY SUM(oi.quantity) DESC) AS rk
  FROM products AS p
  JOIN order_items AS oi ON oi.product_id = p.product_id
  GROUP BY p.category, p.name
) AS ranked
WHERE rk = 1
ORDER BY category, name;

Ergebnis: Das meistverkaufte Produkt jeder Kategorie. Bei Cake erscheinen zwei Produkte, weil sie mit je 3 Einheiten gleichauf liegen.

Laufende Summe

Verwende SUM als Fensterfunktion mit ORDER BY. Sortiere nach einer Spalte ohne Gleichstände, sonst werden gleichrangige Zeilen zusammengezählt.

SELECT order_id,
       SUM(quantity) AS units,
       SUM(SUM(quantity)) OVER (ORDER BY order_id) AS running_units
FROM order_items
GROUP BY order_id
ORDER BY order_id;

Ergebnis: Einheiten pro Bestellung und die laufende Summe, die am Ende bei 56 liegt.

WHERE gegen HAVING

WHERE filtert Zeilen, bevor sie gruppiert werden, daher kann es keine Aggregatfunktion verwenden. HAVING filtert die Gruppen nach der Aggregation. Im Beispiel entfernt WHERE zuerst die günstigen Produkte, und HAVING behält die Kategorien mit mindestens zwei der verbleibenden Produkte.

SELECT category, COUNT(*) AS products
FROM products
WHERE unit_price > 2.50
GROUP BY category
HAVING COUNT(*) >= 2
ORDER BY category;

Ergebnis: Bread and cake, mit je zwei Produkten über 2.50. Pastry und drinks haben nur ein Produkt über 2.50 und fallen weg.

UNION gegen UNION ALL

UNION entfernt doppelte Zeilen, was zusätzliche Arbeit erfordert. UNION ALL behält alles und ist schneller. Verwende UNION ALL, außer du möchtest Duplikate entfernen.

SELECT city FROM customers
UNION
SELECT city FROM customers
ORDER BY city;

Ergebnis: Fünf Städte, jede einmal. Mit UNION ALL wären es 16 Zeilen.

Häufige Fragen

Was ist der Unterschied zwischen DELETE, TRUNCATE und DROP?
DELETE entfernt die Zeilen, die du mit WHERE auswählst, und kann zurückgerollt werden. TRUNCATE leert die ganze Tabelle schnell und behält ihre Struktur. DROP entfernt die Tabelle selbst mit Struktur und Daten.
Was ist der Unterschied zwischen INNER JOIN und LEFT JOIN?
INNER JOIN behält nur Zeilen, die auf beiden Seiten übereinstimmen. LEFT JOIN behält jede Zeile der linken Tabelle und füllt die rechte Seite mit NULL, wo kein Treffer existiert.
Was ist der Unterschied zwischen RANK, DENSE_RANK und ROW_NUMBER?
Alle drei nummerieren Zeilen in einer Reihenfolge. RANK gibt Gleichständen dieselbe Nummer und überspringt die folgenden Nummern. DENSE_RANK gibt Gleichständen dieselbe Nummer und überspringt keine. ROW_NUMBER vergibt nie dieselbe Nummer zweimal.
Welchen SQL-Dialekt verwenden diese Antworten?
PostgreSQL. LIMIT/OFFSET, Fensterfunktionen, CTEs und Joins funktionieren fast überall. In SQL Server verwendest du TOP oder OFFSET FETCH statt LIMIT, in Oracle FETCH FIRST.

Übe es