• Facile

Mis à jour le 21/11/2013

Les conditions

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

Les conditions SQL ne sont pas forcément importantes pour l'optimisation mais sont extrêmement pratiques pour obtenir des données tirées d'autres données très rapidement. Elles permettent de renvoyer une valeur si une expression est vraie, ou une autre valeur si elle est fausse...

Enfin, je vous laisse découvrir ça, vous vous rendrez vite compte de leur utilité. ;) :)

Des conditions en SQL ? Différences entre MySQL et la norme

La norme SQL prévoit ce qu'on appelle des structures conditionnelles qui permettent de dire "SI telle valeur vaut ça, faire ça, sinon si cette valeur vaut ça, faire ça, sinon faire ça".

Ce n'est bien sûr qu'un exemple, mais c'est le principe. Une structure conditionnelle permet d'énoncer... Des conditions. :p

Dans MySQL, il existe 4 structures conditionnelles :

  • CASE

  • NULLIF

  • IF

  • IFNULL

Les deux dernières structures peuvent très facilement être obtenues à partir des deux premières et sont plus limitées. En fait, elles sont spécifiques à MySQL et n'existent pas dans la norme.

Il est notamment déconseillé d'utiliser IF car si un jour vous passez à PostGreSQL (par exemple), vous allez devoir restructurer toutes vos requêtes... :(

IFNULL, même s'il n'est pas repris par la norme, est implémenté dans la plupart des SGBDR (notamment MySQL, PostGreSQL et SQL Server), cela est donc moins grave si vous l'utilisez, mais c'est déconseillé quand même...

Utilisation de CASE

CASE est la structure conditionnelle la plus répandue parmis les SGBDR. Et c'est également la plus complète ! Les autres structures sont toutes dérivées de celle-ci.
Pour toutes les structures conditionnelles suivantes, je vous montrerais à chaque fois le rapport entre la structure et CASE.

Bon alors comment on l'utilise, ce CASE ?

C'est assez simple, voici tout d'abord une structure générale :

CASE [colonne]
WHEN condition THEN valeur
WHEN condition THEN valeur
[...]
ELSE valeur
END

Bon, peut-être qu'à première vue, comme ça, ça ne vous parle pas trop, mais avec les exemples ça rentrera tout seul. ;) :)

Voici un premier exemple :

SELECT @a, CASE
WHEN @a > 0 THEN 'positif'
WHEN @a < 0 THEN 'negatif'
WHEN @a = 0 THEN 'nul'
ELSE 'NULL'
END AS signe_a;
SET @a = -5;
SELECT @a, CASE
WHEN @a > 0 THEN 'positif'
WHEN @a < 0 THEN 'negatif'
WHEN @a = 0 THEN 'nul'
ELSE 'NULL'
END AS signe_a;
Image utilisateur

Je crois que l'exemple se passe de commentaire : le code veut dire ce qu'il veut dire. :p

Imaginons maintenant un autre cas : on fait un script de news et on a une colonne dans la table des news qui s'appelle 'validee' et qui indique si la news a été validée par un admin ou pas.

Dans le panel d'administration, on affiche toutes les news dans un tableau, et dans la colonne "Validée ?", on aimerait indiquer "validée", ou "en attente de validation" plutôt que 0 ou 1...

Rien de plus simple avec CASE ! Voici une table fictive :

CREATE TABLE news (
id int NOT NULL AUTO_INCREMENT,
titre varchar(100) NOT NULL,
validee tinyint NOT NULL DEFAULT 0,
PRIMARY KEY(id)
);
INSERT INTO news (titre, validee) VALUES ('news 1', 1);
INSERT INTO news (titre, validee) VALUES ('news 2', 0);
INSERT INTO news (titre, validee) VALUES ('news 3', 0);
INSERT INTO news (titre, validee) VALUES ('news 4', 2);
INSERT INTO news (titre, validee) VALUES ('news 5', 1);
INSERT INTO news (titre, validee) VALUES ('news 6', 0);

Essayez de trouver une requête qui renverra :

  • L'id de la news

  • Le titre de la news

  • Si la colonne validee vaut 1, 'Validee', si la colonne vaut 0, 'En attente de validation', sinon 'Etat inconnu' dans une colonne nommée validee_txt

Quand vous penserez avoir trouvé la requête, comparez votre code au mien :

SELECT id, titre, CASE WHEN validee = 1 THEN 'Validee' WHEN validee = 0 THEN 'En attente de validation' ELSE 'Etat inconnu' END AS validee_txt FROM news;

Bon, normalement c'était pas trop dur. :D

Oui mais attend, tantôt en nous montrant la structure de base, j'ai vu qu'elle commençait comme ça : CASE [colonne] WHEN ... A quoi correspond ce [colonne] ?

Bien vu, en fait l'exemple que je viens de vous montrer peut être simplifié grâce à ce [colonne]. Comme un exemple vaut mieux qu'un long discours, voici le code qu'on aurait pu aussi utiliser :

SELECT id, titre, CASE validee WHEN 1 THEN 'Validee' WHEN 0 THEN 'En attente de validation' ELSE 'Etat inconnu' END AS validee_txt FROM news;
Image utilisateur

Pratique aussi non ? Le seul problème avec cette syntaxe c'est qu'elle ne s'applique pas à tous les cas, par exemple notre premier exemple (savoir si @a était positif, négatif, nul (0) ou NULL) ne pourrait utiliser cette syntaxe car on ne peut pas mettre le signe ">" ou "<".

Vous suivez toujours ? Tant mieux parce qu'on a fait le plus dur. :D :p

Les autres structures conditionnelles

Comme je vous l'ai dit, il existe trois autres structures conditionnelles en dehors de CASE en MySQL : IF, NULLIF et IFNULL.

Nous avons déjà vu l'utilité de IFNULL mais je vais en reparler juste pour vous montrer le lien avec CASE et la facilité de ce dernier.

Une alternative simplifiée : IF

IF est en fait une fonction. Voici comment on l'utilise :

SELECT IF(condition, operation_si_vrai, operation_si_faux);

Comme vous le constatez, IF est beaucoup plus limité que CASE, voici comment on pourrait reproduire IF dans un CASE :

SELECT CASE WHEN condition THEN operation_si_vrai ELSE operation_si_faux END;

Vous vous souvenez de ce qu'on a vu au chapitre précédent ? La table ex_null qui contenait des scores ou NULL si le joueur n'avait joué aucune partie...

Et bien le IF se prête bien à cette situation, nous avions utilisé cette requête :

SELECT id, COALESCE(IFNULL(points, 0) / COALESCE(points, 1), 1) AS a_deja_joue FROM ex_null;
Image utilisateur

Et bien avec le IF, voici ce qui suffirait :

SELECT id, IF(points IS NULL, 0, 1) AS a_deja_joue FROM ex_null;

On peut même l'améliorer en mettant oui / non à la place de 1 / 0. :)

SELECT id, IF(points IS NULL, 'non', 'oui') AS a_deja_joue FROM ex_null;
Image utilisateur

Comme vous le voyez, c'est beaucoup plus pratique et plus simple que notre solution à base de COALESCE / IFNULL. :D :p

NULLIF

SELECT NULLIF(expr1, expr2) AS resultat;

SI expr1 = expr2 ALORS resultat vaudra NULL
SINON resultat vaudra expr1.

Avec CASE :

SELECT CASE WHEN expr1 = expr2 THEN NULL ELSE expr1 END AS resultat;

Bon, en fait l'utilité de cette fonction est assez... réduite. :-° Rarissimes sont les cas où elle vous servira, donc je ne détaille pas. ^^

IFNULL

On a déjà vu l'utilité de cette fonction, qui s'utilise comme cela :

SELECT IFNULL(expr1, expr2) AS resultat;

SI expr1 est NULL ALORS renvoyer expr2
SINON renvoyer expr1

Avec CASE :

SELECT CASE WHEN expr1 IS NULL THEN expr2 ELSE expr1 END AS resultat;

Personnellement, je trouve cette fonction tout autant inutile que la précédente, dans la plupart des cas, un CASE (voir même un IF, comme nous l'avons vu) fait parfaitement l'affaire !

Si j'étais vous, je n'encombrerais pas mon cerveau des deux dernières fonctions (NULLIF et IFNULL)...

[Problème SQL] Somme des nombres si leur nombre correspond à un nombre...

Voici le premier problème SQL que je vous propose, d'autres suivront, en fait un problème SQL ressemble à un mini-TP sauf qu'un mini-TP vous servira peut-être un jour, tandis que les problèmes sont totalement loufoques et ne vous serviront certainement jamais. :D

J'espère que vous trouvez le titre accrocheur. o_O

Voici le problème : on a une table de 7 colonnes dont une "id" :

CREATE TABLE probleme1 (
id int NOT NULL AUTO_INCREMENT,
i1 int DEFAULT NULL,
i2 int DEFAULT NULL,
i3 int DEFAULT NULL,
i4 int DEFAULT NULL,
i5 int DEFAULT NULL,
i6 int DEFAULT NULL,
PRIMARY KEY(id)
);
INSERT INTO probleme1 (i1, i2, i3, i4, i5, i6) VALUES
(NULL, NULL, 5, NULL, 4, 3),
(3, NULL, NULL, 8, NULL, NULL),
(NULL, NULL, NULL, NULL, 5, 6),
(NULL, NULL, NULL, NULL, NULL, NULL),
(8, -4, 3, NULL, NULL, NULL),
(1, 1, 1, 1, 1, 1),
(9, NULL, 2, NULL, NULL, 0),
(-8, 2, -1, NULL, 4, 1),
(-1, 1, -1, 1, -1, 1),
(0, 0, 0, NULL, NULL, 0);

On veut obtenir :

  • Une colonne id contenant simplement l'id de la ligne.

  • Une colonne somme contenant la somme des colonnes i1, i2, i3, i4, i5 et i6 ou NULL lorsque toutes ces colonnes valent NULL.

  • Une colonne nb_cols qui contiendra le nombre de colonnes non-nulles.

  • Les colonnes i1 à i6.

Voici ce que vous devriez arriver à obtenir :

Image utilisateur

SELECT
id, @somme := CASE
WHEN (((((i1 + 1 OR i2 + 1) OR i3 + 1) OR i4 + 1) OR i5 + 1) OR i6 + 1) IS NULL THEN 'NULL'
ELSE COALESCE(i1, 0) + COALESCE(i2, 0) + COALESCE(i3, 0) + COALESCE(i4, 0) + COALESCE(i5, 0) + COALESCE(i6, 0) END AS somme,
6 + @somme - COALESCE(i1, 1) - COALESCE(i2, 1) - COALESCE(i3, 1) - COALESCE(i4, 1) - COALESCE(i5, 1) - COALESCE(i6, 1) AS nb_cols,
i1, i2, i3, i4, i5, i6
FROM probleme1;

:waw:

Bien sûr, il serait tout à fait surprenant que vous ayez trouvé exactement le même que moi, mais ce qui compte pour le moment, c'est que ça fonctionne, pas que ce soit optimisé et supersonique ! :p Ma requête est de votre niveau, mais sachez qu'il existe d'autres façons de faire encore plus rapides et pratiques ! Mais notre niveau n'est pas encore assez élevé pour ce type de requêtes et on s'en tiendra à la mienne pour le moment. :p
Si vous n'avez pas la même requête que moi c'est normal, mais essayez de comprendre la mienne, c'est important !

Comme vous le constatez, les structures et fonctions conditionnelles de MySQL permettent d'éviter facilement du traitement du côté de PHP. Toutefois, il ne faut pas non plus utiliser les conditions pour tout et n'importe quoi, certains traitements sont plus rapides du côté de PHP que du côté de MySQL, mais en général le mieux est de les faire du côté de SQL qui a l'avantage de mettre en cache les résultats des requêtes souvent appelées, contrairement à PHP. :)

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