Das Wichtigste in Kürze
- Eine Abfrage nennt mit SELECT die Spalten, mit FROM die Tabelle und mit WHERE die Bedingungen für die Zeilen.
- Fehlende Werte (NULL) findest du nur mit IS NULL, nicht mit = NULL.
- Ohne ORDER BY ist die Reihenfolge der Ergebniszeilen nicht festgelegt.
- JOIN liefert nur Zeilen mit Treffer auf beiden Seiten, LEFT JOIN behält alle Zeilen der linken Tabelle und füllt fehlende Werte mit NULL.
Üben ohne Installation: SQLite über Python
SQL (Structured Query Language) ist die Sprache, mit der du Daten aus relationalen Datenbanken abfragst. Daten liegen dort in Tabellen aus Zeilen und Spalten; Tabellen können über gemeinsame Werte aufeinander verweisen.
Zum Üben brauchst du keinen Datenbankserver. Python bringt das Modul sqlite3 mit, und mit dem Namen ":memory:" legt es laut Python-Dokumentation eine Datenbank an, die nur im Arbeitsspeicher existiert. Das folgende Skript erstellt zwei ausgedachte Tabellen: kunden und bestellungen. Eine Bestellung verweist über kunden_id auf einen Kunden. Wie du Python installierst und Skripte startest, steht in den Python-Grundlagen.
import sqlite3
con = sqlite3.connect(":memory:")
con.executescript("""
CREATE TABLE kunden (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT,
status TEXT
);
CREATE TABLE bestellungen (
bestellnummer INTEGER PRIMARY KEY,
kunden_id INTEGER REFERENCES kunden(id),
betrag REAL,
status TEXT
);
INSERT INTO kunden VALUES
(1, 'Marta Beispiel', 'marta@example.com', 'aktiv'),
(2, 'Malte Muster', 'malte@example.org', 'aktiv'),
(3, 'Jonas Probe', 'jonas@example.com', 'inaktiv'),
(4, 'Lea Platzhalter', NULL, 'aktiv');
INSERT INTO bestellungen VALUES
(1001, 1, 120.00, 'offen'),
(1002, 1, 45.50, 'versendet'),
(1003, 2, 210.00, 'versendet'),
(1004, 3, 80.00, 'offen'),
(1005, NULL, 60.00, 'offen');
""")
def zeige(sql):
cur = con.execute(sql)
print(" | ".join(d[0] for d in cur.description))
for zeile in cur:
print(" | ".join("NULL" if w is None else str(w) for w in zeile))
zeige("SELECT name, email FROM kunden;")Speichere das Skript als uebung.py und starte es. Für jede weitere Abfrage in diesem Artikel ersetzt du den Text in der letzten Zeile.
SELECT: Spalten auswählen
Die einfachste Abfrage nennt Spalten und Tabelle:
SELECT name, email
FROM kunden;name | email
Marta Beispiel | marta@example.com
Malte Muster | malte@example.org
Jonas Probe | jonas@example.com
Lea Platzhalter | NULLSELECT bestimmt die Spalten, FROM die Tabelle. Das Semikolon schließt die Anweisung ab. Schlüsselwörter werden oft großgeschrieben, damit sie sich von Tabellen- und Spaltennamen abheben; nötig ist das nicht. Bei Lea fehlt die E-Mail-Adresse: Die Datenbank speichert dort NULL, also „kein Wert".
Mit SELECT * bekommst du alle Spalten. Für gezielte Abfragen ist es übersichtlicher, die Spalten ausdrücklich zu nennen: So siehst du schon im Code, welche Daten du abrufst.
Spalten umbenennen mit AS
Mit AS gibst du einer Spalte im Ergebnis einen anderen Namen (Alias). Die Tabelle selbst bleibt unverändert:
SELECT name AS kundenname,
email AS kontaktadresse
FROM kunden;Aliasnamen ohne Leerzeichen sind am unkompliziertesten; für Namen mit Leerzeichen brauchst du je nach Datenbank besondere Anführungszeichen.
WHERE: Zeilen filtern
WHERE legt Bedingungen fest. Zurück kommen nur Zeilen, die sie erfüllen:
SELECT bestellnummer, betrag
FROM bestellungen
WHERE betrag > 100;bestellnummer | betrag
1001 | 120.0
1003 | 210.0Neben > gibt es = (gleich), < (kleiner), <= (kleiner oder gleich) und >= (größer oder gleich). Für „ungleich" akzeptiert SQLite laut Dokumentation sowohl <> als auch !=. Textwerte stehen in einfachen Anführungszeichen, Zahlen ohne:
SELECT bestellnummer, status
FROM bestellungen
WHERE status = 'offen';Ein falsch geschriebener Spaltenname führt zu einer Fehlermeldung statt zu einem Ergebnis.
Bedingungen kombinieren
Mit AND müssen alle Bedingungen zutreffen, mit OR genügt eine. Mischst du beide, setze Klammern, damit klar ist, was zusammengehört:
SELECT bestellnummer, status
FROM bestellungen
WHERE status = 'offen'
OR (status = 'versendet' AND betrag > 100);bestellnummer | status
1001 | offen
1003 | versendet
1004 | offen
1005 | offenAlle offenen Bestellungen sind dabei, von den versendeten nur die über 100.
Textmuster, Wertebereiche und fehlende Werte
LIKE sucht nach Mustern. % steht für beliebig viele Zeichen, _ für genau eines:
SELECT name
FROM kunden
WHERE name LIKE 'Ma%';name
Marta Beispiel
Malte MusterIn SQLite unterscheidet LIKE standardmäßig nicht zwischen Groß- und Kleinschreibung, allerdings nur bei ASCII-Buchstaben; Umlaute behandelt es laut Dokumentation anders. Andere Datenbanken verhalten sich hier unterschiedlich.
BETWEEN fragt einen Bereich ab, die Grenzen eingeschlossen. betrag BETWEEN 50 AND 150 entspricht betrag >= 50 AND betrag <= 150:
SELECT bestellnummer, betrag
FROM bestellungen
WHERE betrag BETWEEN 50 AND 150;Ein Sonderfall sind fehlende Werte. kunden_id = NULL findet nichts, weil ein Vergleich mit NULL selbst NULL ergibt und nicht „wahr". Verwende IS NULL oder IS NOT NULL:
SELECT bestellnummer
FROM bestellungen
WHERE kunden_id IS NULL;bestellnummer
1005Mit = NULL statt IS NULL liefert dieselbe Abfrage nur die Kopfzeile, ohne einen einzigen Treffer.
Sortieren und begrenzen: ORDER BY und LIMIT
Ohne ORDER BY ist die Reihenfolge der Ergebniszeilen nicht festgelegt. Mit ORDER BY sortierst du, standardmäßig aufsteigend; DESC dreht die Richtung um. LIMIT begrenzt die Zahl der Zeilen:
SELECT bestellnummer, betrag
FROM bestellungen
ORDER BY betrag DESC
LIMIT 3;bestellnummer | betrag
1003 | 210.0
1001 | 120.0
1004 | 80.0Zählen und summieren: COUNT, SUM und GROUP BY
Aggregatfunktionen fassen viele Zeilen zu einem Wert zusammen: COUNT(*) zählt Zeilen, SUM() addiert, AVG() bildet den Durchschnitt. Mit GROUP BY rechnest du das für jede Gruppe getrennt aus:
SELECT status, COUNT(*) AS anzahl, SUM(betrag) AS umsatz
FROM bestellungen
GROUP BY status
ORDER BY status;status | anzahl | umsatz
offen | 3 | 260.0
versendet | 2 | 255.5Genau so entstehen viele Kennzahlen im Marketing, etwa Anfragen pro Monat; ein Beispiel dafür steht im Artikel zu Marketing-KPIs.
JOIN: Tabellen verbinden
In relationalen Datenbanken liegen zusammengehörige Informationen in verschiedenen Tabellen. Ein JOIN führt passende Zeilen über eine gemeinsame Spalte zusammen. Mit kurzen Aliasnamen für die Tabellen bleibt die Abfrage lesbar:
SELECT k.name, b.bestellnummer
FROM kunden AS k
JOIN bestellungen AS b
ON k.id = b.kunden_id
ORDER BY b.bestellnummer;name | bestellnummer
Marta Beispiel | 1001
Marta Beispiel | 1002
Malte Muster | 1003
Jonas Probe | 1004ON beschreibt die Verknüpfung: Die id des Kunden muss zur kunden_id der Bestellung passen. Die Präfixe k. und b. zeigen, aus welcher Tabelle eine Spalte stammt. Das ist Pflicht, sobald beide Tabellen gleichnamige Spalten haben, hier etwa status.
INNER JOIN und LEFT JOIN
Ein einfacher JOIN ist ein INNER JOIN; laut SQLite-Dokumentation sind beide Schreibweisen dort völlig gleichwertig. Er liefert nur Zeilen, für die es auf beiden Seiten einen Treffer gibt. Deshalb fehlen oben Lea, die nichts bestellt hat, und Bestellung 1005 ohne Kunden.
LEFT JOIN behält dagegen alle Zeilen der linken Tabelle. Gibt es rechts keinen Treffer, stehen in den Spalten der rechten Tabelle NULL-Werte:
SELECT k.name, b.bestellnummer
FROM kunden AS k
LEFT JOIN bestellungen AS b
ON k.id = b.kunden_id
ORDER BY k.id, b.bestellnummer;name | bestellnummer
Marta Beispiel | 1001
Marta Beispiel | 1002
Malte Muster | 1003
Jonas Probe | 1004
Lea Platzhalter | NULLWelche Variante passt, hängt von der Frage ab. Geht es nur um vorhandene Bestellungen, reicht JOIN. Sollen alle Kunden erscheinen, auch die ohne Bestellung, brauchst du LEFT JOIN. Zusammen mit GROUP BY zählst du so die Bestellungen je Kunde, einschließlich der Nullen:
SELECT k.name, COUNT(b.bestellnummer) AS bestellungen
FROM kunden AS k
LEFT JOIN bestellungen AS b
ON k.id = b.kunden_id
GROUP BY k.id, k.name
ORDER BY bestellungen DESC, k.name;name | bestellungen
Marta Beispiel | 2
Jonas Probe | 1
Malte Muster | 1
Lea Platzhalter | 0COUNT(b.bestellnummer) zählt nur Werte, die nicht NULL sind; deshalb steht bei Lea eine 0.
Abfragen schrittweise aufbauen
Die Bausteine lassen sich kombinieren. Diese Abfrage zeigt die Bestellungen aktiver Kunden mit Namen:
SELECT k.name, b.bestellnummer, b.betrag
FROM kunden AS k
JOIN bestellungen AS b
ON k.id = b.kunden_id
WHERE k.status = 'aktiv'
ORDER BY b.bestellnummer;Geschrieben wird in der Reihenfolge SELECT, FROM, JOIN, WHERE, GROUP BY, ORDER BY, LIMIT. Beim Entwickeln gehst du am besten anders herum vor: erst Tabelle und Spalten, dann die Verknüpfung, dann die Filter, zuletzt Gruppierung und Sortierung. Prüfe nach jedem Schritt, ob das Ergebnis zur Frage passt. So erkennst du sofort, welcher Baustein ein unerwartetes Ergebnis verursacht; mehr zu dieser Arbeitsweise findest du unter Debugging für Einsteiger.
Praxis-Tipp: Die Grundformen gelten fast überall, Details wie Datumsfunktionen oder Textvergleiche unterscheiden sich aber zwischen Datenbanksystemen. Wenn eine Abfrage in deinem System anders reagiert als in SQLite, schau zuerst in dessen Dokumentation.
Dein nächster Schritt
Erweitere das Übungsskript um eine dritte Tabelle, zum Beispiel kampagnen, und gib jeder Bestellung eine kampagnen_id. Schreibe dann eine Abfrage, die den Umsatz je Kampagne zeigt, und eine zweite, die auch Kampagnen ohne Bestellung auflistet. Wenn dich interessiert, wie die Daten im Browser aussehen, bevor sie in einer Datenbank landen, fang mit HTML lernen an; alle Grundlagen findest du im Ressort Programmierung.
Häufige Fragen
Kann eine SELECT-Abfrage Daten verändern?
Nein, SELECT liest nur. Zum Einfügen, Ändern und Löschen gibt es eigene Anweisungen (INSERT, UPDATE, DELETE); ob du sie ausführen darfst, hängt von den Rechten in der jeweiligen Datenbank ab.
Muss jede SQL-Anweisung mit einem Semikolon enden?
Das hängt vom Werkzeug ab. Viele erwarten es als Abschluss, manche Oberflächen führen eine einzelne Anweisung auch ohne aus. Gewöhne es dir an: Bei mehreren Anweisungen hintereinander ist es nötig.
Ist SQL in jeder Datenbank gleich?
Die Grundformen wie SELECT, WHERE, GROUP BY und JOIN sind weit verbreitet, Funktionen, Datumsbehandlung und Regeln für Textvergleiche unterscheiden sich aber. Funktioniert eine Abfrage in deinem System nicht, ist dessen Dokumentation die erste Anlaufstelle.
Quellen
- SELECT SQLite-Dokumentation (sqlite.org) · abgerufen am 13. November 2026
- SQL Language Expressions SQLite-Dokumentation (sqlite.org) · abgerufen am 13. November 2026
- sqlite3 — DB-API 2.0 interface for SQLite databases Python-Dokumentation (python.org) · abgerufen am 13. November 2026