SELECT est la seule commande du SQL permettant d'interroger une base de données. Il existe d'autres commandes pour manipuler les données (ajouter, modifier), manipuler les structures (bases, vues, tables), gérer les utilisateurs et leurs droits, créer des procédures stockées.
Le résultat d'un SELECT est appelé un jeu d'enregistrements (recordset en anglais).
tp_id | tp_usr_id | tp_rep_id | tp_rep | tp_rep_validee | tp_date | tp_commentaire_prof | tp_commentaires_all | tp_nb_post | tp_note | tp_fdg |
1 | 1 | 1 | SELECT NomClt, PrénomClt FROM Client; | 4 | 2009-12-16 15:57:54 | 1 | 1.0 | 0 | ||
1 | 1 | 2 | Select Distinct NumLivre From Emprunt Where Date >= #01/01/97#; - le distinct est nécessaire car un livre peut ?tre emprunté plusieurs fois. - la table "livre" est inutile ici : les champs qu'on teste et qu'on affiche sont présents dans "emprunt". | 4 | 2010-10-14 09:53:50 | 1 | 1.0 | 0 | ||
1 | 1 | 3 | Select NumClt From Emprunt Where NumLivre = 6 And Date <#09/01/97#; | 4 | 2010-10-13 11:22:48 | 1 | 1.0 | 0 | ||
1 | 1 | 4 | Select Titre From Livre, Type Where Livre.NumType = Type.NumType And LibType = "roman"; | 4 | 2009-10-23 17:57:56 | 1 | 1.0 | 0 | ||
1 | 1 | 5 | Select Titre From Livre, Type, Auteur Where Livre.NumType = Type.NumType and Livre.NumAuteur = Auteur.NumAuteur And LibType = 'roman' and NomAuteur = "Pennac" Erreurs fréquentes : - Vérifier que le type est bien "Roman". | 4 | 2010-10-13 11:24:23 | 1 | 1.0 | 0 | ||
1 | 1 | 6 | Select distinct Client.* From Client, Emprunt, Livre, Type Where Client.NumClt = Emprunt.NumClt And Emprunt.NumLivre=Livre.NumLivre And Livre.NumType = Type.NumType And LibType = "Science-fiction"; Erreurs courantes : - distinct obligatoire car un client a pu emprunter plusieurs livres de science-fiction, il appara?tra plusieurs fois. - select simplifiable gr?ce ? "client.*" | 4 | 2010-10-20 10:50:27 | 1 | 1.0 | 0 | ||
1 | 1 | 7 | Select Distinct Titre From Client, Emprunt, Livre, Type Where Client.NumClt = Emprunt.NumClt And Emprunt.NumLivre=Livre.NumLivre And Livre.NumType = Type.NumType And LibType = "Roman" And NomClt = "DURAND" And PrénomClt = "Marc"; - Distinct obligatoire car Marc Durand a pu emprunter plusieurs fois le m?me roman. - Vérifier qu'il s'agisse bien d'un roman. | 4 | 2010-10-14 10:40:35 | 1 | 1.0 | 0 | ||
1 | 1 | 8 | Select Distinct Client.* From Client, Emprunt, Livre, Type, Auteur Where Client.NumClt = Emprunt.NumClt And Emprunt.NumLivre=Livre.NumLivre And Livre.NumType = Type.NumType And Livre.NumAuteur = Auteur.NumAuteur And NomAuteur = "William H. Gates" And LibType = "Essai"; - Vérifier que le libType est bien "essai". - Select simplifiable gr?ce ? "client.*" | 4 | 2010-10-13 11:47:26 | 1 | 1.0 | 0 | ||
1 | 1 | 9 | Select * from Auteur Where NumAuteur Not In (Select NumAuteur from Livre Where NumType = 2); Erreur fréquente : - La requ?te imbriquée nécessite qu'une seule table. | 4 | 2010-10-19 11:26:28 | 1 | 1.0 | 0 | ||
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
A partir du schéma relationnel ci-dessus, représentant la base d'un vendeur de logiciels (et qui va nous accompagner tout au long de ce cours), affichez l'ensemble de la table Produit.
Au lieu d'afficher toutes les colonnes (ou champs), on veut afficher uniquement le nom et le prénom (c'est à dire les colonnes qui ont été coloriées en orange sur le schéma ci-dessous).
usr_id | usr_name | usr_first_name | usr_login | usr_password | usr_year_study | ... |
1 | PASTORE | Sébastien | spastore | *********** | 6 | |
540 | DETEST | Ysser | testeleve1 | *********** | 1 | |
539 | DUBUISSON | Christophe | cdubuisson | *********** | 2 | |
538 | BONVALOT | Romain | rbonvalot | *********** | 2 | |
537 | LUCK | Florent | fluck | *********** | 1 | |
536 | TRAN | Alexandre | atran | *********** | 2 | |
534 | ESQUIROL | Georges | gesquirol | *********** | 6 | |
533 | LEGRAND | Marie-Pierre | mplegrand | *********** | 6 | |
532 | TEXTORIS | André | atextoris | *********** | 6 | |
... |
On utilise pour ça la requête suivante :
usr_first_name | usr_name |
Sébastien | Pastore |
Ysser | Detest |
Christophe | Dubuisson |
Romain | Bonvalot |
Florent | Luck |
Alexandre | Tran |
Georges | Esquirol |
Abdellatif | HSAINI |
Rémi | Fort |
... | ... |
A partir de la base "vendeur de logiciels", affichez le nom et le prénom des clients.
Très utile pour clarifier l'affichage ou exploiter les données dans un langage de programmation :
Prenom | Nom |
Sébastien | Pastore |
Ysser | Detest |
Christophe | Dubuisson |
Romain | Bonvalot |
Florent | Luck |
Alexandre | Tran |
Georges | Esquirol |
Abdellatif | HSAINI |
Rémi | Fort |
... | ... |
Le AS est facultatif, on peut donc écrire :
Prénom | Nom |
Sébastien | Pastore |
Ysser | Detest |
Christophe | Dubuisson |
Romain | Bonvalot |
Florent | Luck |
Alexandre | Tran |
Georges | Esquirol |
Abdellatif | HSAINI |
Rémi | Fort |
... | ... |
A partir de la base "vendeur de logiciels", affichez le nom et le prénom des clients, en les renommant sans le C final.
Au lieu d'afficher tous les enregistrements (ou
lignes), on veut afficher uniquement les utilisateurs qui s'appellent
Romain (en orange sur la capture
ci-dessous).
usr_id | usr_name | usr_first_name | usr_login | usr_password | usr_year_study | ... |
1 | PASTORE | Sébastien | spastore | *********** | 6 | |
540 | DETEST | Ysser | testeleve1 | *********** | 1 | |
539 | DUBUISSON | Christophe | cdubuisson | *********** | 2 | |
538 | BONVALOT | Romain | rbonvalot | *********** | 2 | |
537 | LUCK | Florent | fluck | *********** | 1 | |
536 | TRAN | Alexandre | atran | *********** | 2 | |
534 | ESQUIROL | Georges | gesquirol | *********** | 6 | |
533 | LEGRAND | Marie-Pierre | mplegrand | *********** | 6 | |
532 | TEXTORIS | André | atextoris | *********** | 6 | |
... |
On utilise pour ça la clause WHERE :
Prenom | Nom |
Romain | Bonvalot |
Romain | Dumas |
Romain | Di Felice |
Romain | Barial |
Romain | Viala |
Romain | Constant |
Romain | Sicaud |
Romain | Vanderhaeghen |
Romain | Chaix |
Romain | Boehler |
Romain | Dutoit |
Romain | Vaudron |
La condition WHERE est suivie de n'importe quelle expression booléenne, c'est à dire qui a pour résultat "vrai" ou "faux". Par exemple :
Une erreur fréquente, chez les débutants, est de séparer les conditions par une virgule. Ceci ne marche pas :
A partir de la base "vendeur de logiciels", affichez les clients qui habitent Avignon.
Affichez les produits de catégorie n°5.
Pour que les résultats soient triés, on utilise la clause ORDER BY, et les paramètres ASC (pour un tri croissant, ascendant en anglais) ou DESC (pour un tri décroissant, descendant en anglais). Par exemple :
Prenom | Nom |
Isis | Abd Rabo |
Chakib | Abdallah |
Malik | Abdesslem |
Shakir | ABDOUSSI |
Faycel | ABERKAN |
Olivier | Abran |
Morad | Achachera |
Mimouna | Adda-Benameur |
Ophélie | Adolphe |
... | ... |
Prenom | Nom |
Xinyu | Zhao |
Yassin | ZBLAH |
Nordine | Zarqane |
Florent | Zamuner |
Paul | ZAGACKI |
Detest | Ysser |
Ibrahim | Yildirim |
Anthony | Xueref |
Dylan | WUCHER |
... | ... |
Le tri par défaut est croissant, on n'est donc pas obligé de préciser ASC. Par exemple :
Prenom | Nom |
Isis | Abd Rabo |
Chakib | Abdallah |
Malik | Abdesslem |
Shakir | ABDOUSSI |
Faycel | ABERKAN |
Olivier | Abran |
Morad | Achachera |
Mimouna | Adda-Benameur |
Ophélie | Adolphe |
... | ... |
Cela revient au même de trier sur le nom original du champ (usr_name), sur le nom renommé (Nom) ou sur la position du champ dans le SELECT (2).
On peut enchaîner plusieurs tris. Par exemple : utilisateurs nés en février, triés sur la date d'anniversaire. Pour ceux qui sont nés le même jour, on veut un classement par nom :
Date d'anniversaire | Prenom | Nom |
20/2 | Arnaud | Taelman |
21/2 | Renaud | Deville |
21/2 | Sébastien | Noguera |
22/2 | Cynthia | Robin |
23/2 | Juliette | Barnaud |
23/2 | Cyril | Covin |
24/2 | Lucas | BIANCIOTTO |
25/2 | Yannis | Barembaum |
25/2 | Sébastien | Pastore |
... | ... | ... |
A partir de la base "vendeur de logiciels", affichez les produits triés par nom de produit.
Affichez les clients triés par ville. Dans une même ville, les clients sont triés par nom, puis par prénom s'il y a des noms identiques.
Si je regarde la table des petites annonces, je vois qu'il n'y figure que le numéro de l'utilisateur qui a déposé l'annonce, mais pas son nom ni son prénom. C'est normal : si on stockait son nom et son prénom pour chaque petite annonce, on l'aurait en plusieurs exemplaires. C'est ce qu'on appelle la redondance, et on essaie la plupart du temps de l'éviter dans les bases de données (ça fait perdre de la mémoire et ça rend les mises à jour plus difficiles).
ann_id | ann_user_id | ann_titre | ann_prix | ann_texte | ann_is_html | ann_date_depot |
204 | 442 | <script>alert('Je suis un boulet')</script> | test | test | 0 | 2015-01-27 00:16:27 |
206 | 401 | Vend ordinateur | 150€ | Je vend un ordinateur fixe de la marque HP, possède un lecteur de carte mémoire, 3 port USB frontaux et 6 a l'arrière, lecteur CD/DVD, écran, clavier, souris et son tapis inclus. Vous pouvez le tester en Salle C352, c'est celui au fond à coté de la fenêtre. | 0 | 2015-10-27 12:22:56 |
208 | 538 | Echange magnet père dodu | 0€ | Je cherche à échanger un magnet Martinique que j'ai déjà contre un de vos doubles | 0 | 2017-03-28 20:33:13 |
209 | 482 | Hello ! | Je donne 10 000€ | Bonjour, je n'ai pas un mot de passe sensible à la casse. Du coup, on m'a piraté mon compte, changé l'adresse mail, le mdp, je ne peux donc pas retrouver mon compte. Je demande donc à celui qui a hacké mon compte de me donner le mdp merci ! | 1 | 2017-04-07 11:31:34 |
Toutefois, je peux afficher cette information puisque le nom et le prénom sont stockés dans la table user, et que ces deux tables sont reliées par le numéro de l'utilisateur qui a déposé l'annonce :
usr_id | usr_first_name | usr_name | ann_user_id | ann_titre |
442 | Steeven | Thein | 442 | <script>alert('Je suis un boulet')</script> |
401 | Florent | Valay | 401 | Vend ordinateur |
538 | Adrien | Guillermet | 538 | Echange magnet père dodu |
482 | Pierrick | Delamotte | 482 | Hello ! |
Notez bien l'importance du WHERE usr_id = ann_user_id
.
Si vous l'oubliez, vous obtenez des résultats incohérents (remarquez
que chaque annonce a été affichée à côté de chaque utilisateur : SQL a
fait toutes les combinaisons possibles, c'est ce qu'on appelle un produit
cartésien et c'est rarement ce qu'on souhaite) :
usr_id | usr_first_name | usr_name | ann_user_id | ann_titre |
1 | Sébastien | Pastore | 442 | <script>alert('Je suis un boulet')</script> |
1 | Sébastien | Pastore | 401 | Vend ordinateur |
1 | Sébastien | Pastore | 538 | Echange magnet père dodu |
1 | Sébastien | Pastore | 482 | Hello ! |
77 | Ysser | Detest | 442 | <script>alert('Je suis un boulet')</script> |
77 | Ysser | Detest | 401 | Vend ordinateur |
77 | Ysser | Detest | 538 | Echange magnet père dodu |
77 | Ysser | Detest | 482 | Hello ! |
76 | Christophe | Dubuisson | 442 | <script>alert('Je suis un boulet')</script> |
... | ... | ... | ... | ... |
A partir de la base "vendeur de logiciels", affichez les noms des produits, suivi du nom de la catégorie correspondante (jointure avec deux tables).
Affichez les noms et prénoms des clients, suivi des noms des produits qu'ils ont achetés (jointure avec trois tables).
Parfois, on est susceptible d'écrire une requête qui répond plusieurs fois la même réponse. Par exemple : qui a déjà déposé un commentaire sur les TP ?
Nom |
Terence RENARD |
Terence RENARD |
Terence RENARD |
Terence RENARD |
Terence RENARD |
Loïc BEGUE |
Thomas RIVIERE |
Dylan PISTACHI |
Dylan PISTACHI |
... |
Pour éviter que la même réponse soit donnée deux fois, on utilise la clause DISTINCT.
usr_id | Nom |
860 | Terence RENARD |
837 | Loïc BEGUE |
796 | Thomas RIVIERE |
690 | Dylan PISTACHI |
684 | Mathieu THIVENT |
680 | Fabien RUSSO |
679 | Steven ROBERT |
676 | Florian MARI |
674 | Dorian JOURDE |
... | ... |
Il faut arriver à savoir quand le DISTINCT est obligatoire ou non, sinon vous serez pénalisés à l'examen. Essayez donc d'évaluer si la requête risque de multiplier les résultats ou pas. Par exemple :
Écrivez les requêtes SQL suivantes en vous demandant, à chaque fois, si le DISTINCT est nécessaire ou pas.
Dans quelles villes y a-t-il des clients ?
A quelle catégorie appartient le produit Firefox ?.
Quelles sont les catégories des produits achetés par Alexandre SUSEC (testez : vous devez obtenir 4 réponses) ?
On peut affecter une valeur spéciale à un champ : la valeur NULL.
A ne pas confondre avec une chaîne de caractères vide :
champ=""
, une valeur NULL se teste avec champ IS NULL
. Une chaîne non vide se teste avec champ <> ""
, une valeur non nulle se teste avec champ IS NOT NULL
.Quand on construit une base de données, on doit préciser pour chaque champ s'il peut recevoir la valeur NULL ou pas démonstration.
Afficher les clients (nom et prénom) dont on ne connaît pas la ville (testez : vous devez obtenir trois réponses).
On n'est pas obligé d'afficher des champs bruts, on peut afficher des expressions basées (ou non) sur les champs.
Une que j'utilise souvent est pour améliorer l'affichage du nom et du prénom :
Nom |
Sébastien Pastore |
Georges Esquirol |
Alexa Strozzi |
Gilles Girard |
Florian Ballesta |
Xinyu Zhao |
Thierry JURAIN |
Thomas SCULFORT |
Paul ZAGACKI |
Arsène FATH |
Afficher l'année de naissance d'une personne (remarquez le IS NOT NULL qui permet de n'afficher que les utilisateurs dont on connaît la date de naissance) :
usr_login | annee de naissance |
kbouhamed | 2004 |
ubiagetti | 2005 |
mabitton | 2004 |
hbajdikh | 2005 |
sbouimouh | 2004 |
jcatalin | 2004 |
ncharnet | 2005 |
schiarelli | 2003 |
mchouhani | 2004 |
... | ... |
Afficher un prix TTC à partir d'un prix hors taxe : SELECT prix_HT * 1.2 FROM produits ;
Afficher le numéro des produits et le mois auquel ils ont été achetés.
Afficher le nom et le prénom des clients dans une seule colonne, séparés par un espace.
Parfois, on a besoin d'utiliser SELECT simplement pour évaluer une expression, sans aller chercher des données dans une table.
L'utilisation la plus courante est pour vérifier le fonctionnement des fonctions SQL. Par exemple, pour vérifier des fonctions de date ou de cryptage :
CURDATE() |
2023-10-01 |
NOW() |
2023-10-01 06:23:07 |
SHA1('mypassword') |
91dfd9ddb4198affc5c194cd8ce6d338fde470e2 |
Très utile pour les recherches, LIKE permet de comparer des chaînes entre elles en utilisant des caractères jokers, c'est à dire des caractères qui remplacent un ou plusieurs caractères.
% remplace 0, 1 ou plusieurs caractères. Par exemple :
champ like "méd%"
est vrai pour les champs ayant la valeur méd, médecin, médical, médée, etc.champ like "%test%"
est vrai pour les champs ayant la valeur greatest hits, test, contest, testament, etc. Très utile pour des recherches simples._ (appelé l'underscore, sous la touche 8 du clavier) remplace 1 caractère. Par exemple :
champ like "par_"
est vrai pour les champs ayant la valeur part, pars, pare, etc.champ like "199_-12-31"
est vrai pour les champs ayant la valeur 1990-12-31, 1991-12-31, ... 1999-12-31.Pour compliquer un peu : sous Access, le % s'écrit * et le _ s'écrit ? (respectant ainsi le formalisme des caractères jokers sous MS-DOS, et dans l'explorateur de fichiers en général).