Sélection de données

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 NULL aussi)

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

AND

&&

ET

OR

||

OU

XOR

OU exclusif

NOT

!

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ès SELECT.
  • LIMIT nb_lignes OFFSET decalage permet de sélectionner uniquement nb_lignes de résultats, avec un certain décalage.