samedi 22 mars 2014

13 - Sélection de données

0 commentaires

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 !!
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
1SELECT 'Hello World !';
2SELECT 3+2;
1SELECT
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.
1SELECT colonne1colonne2, ... 
2FROM nom_table;
Par exemple, si l'on veut sélectionner l'espèce, le nom et le sexe des animaux présents dans la tableAnimal, on utilisera :
1SELECT especenomsexe 
2FROM 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 :
1SELECT * 
2FROM 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 ("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 :
1SELECT * 
2FROM Animal 
3WHERE espece='chien';

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 :
1SELECT * 
2FROM Animal 
3WHERE date_naissance < '2008-01-01'-- Animaux nés avant 2008
4
5SELECT * 
6FROM Animal 
7WHERE 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 :
1SELECT * 
2FROM Animal 
3WHERE espece='chat' 
4    AND sexe='F';
5-- OU
6SELECT * 
7FROM Animal 
8WHERE espece='chat' 
9    && sexe='F';

OR

Sélection des tortues et des perroquets. Je désire donc obtenir les animaux qui sont des tortues OU des perroquets :
1SELECT * 
2FROM Animal 
3WHERE espece='tortue' 
4    OR espece='perroquet';
5-- OU
6SELECT * 
7FROM Animal 
8WHERE espece='tortue' 
9    || espece='perroquet';

NOT

Sélection de tous les animaux femelles sauf les chiennes.
1SELECT * 
2FROM Animal 
3WHERE sexe='F' 
4    AND NOT espece='chien';
5-- OU
6SELECT * 
7FROM Animal 
8WHERE sexe='F' 
9    AND ! espece='chien';

XOR

Sélection des animaux qui sont soit des mâles, soit des perroquets (mais pas les deux) :
1SELECT * 
2FROM Animal 
3WHERE sexe='M' 
4    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 : rougeANDvertORbleu
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 à (rougeANDvert) ORbleu, et le deuxième cas à rougeAND (vertORbleu).
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 !
1SELECT * 
2FROM Animal 
3WHERE date_naissance > '2009-12-31'
4    OR
5    ( espece='chat'
6         AND
7        ( sexe='M'
8            OR
9            ( sexe='F' AND date_naissance < '2007-06-01' )
10        )
11    );

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 :
1SELECT * 
2FROM Animal 
3WHERE nom = NULL-- sélection des animaux sans nom
4
5SELECT * 
6FROM Animal  
7WHERE 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 :
1SELECT * 
2FROM Animal 
3WHERE nom <=> NULL-- sélection des animaux sans nom
4-- OU
5SELECT * 
6FROM Animal 
7WHERE nom IS NULL;
8
9SELECT * 
10FROM Animal 
11WHERE 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
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 :
1SELECT * 
2FROM Animal 
3WHERE espece='chien' 
4ORDER 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.
1SELECT * 
2FROM Animal 
3WHERE espece='chien' 
4    AND nom IS NOT NULL 
5ORDER 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 :
1SELECT * 
2FROM Animal 
3ORDER BY especedate_naissance;
Vous pouvez trier sur autant de colonnes que vous voulez.

Leave a Reply