La clause WHERE filtre les lignes une par une
Un SELECT sans WHERE te renvoie absolument toutes les lignes de la table. En pratique, c'est rarement ce qu'on cherche. La clause WHERE de SQLite permet de ne garder que les lignes qui respectent une condition donnée : SQLite parcourt la table, évalue la condition pour chaque ligne, et conserve uniquement celles pour lesquelles le résultat est vrai.
Trois lignes ressortent : Neuromancer, Hyperion et The Martian. La condition year > 1980 a été évaluée pour chaque ligne, et seules celles qui correspondent ont survécu.
Le modèle mental à retenir : WHERE agit comme un filtre placé entre le FROM et les colonnes que vous sélectionnez. Tout ce qui s'évalue à vrai passe à travers.
Les opérateurs de comparaison
Les bases fonctionnent comme on s'y attend :
= pour l'égalité, != ou <> pour « différent de », et <, <=, >, >= pour les comparaisons d'ordre. Les chaînes de caractères utilisent les mêmes opérateurs : author = 'Asimov' fait une correspondance stricte, caractère par caractère.
Un point important à retenir : en SQL, les littéraux de type chaîne s'écrivent entre apostrophes (guillemets simples). Les guillemets doubles, eux, servent à désigner des identifiants (noms de colonnes ou de tables). En SQLite, WHERE author = "Asimov" peut fonctionner pour des raisons historiques, mais ce n'est pas portable et ça peut produire des comportements silencieusement erronés si la « chaîne » correspond justement à un nom de colonne. Tenez-vous-en aux apostrophes.
Combiner plusieurs conditions avec AND, OR et parenthèses
Dans la vraie vie, une clause WHERE SQLite combine presque toujours plusieurs conditions. AND exige que les deux côtés soient vrais ; OR se contente d'au moins un des deux :
La première requête garde uniquement les livres récents et courts. La seconde récupère les livres écrits par l'un ou l'autre des auteurs.
Dès qu'on mélange AND et OR, la priorité des opérateurs piège pas mal de monde. AND est prioritaire sur OR, donc :
se lit comme Herbert OR (Gibson AND year > 1980) — soit tous les livres de Herbert, peu importe l'année, plus les livres de Gibson postérieurs à 1980. Sans doute pas ce que vous vouliez. Mettez votre intention entre parenthèses :
En cas de doute, mettez des parenthèses. Ça ne change rien pour l'optimiseur de requêtes, et la prochaine personne qui relira le code vous remerciera.
NULL ne se comporte pas comme une valeur
C'est le piège classique de la clause WHERE : tout le monde tombe dedans une fois. En SQL, NULL signifie « inconnu », et on ne peut pas comparer ce qui est inconnu. column = NULL n'est pas faux — le résultat est NULL, et WHERE interprète ça comme « ignorer cette ligne ».
IS NULL et IS NOT NULL sont les seuls opérateurs qui testent réellement NULL. Imprimez-vous bien ça dans la tête : toute autre comparaison avec NULL renvoie NULL et écarte silencieusement les lignes concernées.
La même règle vaut pour la négation. WHERE author != 'Asimov' ne renvoie pas les lignes où author IS NULL, puisque NULL != 'Asimov' vaut aussi NULL. Pour inclure les NULL, il faut le demander explicitement : WHERE author != 'Asimov' OR author IS NULL.
SQLite WHERE IN et BETWEEN : les raccourcis du quotidien
IN vérifie l'appartenance à une liste. C'est une façon plus propre d'écrire une suite de OR :
BETWEEN teste un intervalle, bornes incluses des deux côtés :
year BETWEEN 1980 AND 2000 est strictement équivalent à year >= 1980 AND year <= 2000, juste en plus court. Attention quand même : les deux bornes sont incluses. Si vous voulez des bornes exclusives, il faudra écrire les comparaisons à la main.
Petit piège avec IN et NULL : un WHERE column NOT IN (1, 2, NULL) ne renverra jamais aucune ligne, car toute comparaison avec NULL donne NULL. Retirez les valeurs NULL de votre liste, ou gérez-les à part avec IS NULL.
SQLite WHERE LIKE : la recherche par motif
LIKE permet de filtrer des chaînes selon un motif, à l'aide de deux jokers :
%correspond à n'importe quelle suite de caractères (y compris une suite vide)._correspond à un seul caractère, exactement.
Par défaut, l'opérateur LIKE de SQLite ne tient pas compte de la casse pour les lettres ASCII : 'Dune' LIKE 'dune' renvoie vrai. Ça surprend quand on vient de Postgres, où LIKE est sensible à la casse et où l'on dispose de ILIKE pour la version insensible. (SQLite, lui, n'a pas d'ILIKE.)
Si vous avez besoin d'une correspondance sensible à la casse, deux options s'offrent à vous. La première : activer le pragma global :
PRAGMA case_sensitive_like = ON;
Ou alors utilisez GLOB, qui est toujours sensible à la casse et s'appuie sur les jokers à la sauce Unix (* pour une suite quelconque de caractères, ? pour un seul caractère) :
GLOB 'd*' ne matcherait rien ici — la casse compte.
Filtrer des dates
SQLite stocke les dates sous forme de texte (en général YYYY-MM-DD ou en ISO 8601 complet). Du coup, les comparaisons de chaînes font aussi office de comparaisons de dates — à condition de bien respecter le format ISO :
Comme '2024-06-01' < '2024-11-08' est vrai aussi bien en tant que chaîne qu'en tant que date, ces requêtes se comportent comme on s'y attend. En revanche, si vous stockez vos dates dans un autre format ('15/01/2024', 'Jan 15 2024'), les comparaisons donneront des résultats faux sans le moindre avertissement. Tenez-vous-en toujours à l'ISO 8601 — votre vous du futur vous remerciera.
Pour des calculs de dates plus poussés (extraire l'année, comparer à « aujourd'hui »), SQLite propose les fonctions date(), strftime() et julianday(). On y reviendra dans le chapitre dédié aux dates et heures.
Tout combiner dans une seule requête
Voici une requête qui mobilise plusieurs de ces éléments d'un coup :
Lisez-le ligne par ligne : on garde les lignes dont l'année est connue, comprise dans l'intervalle, écrites par l'un des deux auteurs ou suffisamment longues, et qui ne sont pas des brouillons. Voilà la clause WHERE dans son rôle de prédilection : combiner de petites conditions lisibles pour obtenir un filtre précis.
Deux bonnes habitudes à garder :
- Mettre chaque condition sur sa propre ligne, avec indentation. Une clause
WHEREun peu longue devient vite illisible quand elle tient sur une seule ligne géante. - Commenter l'intention quand la condition n'est pas évidente. Un petit
-- exclut les brouillons, ça ne coûte rien et ça sauve la mise.
La suite : les opérateurs et NULL en détail
La clause WHERE, c'est essentiellement des opérateurs appliqués à des colonnes — et NULL vient discrètement changer le comportement de chacun d'eux. La page suivante creuse l'ensemble des opérateurs de SQLite : arithmétique, concaténation de chaînes avec ||, la famille IS, la logique à trois valeurs… histoire que les surprises arrêtent d'en être.
Questions fréquentes
Comment fonctionne la clause WHERE en SQLite ?
WHERE filtre les lignes d'une requête en évaluant une condition sur chacune d'elles. Les lignes pour lesquelles la condition est vraie sont conservées ; celles qui renvoient false ou NULL sont écartées. Elle se place juste après FROM : SELECT ... FROM table WHERE condition.
Comment combiner plusieurs conditions dans un WHERE en SQLite ?
Avec AND et OR. AND exige que les deux côtés soient vrais, OR se contente d'un seul. Attention : AND a une priorité plus forte que OR, donc dès qu'on mélange les deux, on met des parenthèses pour lever toute ambiguïté : WHERE (a OR b) AND c.
Pourquoi WHERE colonne = NULL ne fonctionne pas en SQLite ?
NULL signifie « inconnu ». Du coup, toute comparaison avec = ou != renvoie NULL au lieu de vrai ou faux — et seules les lignes où la condition est vraie sont gardées. Il faut utiliser IS NULL et IS NOT NULL : ce sont les seuls opérateurs capables de tester directement la présence d'un NULL.
La clause WHERE avec LIKE est-elle sensible à la casse en SQLite ?
Par défaut, LIKE est insensible à la casse pour les caractères ASCII — 'Hello' LIKE 'hello' renvoie vrai. Pour forcer la sensibilité à la casse, active PRAGMA case_sensitive_like = ON; ou utilise GLOB, qui est toujours sensible à la casse et fonctionne avec les jokers à la mode Unix (* et ?).