Mit WHERE Zeilen einzeln filtern
Ein SELECT ohne WHERE liefert dir alle Zeilen der Tabelle zurück – und genau das willst du in der Praxis nur selten. Mit der WHERE-Klausel filterst du gezielt die Zeilen heraus, die eine bestimmte Bedingung erfüllen: SQLite geht die Tabelle Zeile für Zeile durch, prüft jeweils die Bedingung und behält nur die Treffer, bei denen sie wahr ist.
Drei Zeilen kommen zurück: Neuromancer, Hyperion und The Martian. Die Bedingung year > 1980 wurde gegen jede Zeile geprüft – durchgekommen sind nur die Treffer.
Das mentale Modell dahinter: Die WHERE-Klausel ist ein Filter, der zwischen FROM und den ausgewählten Spalten sitzt. Alles, was zu wahr ausgewertet wird, rutscht durch.
Vergleichsoperatoren
Die Grundlagen funktionieren so, wie man es erwartet:
= für Gleichheit, != oder <> für „ungleich" und <, <=, >, >= für Größenvergleiche. Bei Strings funktionieren dieselben Operatoren — author = 'Asimov' trifft exakt, Zeichen für Zeichen.
Ein wichtiger Hinweis: In SQL stehen String-Literale in einfachen Anführungszeichen. Doppelte Anführungszeichen sind für Bezeichner (also Spalten- oder Tabellennamen) reserviert. WHERE author = "Asimov" mag in SQLite aus historischen Gründen noch funktionieren, ist aber nicht portabel und kann sich heimlich falsch verhalten, sobald der vermeintliche „String" zufällig einem Spaltennamen entspricht. Bleib bei einfachen Anführungszeichen.
SQLite WHERE mit mehreren Bedingungen: AND, OR und Klammern
In der Praxis kombiniert man fast immer mehrere Bedingungen in der WHERE-Klausel. AND verlangt, dass beide Seiten wahr sind, bei OR reicht eine der beiden:
Die erste Abfrage filtert nach aktuellen und kurzen Büchern. Die zweite holt sich Bücher von einem der beiden Autoren.
Sobald du AND und OR kombinierst, tappen viele in die Präzedenz-Falle. AND bindet stärker als OR – das heißt:
liest sich als Herbert OR (Gibson AND year > 1980) – also jedes Herbert-Buch unabhängig vom Jahr, plus Gibson-Bücher nach 1980. Vermutlich nicht das, was du eigentlich willst. Klammere deine Absicht deshalb deutlich:
Im Zweifel lieber Klammern setzen. Dem Query-Optimizer ist das egal, und die nächste Person, die den Code liest, wird es dir danken.
NULL verhält sich nicht wie ein normaler Wert
Das ist die klassische Falle in der WHERE-Klausel, in die jeder einmal tappt. NULL bedeutet in SQL „unbekannt", und Unbekanntes lässt sich nicht vergleichen. column = NULL ist also nicht falsch — das Ergebnis ist NULL, und WHERE behandelt das wie „diese Zeile überspringen".
IS NULL und IS NOT NULL sind die einzigen Operatoren, die NULL direkt prüfen. Präg dir das gut ein – jeder andere Vergleich mit NULL liefert wieder NULL und schluckt die Zeilen lautlos weg.
Bei der Verneinung gilt dasselbe. WHERE author != 'Asimov' liefert keine Zeilen, in denen author IS NULL ist, denn auch NULL != 'Asimov' ergibt NULL. Wenn du NULL-Werte mit dabeihaben willst, musst du das explizit sagen: WHERE author != 'Asimov' OR author IS NULL.
SQLite WHERE IN und BETWEEN: Abkürzungen für den Alltag
IN prüft, ob ein Wert in einer Liste enthalten ist. Es ist die saubere Variante einer langen Kette aus OR-Bedingungen:
BETWEEN prüft einen Wertebereich – inklusive beider Grenzen:
year BETWEEN 1980 AND 2000 ist gleichbedeutend mit year >= 1980 AND year <= 2000 — nur eben kürzer. Wichtig dabei: Beide Grenzwerte sind inklusiv. Brauchst du exklusive Grenzen, schreibst du die Vergleiche besser aus.
Noch ein kurzer Hinweis zu IN und NULL: WHERE column NOT IN (1, 2, NULL) liefert dir grundsätzlich keine Zeilen, weil jeder Vergleich mit NULL wieder NULL ergibt. Entweder du entfernst NULL-Werte vorher aus der Liste oder du behandelst sie separat über IS NULL.
Mustervergleich mit LIKE
Mit LIKE kannst du in SQLite Zeilen anhand von Textmustern filtern. Es gibt zwei Platzhalter:
%steht für eine beliebige Zeichenfolge (auch eine leere)._steht für genau ein einzelnes Zeichen.
Standardmäßig ist LIKE in SQLite bei ASCII-Buchstaben nicht case-sensitiv — 'Dune' LIKE 'dune' liefert also true. Wer von Postgres kommt, stolpert hier gerne: dort arbeitet LIKE case-sensitiv, und für die Variante ohne Groß-/Kleinschreibung gibt es ILIKE. In SQLite existiert ILIKE übrigens gar nicht.
Wenn du tatsächlich case-sensitiv vergleichen willst, hast du zwei Möglichkeiten. Entweder du setzt das globale Pragma:
PRAGMA case_sensitive_like = ON;
Alternativ kannst du GLOB verwenden – das arbeitet immer case-sensitiv und nutzt Wildcards im Unix-Stil (* für eine beliebige Zeichenfolge, ? für genau ein Zeichen):
GLOB 'd*' würde hier gar nichts finden – Groß- und Kleinschreibung zählt eben.
Datumswerte filtern
SQLite speichert Datumsangaben als Text (meistens im Format YYYY-MM-DD oder als vollständiges ISO 8601). Praktischer Nebeneffekt: String-Vergleiche funktionieren dadurch automatisch auch als Datumsvergleiche – solange du konsequent beim ISO-Format bleibst:
Da '2024-06-01' < '2024-11-08' sowohl als String- als auch als Datumsvergleich true ergibt, liefern solche Abfragen genau das erwartete Ergebnis. Sobald du Datumswerte aber in einem anderen Format ablegst ('15/01/2024', 'Jan 15 2024'), produzieren Vergleiche stillschweigend falsche Ergebnisse. Halte dich daher konsequent an ISO 8601 – dein zukünftiges Ich wird es dir danken.
Für etwas anspruchsvollere Datumsberechnungen (etwa das Jahr extrahieren oder mit „heute" vergleichen) bietet SQLite die Funktionen date(), strftime() und julianday(). Die schauen wir uns im Kapitel zu Datum und Uhrzeit genauer an.
Alles zusammen: mehrere Bedingungen kombinieren
Eine Abfrage, die mehrere dieser Bausteine gleichzeitig nutzt:
Lies das Ganze einfach Zeile für Zeile durch: Behalte Zeilen mit bekanntem Jahr, im passenden Bereich, von einem der beiden Autoren oder ausreichend lang, und keine Entwürfe. Genau das macht die WHERE-Klausel am besten — kleine, gut lesbare Bedingungen zu präzisen Filtern kombinieren.
Zwei Angewohnheiten, die sich lohnen:
- Rücke jede Bedingung in einer eigenen Zeile ein. Lange
WHERE-Klauseln werden als ein einziger langer Strich schnell unleserlich. - Kommentiere die Absicht, wenn die Bedingung nicht selbsterklärend ist.
-- Entwürfe ausschließenkostet nichts und spart später Nerven.
Als Nächstes: Operatoren und NULL im Detail
Die WHERE-Klausel besteht im Kern aus Operatoren, die auf Spalten angewendet werden — und NULL verändert klammheimlich das Verhalten praktisch jedes Operators. Die nächste Seite geht tiefer in den Operator-Vorrat von SQLite: Arithmetik, String-Verkettung mit ||, die IS-Familie und dreiwertige Logik. Danach sind die typischen Überraschungen keine Überraschungen mehr.
Häufig gestellte Fragen
Wie funktioniert die WHERE-Klausel in SQLite?
WHERE filtert die Zeilen einer Abfrage, indem es für jede Zeile eine Bedingung prüft. Zeilen, bei denen die Bedingung wahr ergibt, bleiben übrig – Zeilen mit false oder NULL fliegen raus. Sie steht direkt hinter FROM: SELECT ... FROM tabelle WHERE bedingung.
Wie kombiniere ich mehrere Bedingungen in einer WHERE-Klausel?
Mit AND und OR. AND verlangt, dass beide Seiten wahr sind, OR reicht schon eine. Wichtig: AND bindet stärker als OR. Wenn du beides mischst, setz lieber Klammern, damit die Logik eindeutig ist: WHERE (a OR b) AND c.
Warum funktioniert WHERE spalte = NULL in SQLite nicht?
NULL bedeutet "unbekannt". Jeder Vergleich mit = oder != liefert deshalb wieder NULL und nicht true oder false – und Zeilen werden nur behalten, wenn die Bedingung wahr ist. Stattdessen nimmst du IS NULL bzw. IS NOT NULL. Das sind die einzigen Operatoren, die direkt auf NULL prüfen.
Ist die WHERE-Klausel mit LIKE case-sensitive?
Standardmäßig nicht – LIKE ignoriert bei ASCII-Zeichen die Groß-/Kleinschreibung, also ist 'Hello' LIKE 'hello' wahr. Brauchst du echte Case-Sensitivität, setz PRAGMA case_sensitive_like = ON; oder nimm GLOB. GLOB unterscheidet immer Groß und Klein und nutzt Unix-typische Wildcards (* und ?).