Comme son nom l'indique, ce chapitre traitera de la sélection et de l'affichage de données.
Au menu :
- syntaxe de la requête
SELECT
(que vous avez déjà croisée il y a quelque temps) ; - sélection de données répondant à certaines conditions ;
- tri des données ;
- élimination des données en double ;
- récupération de seulement une partie des données (uniquement les 10 premières lignes, par exemple).
Motivés ? Alors c'est parti !!!
Syntaxe de SELECT
La requête qui permet de sélectionner et afficher des données s'appelle SELECT
. Nous l'avons déjà un peu utilisée dans le chapitre d'installation, ainsi que pour afficher tout le contenu de la table Animal.
SELECT
permet donc d'afficher des données directement. Des chaînes de caractères, des résultats de calculs, etc.
Exemple
1 2 | SELECT 'Hello World !'; SELECT 3+2; |
SELECT
permet également de sélectionner des données à partir d'une table. Pour cela, il faut ajouter une clause à la commande SELECT
: la clause FROM
, qui définit de quelle structure (dans notre cas, une table) viennent les données.
1 2 | SELECT colonne1, colonne2, ... FROM nom_table; |
Par exemple, si l'on veut sélectionner l'espèce, le nom et le sexe des animaux présents dans la table Animal, on utilisera :
1 2 | SELECT espece, nom, sexe FROM Animal; |
Sélectionner toutes les colonnes
Si vous désirez sélectionner toutes les colonnes, vous pouvez utiliser le caractère * dans votre requête :
1 2 | SELECT * FROM Animal; |
Il est cependant déconseillé d'utiliser SELECT *
trop souvent. Donner explicitement le nom des colonnes dont vous avez besoin présente deux avantages :
- d'une part, vous êtes certains de ce que vous récupérez ;
- d'autre part, vous récupérez uniquement ce dont vous avez vraiment besoin, ce qui permet d'économiser des ressources.
Le désavantage est bien sûr que vous avez plus à écrire, mais le jeu en vaut la chandelle.
Comme vous avez pu le constater, les requêtes SELECT
faites jusqu'à présent sélectionnent toutes les lignes de la table. Or, bien souvent, on ne veut qu'une partie des données. Dans la suite de ce chapitre, nous allons voir ce que nous pouvons ajouter à cette requête SELECT
pour faire des sélections à l'aide de critères.
La clause WHERE
La clause WHERE
("où" en anglais) permet de restreindre les résultats selon des critères de recherche. On peut par exemple vouloir ne sélectionner que les chiens :
1 2 3 | SELECT * FROM Animal WHERE espece='chien'; |
Comme 'chien' est une chaîne de caractères, je dois bien sûr l'entourer de guillemets.
Les opérateurs de comparaison
Les opérateurs de comparaison sont les symboles que l'ont utilise pour définir les critères de recherche (le = dans notre exemple précédent). Huit opérateurs simples peuvent être utilisés.
Opérateur |
Signification |
---|---|
= |
égal |
< |
inférieur |
<= |
inférieur ou égal |
> |
supérieur |
>= |
supérieur ou égal |
<> ou != |
différent |
<=> |
égal (valable pour |
Exemples :
1 2 3 4 5 6 7 | SELECT * FROM Animal WHERE date_naissance < '2008-01-01'; -- Animaux nés avant 2008 SELECT * FROM Animal WHERE espece <> 'chat'; -- Tous les animaux sauf les chats |
Combinaisons de critères
Tout ça c'est bien beau, mais comment faire si on veut les chats et les chiens par exemple ? Faut-il faire deux requêtes ? Non bien sûr, il suffit de combiner les critères. Pour cela, il faut des opérateurs logiques, qui sont au nombre de quatre :
Opérateur |
Symbole |
Signification |
---|---|---|
|
&& |
ET |
|
|| |
OU |
|
OU exclusif |
|
|
! |
NON |
Voici quelques exemples, sûrement plus efficaces qu'un long discours.
AND
Je veux sélectionner toutes les chattes. Je veux donc sélectionner les animaux qui sont à la fois des chats ET des femelles. J'utilise l'opérateur AND
:
1 2 3 4 5 6 7 8 9 | SELECT * FROM Animal WHERE espece='chat' AND sexe='F'; -- OU SELECT * FROM Animal WHERE espece='chat' && sexe='F'; |
OR
Sélection des tortues et des perroquets. Je désire donc obtenir les animaux qui sont des tortues OU des perroquets :
1 2 3 4 5 6 7 8 9 | SELECT * FROM Animal WHERE espece='tortue' OR espece='perroquet'; -- OU SELECT * FROM Animal WHERE espece='tortue' || espece='perroquet'; |
Je vous conseille d'utiliser plutôt OR
que ||
, car dans la majorité des SGBDR (et dans la norme SQL), l'opérateur ||
sert à la concaténation. C'est-à-dire à rassembler plusieurs chaînes de caractères en une seule. Il vaut donc mieux prendre l'habitude d'utiliser OR
, au cas où vous changeriez un jour de SGBDR (ou tout simplement parce que c'est une bonne habitude).
NOT
Sélection de tous les animaux femelles sauf les chiennes.
1 2 3 4 5 6 7 8 9 | SELECT * FROM Animal WHERE sexe='F' AND NOT espece='chien'; -- OU SELECT * FROM Animal WHERE sexe='F' AND ! espece='chien'; |
XOR
Sélection des animaux qui sont soit des mâles, soit des perroquets (mais pas les deux) :
1 2 3 4 | SELECT * FROM Animal WHERE sexe='M' XOR espece='perroquet'; |
Et voilà pour les opérateurs logiques. Rien de bien compliqué, et pourtant, c'est souvent source d'erreur. Pourquoi ? Tout simplement parce que tant que vous n'utilisez qu'un seul opérateur logique, tout va très bien. Mais on a souvent besoin de combiner plus de deux critères, et c'est là que ça se corse.
Sélection complexe
Lorsque vous utilisez plusieurs critères, et que vous devez donc combiner plusieurs opérateurs logiques, il est extrêmement important de bien structurer la requête. En particulier, il faut placer des parenthèses au bon endroit. En effet, cela n'a pas de sens de mettre plusieurs opérateurs logiques différents sur un même niveau.
Petit exemple simple :
Critères : rouge AND
vert OR
bleu
Qu'accepte-t-on ?
- Ce qui est rouge et vert, et ce qui est bleu ?
- Ou ce qui est rouge et, soit vert soit bleu ?
Dans le premier cas, [rouge, vert] et [bleu] seraient acceptés. Dans le deuxième, c'est [rouge, vert] et [rouge, bleu] qui seront acceptés, et non [bleu].
En fait, le premier cas correspond à (rouge AND
vert) OR
bleu, et le deuxième cas à rouge AND
(vert OR
bleu).
Avec des parenthèses, pas moyen de se tromper sur ce qu'on désire sélectionner !
Exercice/Exemple
Alors, imaginons une requête bien tordue…
Je voudrais les animaux qui sont, soit nés après 2009, soit des chats mâles ou femelles, mais dans le cas des femelles, elles doivent être nées avant juin 2007.
Je vous conseille d'essayer d'écrire cette requête tout seuls. Si vous n'y arrivez pas, voici une petite aide : l'astuce, c'est de penser en niveaux. Je vais donc découper ma requête.
Je cherche :
- les animaux nés après 2009 ;
- les chats mâles et femelles (uniquement nées avant juin 2007 pour les femelles).
C'est mon premier niveau. L'opérateur logique sera OR
puisqu'il faut que les animaux répondent à un seul des deux critères pour être sélectionnés.
On continue à découper. Le premier critère ne peut plus être subdivisé, contrairement au deuxième. Je cherche :
- les animaux nés après 2009 ;
- les chats :
- mâles ;
- et femelles nées avant juin 2007.
Et voilà, vous avez bien défini les différents niveaux, il n'y a plus qu'à écrire la requête avec les bons opérateurs logiques !
1 2 3 4 5 6 7 8 9 10 11 | SELECT * FROM Animal WHERE date_naissance > '2009-12-31' OR ( espece='chat' AND ( sexe='M' OR ( sexe='F' AND date_naissance < '2007-06-01' ) ) ); |
Le cas de NULL
Vous vous souvenez sans doute de la liste des opérateurs de comparaison que je vous ai présentée (sinon, retournez au début de la partie sur la clause WHERE
). Vous avez probablement été un peu étonnés de voir dans cette liste l'opérateur <=> : égal (valable aussi pour NULL
). D'autant plus que j'ai fait un peu semblant de rien et ne vous ai pas donné d'explication sur cette mystérieuse précision "aussi valable pour NULL
" . Mais je vais me rattraper maintenant !
En fait, c'est très simple, le marqueur NULL
(qui représente donc "pas de valeur") est un peu particulier. En effet, vous ne pouvez pas tester directement colonne = NULL
. Essayons donc :
1 2 3 4 5 6 7 | SELECT * FROM Animal WHERE nom = NULL; -- sélection des animaux sans nom SELECT * FROM Animal WHERE commentaires <> NULL; -- sélection des animaux pour lesquels un commentaire existe |
Comme vous pouvez vous en douter après ma petite introduction, ces deux requêtes ne renvoient pas les résultats que l'on pourrait espérer. En fait, elles ne renvoient aucun résultat. C'est donc ici qu'intervient notre opérateur de comparaison un peu spécial <=> qui permet de reconnaître NULL
. Une autre possibilité est d'utiliser les mots-clés IS NULL
, et si l'on veut exclure les NULL
: IS NOT NULL
. Nous pouvons donc réécrire nos requêtes, correctement cette fois-ci :
1 2 3 4 5 6 7 8 9 10 11 | SELECT * FROM Animal WHERE nom <=> NULL; -- sélection des animaux sans nom -- OU SELECT * FROM Animal WHERE nom IS NULL; SELECT * FROM Animal WHERE commentaires IS NOT NULL; -- sélection des animaux pour lesquels un commentaire existe |
Cette fois-ci, ça fonctionne parfaitement !
id |
espece |
sexe |
date_naissance |
nom |
commentaires |
---|---|---|---|---|---|
4 |
tortue |
F |
2009-08-03 05:12:00 |
NULL |
NULL |
9 |
tortue |
NULL |
2010-08-23 05:18:00 |
NULL |
NULL |
id |
espece |
sexe |
date_naissance |
nom |
commentaires |
---|---|---|---|---|---|
1 |
chien |
M |
2010-04-05 13:43:00 |
Rox |
Mordille beaucoup |
5 |
chat |
NULL |
2010-10-03 16:44:00 |
Choupi |
Né sans oreille gauche |
6 |
tortue |
F |
2009-06-13 08:17:00 |
Bobosse |
Carapace bizarre |
35 |
chat |
M |
2006-05-19 16:56:00 |
Raccou |
Pas de queue depuis la naissance |
52 |
tortue |
F |
2006-03-15 14:26:00 |
Redbul |
Insomniaque |
55 |
tortue |
M |
2008-03-15 18:45:00 |
Relou |
Surpoids |
Tri des données
Lorsque vous faites un SELECT
, les données sont récupérées dans un ordre défini par MySQL, mais qui n'a aucun sens pour vous. Vous avez sans doute l'impression que MySQL renvoie tout simplement les lignes dans l'ordre dans lequel elles ont été insérées, mais ce n'est pas exactement le cas. En effet, si vous supprimez des lignes, puis en ajoutez de nouvelles, les nouvelles lignes viendront remplacer les anciennes dans l'ordre de MySQL. Or, bien souvent, vous voudrez trier à votre manière. Par date de naissance par exemple, ou bien par espèce, ou par sexe, etc.
Pour trier vos données, c'est très simple, il suffit d'ajouter ORDER BY tri
à votre requête (après les critères de sélection de WHERE
s'il y en a) et de remplacer "tri" par la colonne sur laquelle vous voulez trier vos données bien sûr.
Par exemple, pour trier par date de naissance :
1 2 3 4 | SELECT * FROM Animal WHERE espece='chien' ORDER BY date_naissance; |
Et hop ! Vos données sont triées, les plus vieux chiens sont récupérés en premier, les jeunes à la fin.
Tri ascendant ou descendant
Tout ça c'est bien beau, j'ai mes chiens triés du plus vieux au plus jeune. Et si je veux le contraire ?
Pour déterminer le sens du tri effectué, SQL possède deux mots-clés : ASC
pour ascendant, et DESC
pour descendant. Par défaut, si vous ne précisez rien, c'est un tri ascendant qui est effectué : du plus petit nombre au plus grand, de la date la plus ancienne à la plus récente, et pour les chaînes de caractères et les textes, c'est l'ordre alphabétique normal qui est utilisé.
Si par contre vous utilisez le mot DESC
, l'ordre est inversé : plus grand nombre d'abord, date la plus récente d'abord, et ordre anti-alphabétique pour les caractères.
Petit cas particulier : les ENUM
sont des chaînes de caractères, mais sont triés selon l'ordre dans lequel les possibilités ont été définies. Si par exemple on définit une colonne exemple ENUM('a', 'd', 'c', 'b')
, l'ordre ASC
sera 'a', 'd', 'c' puis 'b' et l'ordre DESC
'b', 'c', 'd' suivi de 'a'.
1 2 3 4 5 | SELECT * FROM Animal WHERE espece='chien' AND nom IS NOT NULL ORDER BY nom DESC; |
Trier sur plusieurs colonnes
Il est également possible de trier sur plusieurs colonnes. Par exemple, si vous voulez que les résultats soient triés par espèce et, dans chaque espèce, triés par date de naissance, il suffit de donner les deux colonnes correspondantes à ORDER BY
:
1 2 3 | SELECT * FROM Animal ORDER BY espece, date_naissance; |
L'ordre dans lequel vous donnez les colonnes est important, le tri se fera d'abord sur la première colonne donnée, puis sur la seconde, etc.
Vous pouvez trier sur autant de colonnes que vous voulez.
Éliminer les doublons
Il peut arriver que MySQL vous donne plusieurs fois le même résultat. Non pas parce que MySQL fait des bêtises, mais tout simplement parce que certaines informations sont présentes plusieurs fois dans la table.
Petit exemple très parlant : vous voulez savoir quelles sont les espèces que vous possédez dans votre élevage. Facile, une petite requête :
1 2 | SELECT espece FROM Animal; |
En effet, vous allez bien récupérer toutes les espèces que vous possédez, mais si vous avez 500 chiens, vous allez récupérer 500 lignes 'chien'. Un peu embêtant lorsque la table devient bien remplie.
Heureusement, il y a une solution : le mot-clé DISTINCT
.
Ce mot-clé se place juste après SELECT
et permet d'éliminer les doublons.
1 2 | SELECT DISTINCT espece FROM Animal; |
Ceci devrait gentiment vous ramener quatre lignes avec les quatre espèces qui se trouvent dans la table. C'est quand même plus clair non ?
Attention cependant, pour éliminer un doublon, il faut que toute la ligne sélectionnée soit égale à une autre ligne du jeu de résultats. Ça peut paraître logique, mais cela en perd plus d'un. Ne seront donc prises en compte que les colonnes que vous avez précisées dans votre SELECT
. Uniquement espece donc, dans notre exemple.
Restreindre les résultats
En plus de restreindre une recherche en lui donnant des critères grâce à la clause WHERE
, il est possible de restreindre le nombre de lignes récupérées.
Cela se fait grâce à la clause LIMIT
.
Syntaxe
LIMIT
s'utilise avec deux paramètres.
- Le nombre de lignes que l'on veut récupérer.
- Le décalage, introduit par le mot-clé
OFFSET
et qui indique à partir de quelle ligne on récupère les résultats. Ce paramètre est facultatif. S'il n'est pas précisé, il est mis à 0.
1 | LIMIT nombre_de_lignes [OFFSET decalage]; |
Exemple :
1 2 3 4 5 6 7 8 9 | SELECT * FROM Animal ORDER BY id LIMIT 6 OFFSET 0; SELECT * FROM Animal ORDER BY id LIMIT 6 OFFSET 3; |
Avec la première requête, vous devriez obtenir six lignes, les six plus petits id puisque nous n'avons demandé aucun décalage (OFFSET 0
).
id |
espece |
sexe |
date_naissance |
nom |
commentaires |
---|---|---|---|---|---|
1 |
chien |
M |
2010-04-05 13:43:00 |
Rox |
Mordille beaucoup |
2 |
chat |
NULL |
2010-03-24 02:23:00 |
Roucky |
NULL |
3 |
chat |
F |
2010-09-13 15:02:00 |
Schtroumpfette |
NULL |
4 |
tortue |
F |
2009-08-03 05:12:00 |
NULL |
NULL |
5 |
chat |
NULL |
2010-10-03 16:44:00 |
Choupi |
Né sans oreille gauche |
6 |
tortue |
F |
2009-06-13 08:17:00 |
Bobosse |
Carapace bizarre |
Par contre, dans la deuxième, vous récupérez toujours six lignes, mais vous devriez commencer au quatrième plus petit id, puisqu'on a demandé un décalage de trois lignes.
id |
espece |
sexe |
date_naissance |
nom |
commentaires |
---|---|---|---|---|---|
4 |
tortue |
F |
2009-08-03 05:12:00 |
NULL |
NULL |
5 |
chat |
NULL |
2010-10-03 16:44:00 |
Choupi |
Né sans oreille gauche |
6 |
tortue |
F |
2009-06-13 08:17:00 |
Bobosse |
Carapace bizarre |
7 |
chien |
F |
2008-12-06 05:18:00 |
Caroline |
NULL |
8 |
chat |
M |
2008-09-11 15:38:00 |
Bagherra |
NULL |
9 |
tortue |
NULL |
2010-08-23 05:18:00 |
NULL |
NULL |
Exemple avec un seul paramètre :
1 2 3 4 | SELECT * FROM Animal ORDER BY id LIMIT 10; |
Cette requête est donc équivalente à :
1 2 3 4 | SELECT * FROM Animal ORDER BY id LIMIT 10 OFFSET 0; |
Syntaxe alternative
MySQL accepte une autre syntaxe pour la clause LIMIT
. Ce n'est cependant pas la norme SQL donc idéalement vous devriez toujours utiliser la syntaxe officielle. Vous vous apercevrez toutefois que cette syntaxe est énormément usitée, je ne pouvais donc pas ne pas la mentionner
1 2 3 4 | SELECT * FROM Animal ORDER BY id LIMIT [decalage, ]nombre_de_lignes; |
Tout comme pour la syntaxe officielle, le décalage n'est pas obligatoire, et vaudra 0 par défaut. Si vous le précisez, n'oubliez pas la virgule entre le décalage et le nombre de lignes désirées.
En résumé
- La commande
SELECT
permet d'afficher des données. - La clause
WHERE
permet de préciser des critères de sélection. - Il est possible de trier les données grâce à
ORDER BY
, selon un ordre ascendant (ASC
) ou descendant (DESC
). - Pour éliminer les doublons, on utilise le mot-clé
DISTINCT
, juste aprèsSELECT
. LIMIT nb_lignes OFFSET decalage
permet de sélectionner uniquement nb_lignes de résultats, avec un certain décalage.