Aller au menu - Aller au contenu

Icône Filtrer les données avec WHERE

Mise à jour : 29/06/2009
1 063 visites depuis 7 jours, dont 110 sur ce chapitre classé 122/786
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).
Sommaire du chapitre :
Icône du chapitre
Chapitre précédent Sommaire Chapitre suivant

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 :

Code : SQL
1
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) :

Code : SQL
1
SELECT nws_id, YEAR(nws_date) AS annee FROM t_news WHERE annee = 2007;


ERROR 1054 (42S22): Unknown column 'annee' in 'where clause'


La requête suivante par contre est correcte :

Code : SQL
1
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 :

Code : SQL
1
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érateurSignification
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...

Code : SQL
1
2
3
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é. ^^

Code : SQL
1
2
3
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 :

Code : SQL
1
2
3
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 :

Code : SQL
1
2
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 :
Secret (cliquez pour afficher)
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 :

Secret (cliquez pour afficher)
Code : SQL
1
2
3
4
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

Solution au problème



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

Secret (cliquez pour afficher)

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. :)

Code : SQL
1
2
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);


Solution de la variante


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

Q.C.M.

MySQL s'occupe-t-il d'abord du WHERE ou des colonnes entre SELECT et FROM ?
En quoi cela influe-t-il les requêtes SQL ?
Quelle est la différence entre = et <=> ?
Dans LIKE...

Statistiques de réponses au QCM

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
Chapitre précédent Sommaire Chapitre suivant

Partager

7 commentaires pour "Filtrer les données avec WHERE"
Note moyenne : 3.87 / 4 (31 votes)
Pseudo Commentaire
En ligne Talus # Posté le 27/06/2007 à 17:53:03
People are strange
Avatar

Avis : Très bon Validateurs
Flux RSS

Ville : Paris
Pays : France métropolitaine
Études : EFREI

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


J'aime bien le y'a plus qu'a :p

19, car rien ni personne n'est parfait :p
 
Hors ligne dark-lord # Posté le 29/02/2008 à 10:42:33
Avatar

Ville : Metz
Pays : France métropolitaine

Très bon tuto, j'ai tout compris.
Par contre tu aurais pu parler de la clause MATCHES pour les conditions. Certe la fonction est la même que la clause LIKE, mais elle offre des possibilité plus importante que LIKE.
Hors ligne nim65s # Posté le 01/05/2009 à 18:39:58
Avatar

Ville : Toulouse
Pays : France métropolitaine
Études : ENSEEIHT

J'aurais bien mit une très bonne note à ce tuto, mais je me pose la même question que mwsaz et je vois qu'il n'y a toujours pas de réponse :(

Dommage ^^

Image utilisateur
Orangina POWAAAAAAAAAAAAAA
( &Nutella, non mais! )
 
Hors ligne louf404 # Posté le 30/06/2009 à 17:00:11
Avatar

Citation : Shepard
Le problème (mouahah vous allez souffrir ^^ )

:lol: Bizarrement j'ai trouvé la solution du 1er coup en a peine 2 min :-° (d'ailleurs je n'en revient pas :lol: )

Mais ça ne ressemble pas du tout à la solution :
Code : SQL
1
2
SET @var = -1;
SELECT nws_id,nws_nb_vues FROM t_news WHERE @var < @var := nws_nb_vues;

Version décroissante :
Code : SQL
1
2
SET @var = 999999;
SELECT nws_id,nws_nb_vues FROM t_news WHERE @var > @var := nws_nb_vues;

Easy, non ?
Hors ligne BigGy # Posté le 11/07/2011 à 15:28:50
Tadaaaaaa !
Avatar
Flux RSS

Études : IUT Vannes

Je ne comprends pas non plus pourquoi utiliser 2 variables ? SET @b := 0; SELECT nws_id, @b := nws_nb_vues AS nws_nb_vues FROM t_news WHERE nws_nb_vues > @b; aurait parfaitement fait l'affaire non ?

Image utilisateur
 

Voir tous les commentaires