SQL (Structured Query Language) ist die Abfragesprache relationaler Datenbanken – MySQL, MariaDB, PostgreSQL, SQL Server und SQLite sprechen sie in sehr ähnlicher Form. Die folgenden Bausteine decken den Alltag zu weit über neunzig Prozent ab.

Die Beispieldaten

CREATE TABLE kunden (
  id        INT PRIMARY KEY,
  name      VARCHAR(100) NOT NULL,
  ort       VARCHAR(100),
  erstellt  DATE
);

CREATE TABLE bestellungen (
  id         INT PRIMARY KEY,
  kunden_id  INT NOT NULL REFERENCES kunden(id),
  betrag     DECIMAL(10,2) NOT NULL,
  status     VARCHAR(20) NOT NULL
);

SELECT, WHERE, ORDER BY, LIMIT

SELECT id, name, ort
FROM   kunden
WHERE  ort = 'Lübeck'
  AND  erstellt >= '2026-01-01'
ORDER  BY name ASC
LIMIT  20;

Wichtig: NULL ist kein Wert, sondern „unbekannt". Vergleiche mit = NULL funktionieren nicht – man schreibt where ort IS NULL bzw. IS NOT NULL.

JOINs: Tabellen verbinden

Daten liegen normalisiert in mehreren Tabellen. JOIN führt sie über Schlüssel zusammen.

-- INNER JOIN: nur Kunden MIT Bestellungen
SELECT k.name, b.id AS bestellnr, b.betrag
FROM   kunden k
JOIN   bestellungen b ON b.kunden_id = k.id;

-- LEFT JOIN: ALLE Kunden, Bestellungen optional
SELECT k.name, COALESCE(SUM(b.betrag), 0) AS umsatz
FROM   kunden k
LEFT   JOIN bestellungen b ON b.kunden_id = k.id
GROUP  BY k.id, k.name;

Der Unterschied ist entscheidend: Ein INNER JOIN verschwindet Kunden ohne Bestellung, ein LEFT JOIN behält sie mit NULL.

Aggregate, GROUP BY und HAVING

SELECT status,
       COUNT(*)          AS anzahl,
       SUM(betrag)       AS summe,
       AVG(betrag)       AS durchschnitt
FROM   bestellungen
GROUP  BY status
HAVING SUM(betrag) > 1000
ORDER  BY summe DESC;

Merksatz für die Reihenfolge: WHERE filtert vor der Gruppierung (einzelne Zeilen), HAVING nach der Gruppierung (Ergebnisgruppen).

Daten ändern

INSERT INTO kunden (id, name, ort, erstellt)
VALUES (101, 'Muster GmbH', 'Lübeck', '2026-09-26');

UPDATE kunden SET ort = 'Hamburg' WHERE id = 101;

DELETE FROM kunden WHERE id = 101;

Vorsicht: Ein UPDATE oder DELETE ohne WHERE trifft alle Zeilen. Vorher mit demselben WHERE ein SELECT ausführen und das Ergebnis prüfen.

Indizes: der wichtigste Hebel für Tempo

Ein Index ist wie das Stichwortverzeichnis eines Buchs: Ohne ihn muss die Datenbank jede Zeile lesen (full table scan).

CREATE INDEX idx_bestellungen_kunden ON bestellungen (kunden_id);
CREATE INDEX idx_kunden_ort          ON kunden (ort);

Faustregeln: Indizes auf Spalten, die in WHERE, JOIN und ORDER BY auftauchen; zusammengesetzte Indizes in der Reihenfolge der Filter. Zu viele Indizes kosten Schreibleistung und Speicher – also messen statt raten. Wie man Abfragen analysiert, zeigt die jeweilige EXPLAIN-Ausgabe der Datenbank.

Siehe auch