• Facile

Mis à jour le 21/11/2013

Filtrer les données avec WHERE

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Vous connaissez déjà la clause WHERE, vous l'avez survolée dans le cours de M@teo (si vous pensez que je suis méchant en disant survoler, je ne veux pas l'être, et je sais fort bien que le cours de M@teo21 sur MySQL n'est qu'une brève initiation en la matière, sinon mon tuto n'aurait pas de raison d'être :p ).

Nous allons aller un peu plus loin dans ce chapitre en apprenant des techniques de filtrage et en vous épargnant de tout apprendre sur le tas au fur et à mesure de recherches sur le net >_ .

Dans le chapitre, je pars du principe que vous connaissez déjà les opérateurs AND ( && ) et OR ( || ) qui permettent d'utiliser plusieurs conditions dans la même requête.

Tant qu'on y est, je vous dis 2 mots sur l'opérateur XOR que vous connaissez peut-être également et qui exprime le "Ou exclusif", c'est-à-dire que c'est l'un ou c'est l'autre, mais pas les 2 en même temps (contrairement à OR qui admet que les 2 puissent être vrais).

A propos de la clause WHERE...

Avant de nous lancer dans le listage des fonctions et opérateurs intéressants à utiliser dans la clause WHERE, j'aimerais vous expliquer (très) rapidement son fonctionnement...

Il faut savoir que MySQL trie les données avant de les récupérer. ^^

Vous ne comprenez pas ce que je veux dire ? C'est assez simple : MySQL regarde les lignes qui correspondent à la clause WHERE en ne récupérant que les données nécessaire au triage. Par exemple dans la requête :

SELECT * FROM t_news WHERE nws_auteur = 'karamilo';

MySQL ne récupère d'abord que la colonne nws_auteur (et l'index PRIMARY, qui correspond ici à nws_id), pour voir quelles lignes correspondent (c'est-à-dire dans ce cas-ci les lignes où nws_id vaut 2, 3 ou 5).

Ensuite, il va chercher les autres données comprises entre SELECT et FROM et effectue toutes les fonctions demandées.

D'accord, mais concrètement, à quoi ça nous sert de savoir ça ? o_O

Je voulais vous amener au fait qu'il est impossible d'utiliser des colonnes calculées entre SELECT et FROM dans le WHERE. Ainsi la requête suivante vous renverra une erreur (la fonction YEAR(date) renvoie l'année de date) :

SELECT nws_id, YEAR(nws_date) AS annee FROM t_news WHERE annee = 2007;

La requête suivante par contre est correcte :

SELECT nws_id, YEAR(nws_date) AS annee FROM t_news WHERE YEAR(nws_date) = 2007;

Vous vous dites sans doute que c'est dommage de devoir utiliser 2 fois la fonction YEAR : on fait perdre du temps au serveur MySQL... Dans ce cas-ci, il est très simple d'optimiser la requête, par exemple comme ceci :

SELECT nws_id, 2007 AS annee FROM t_news WHERE YEAR(nws_date) = 2007;

Les opérateurs de comparaison

7 opérateurs...

MySQL en admet 7, vous connaissez certainement déjà la plupart :

Opérateur

Signification

a = b

a et b ont la même valeur

a <> b

a et b ont des valeurs différentes

a < b

a est strictement plus petit que b

a <= b

a est plus petit ou égal à b

a > b

a est strictement plus grand que b

a >= b

a est plus grand ou égal à b

a <=> b

Idem que = mais NULL <=> NULL vaut 1 (au lieu de NULL) et NULL <=> 1 vaut 0 (au lieu de NULL)

Quelques notes...

<=>

Tout d'abord par rapport au dernier opérateur (oui je suis un grand désordonné... :p ). Il est nécessaire de revenir sur le premier opérateur pour comprendre pourquoi il est là :o :

Quand on compare quelque chose à une valeur NULL avec l'opérateur =, peu importe ce quelque chose, le résultat sera NULL. Et quand on fait une requête avec WHERE NULL, on ne reçoit rien...

Rien de grave apparemment, si c'est NULL, c'est NULL, pas de données à récupérer. ^^

Oui mais voilà, si on a le cas NULL = NULL, on aimerait que les données soient récupérées quand même (logique...), or avec l'opérateur =, la ligne sera ignorée, alors qu'on en a besoin !

C'est pour ça que l'opérateur "NULL-safe equal" (jargon...) a été créé. NULL <=> NULL renvoie 1 (true), et donc la ligne est récupérée quand même. :)

Attention toutefois à ce que la valeur 0 n'est pas la valeur NULL ! 0 <=> NULL renvoie 0 (false).

<>

Je vous ai dit que MySQL admettait 7 opérateurs, je vous ai encore menti, en fait il en admet 8. :p

Vous connaissez bien sûr l'opérateur de comparaison PHP != qui permet de vérifier que 2 valeurs ne sont pas égales. Cet opérateur existe également en MySQL.

Toutefois je ne peux que vous déconseiller de l'utiliser. Tout d'abord parce que PHP et MySQL sont 2 langages différents et qu'il est inutile de chercher à faire en sorte qu'ils se ressemblent, et ensuite parce que ce n'est pas normalisé, donc si vous passez un jour à PostGreSQL (même si j'admet qu'en France il n'est pas encore très intégré aux sites web, imaginons que vous déménagiez aux States ^^ ), vous serez bon pour réécrire la plupart de vos requêtes... (on ne peut pas dire que l'opérateur d'inégalité soit rare dans les requêtes ^^ ).

Enfin en bref je vous conseille de jeter != à la poubelle pour les requêtes SQL et d'utiliser exclusivement <>.

(NOT) BETWEEN, IN et LIKE

Voici quelques mots-clefs qu'il est vraiment intéressant de connaitre. :p

(NOT) BETWEEN

Celui-ci vous permet de vérifier qu'une valeur est comprise entre 2 valeurs données. Ca fonctionne évidemment pour les nombres mais également pour les chaînes de caractères. :)

Quelques exemples...

SELECT nws_id, nws_nb_vues FROM t_news WHERE nws_nb_vues BETWEEN 0 AND 1000;
SELECT nws_id, nws_auteur FROM t_news WHERE nws_auteur BETWEEN 'h' AND 'w';
SELECT nws_id, nws_date FROM t_news WHERE nws_date BETWEEN '2007-06-03' AND '2007-06-13'; -- Ma date d'anniversaire et celle de mon filleul :-° :p
Utilisation du mot-clef BETWEEN

Evidemment, ajouter le mot-clef NOT devant BETWEEN permet de vérifier que les valeurs ne sont pas comprises entre les 2 arguments reçus par BETWEEN.

(NOT) IN

Très pratique également, surtout en conjonction avec PHP, ce mot-clef permet de vérifier qu'une valeur se trouve dans une liste d'arguments reçus par IN (NOT IN permet de vérifier qu'elle ne s'y trouve pas ^^ ).

On passe directement aux exemples, rien de compliqué. ^^

SELECT DISTINCT cmt_auteur FROM t_commentaire WHERE cmt_auteur NOT IN ( 'shepard', 'karamilo' );
SELECT nws_id, nws_date FROM t_news WHERE DAY(nws_date) IN ( 5, 8 );
SELECT nws_id, nws_catid FROM t_news WHERE nws_catid IN ( 2, 3 );
utilisation du mot-clef IN

(NOT) LIKE

C'est certainement le plus connu des 3... LIKE permet de vérifier une expression régulière simple, c'est à dire par exemple qu'une chaîne commence par "abc" ou termine par "xyz"...

LIKE admet 2 "jokers" : % et _.

% remplace n'importe quelle chaîne de caractères (y compris une chaine vide).
_ remplace un seul caractère.

On passe aux exemples :

SELECT DISTINCT nws_auteur FROM t_news WHERE nws_auteur LIKE '%k%'; -- Tous les auteurs qui ont au moins un "k" dans leur pseudo
SELECT DISTINCT nws_auteur FROM t_news WHERE nws_auteur LIKE '%o'; -- Tous les auteurs dont le pseudo se termine par "o"
SELECT DISTINCT cmt_auteur FROM t_commentaire WHERE cmt_auteur NOT LIKE '%r%'; -- Tous les auteurs dont le pseudo ne contient pas de "r"
Utilisation du mot-clef LIKE

[Problème SQL] Qui est plus grand que le dernier plus grand ?

Ce problème utilise 2 fonctions SQL que vous ne connaissez pas encore : il s'agit de GREATEST() et LEAST().

GREATEST renvoie l'argument le plus grand qu'il reçoit, tandis que LEAST() renvoie l'argument le plus petit.

Exemples :

SELECT GREATEST(1, 85, 49, 20, 92, 10); -- Renvoie 92
SELECT LEAST(1, 85, 49, 20, 92, 10); -- Renvoie 1

Le problème (mouahah vous allez souffrir ^^ )

On se sert exclusivement de la table t_news.

Le but : afficher un tableau qui donne :

  • l'id de la news (nws_id) ;

  • le nombre de vues de la news (nws_nb_vues).

Bon évidemment ce n'est pas tout. :D

Il faut afficher uniquement les lignes où nws_nb_vues est plus grand que l'élément précédent.

Vous devrez donc obtenir ce résultat :

Résultat attendu pour le problème 2

En effet la première est de toute façon affichée (837), la seconde a 139, c'est moins que 837, donc on ne l'affiche pas, pareil pour la troisième (42 < 837). La quatrième a 1235 vues, c'est plus que 837, donc on l'affiche, idem pour la cinquième (2154 > 1235), la dernière a 0 vue, donc on ne l'affiche pas.

Un petit indice :

Utilisez les variables utilisateur (il vous faudra donc une (ou des) requêtes pour initialiser cette (ces) variable(s)).

Si vous y arrivez, essayez ensuite de le faire en utilisant une des deux fonctions que je vous ai présentées plus haut, c'est assez rigolo. ^^

La solution

Vous avez réussi ? Si pas ce n'est pas grave, 50 pompes et on n'en parles plus je comprends parfaitement que ces problèmes soient loin d'être faciles à réaliser, disons que je trouve ça pratique pour se rendre compte qu'il existe des tonnes de façons de faire une requête SQL ! De plus si vous parvenez à les résoudre, vous serez aptes à surmonter la plupart des difficultés que vous rencontrerez lorsque vous programmerez "pour de vrai" ! :)

Voilà la solution :

SET @a := 1; SET @b := 0; SELECT @a := nws_id AS nws_id, @b := nws_nb_vues AS nws_nb_vues FROM t_news WHERE nws_nb_vues > @b;
-- Avec GREATEST:
SET @a := 1; SET @b := 0; SELECT @a := nws_id AS nws_id, @b := nws_nb_vues AS nws_nb_vues FROM t_news WHERE nws_nb_vues = GREATEST(@b, nws_nb_vues);

Encore une fois, ce n'est vraiment pas un problème si vous ne l'avez pas trouvée par vous-mêmes. ;)

En passant, remarquez que la variable @b vaut maintenant le maximum de vues qu'une news peut avoir. :p

Une variante : faites la même chose mais en ordre décroissant. :p

Vous devez obtenir le résultat suivant :

Problème 2 - Résultat attendu pour la variante :p

Good luck ! La solution est juste en dessous. :p

Ici un petit problème se pose : la valeur initiale de @b ne peut pas être 0 mais doit être plus grand que le nombre de vues de la première news (d'où le + 1).

Avec LEAST, il suffit de donner à @b le nombre de vues de la première news. :)

SET @a := 1; SET @b := ( SELECT nws_nb_vues + 1 FROM t_news WHERE nws_id = 1 ); SELECT @a := nws_id AS nws_id, @b := nws_nb_vues AS nws_nb_vues FROM t_news WHERE nws_nb_vues < @b;
SET @a := 1; SET @b := ( SELECT nws_nb_vues FROM t_news WHERE nws_id = 1 ); SELECT @a := nws_id AS nws_id, @b := nws_nb_vues AS nws_nb_vues FROM t_news WHERE nws_nb_vues = LEAST(@b, nws_nb_vues);

Voilà, cette fois-ci @b vaut le plus petit nombre de vues qu'une news possède. :)

J'espère que ça vous a plu, en gros on vient de réinventer les fonctions MIN et MAX que vous connaissiez peut-être déjà, et que vous connaitrez certainement (du moins je l'espère) d'ici le prochain chapitre. :) :p

Un petit résumé de ce chapitre :

  • Les opérateurs de comparaison : =, <=>, <>, <, <=, >, >=

  • SELECT ... FROM ... WHERE ... BETWEEN x AND y;

  • SELECT ... FROM ... WHERE ... IN ( a, b, c, d, ... );

  • SELECT ... FROM ... WHERE ... LIKE 'expression'; ( %: chaine | _: caractère )

  • GREATEST(x, y, z) renvoie le plus grand nombre (ou chaîne de caractères ou date)

  • LEAST(x, y, z) fait la même chose avec le plus petit.

Voilà, ya plus qu'à attendre la suite. :p

Exemple de certificat de réussite
Exemple de certificat de réussite