Vous êtes sur la page 1sur 16

Les bases de MySQL

Conseils avant de commencer


Il est conseill de raliser soi-mme les exemples qui sont donns dans le cours. Cela suppose vidment que MySQL soit install sur votre machine: soit avec EasyPhp (MySQL 4), soit en allant chercher la dernire version sur le site de MySQL (MySQL 5). Et que MySQL soit lanc. Deux solutions pour mettre en oeuvre MySQL sur votre pc: - soit vous utilisez la fentre SQL qu'offre l'interface d'EasyPhp (clic droit sur l'icne EasyPhp > Administration > Gestion BDD > Slection d'une base > Onglet SQL), - soit vous utilisez le shell window (menu Dmarrer > Excuter > cmd.exe > cd C:\Program Files\EasyPhp1-8 > cd mysql\bin > mysql -u root -p > Password (rien). Si vous avez directement install la dernire version MySQL 5, il suffit pour ouvrir le shell d'aller dans le menu Dmarrer > Programme > MySQL > MySQL 5.0 > MySQL Command Line Client. Afin de sauvegarder vos exemples, prenez l'habitude d'crire vos requtes MySQL l'intrieur d'un fichier texte auquel vous donnerez une extension .sql pour le distinguer des autres et que vous appelerez dans le shell l'aide de la commande suivante: source monFichier.sql Par ailleurs ce cours ne revient pas sur la modlisation des bases de donnes. Celle-ci est considre comme acquise.

1. Types de donnes MySQL


Principaux types de donnes SQL

Type
CHAR(n) INTEGER VARCHAR(n) DECIMAL(m,n) DATE TIME DATETIME TEXT

Description Chaine de longueur fixe gale n caractres. Entier. Chaine de longueur maximale n. Numrique sur m chiffres avec n dcimales. Date avec le jour, le mois, l'anne. Horaire avec heures, minutes, secondes. Date et horaire runis (non ANSI) Texte de longueur quelconque (non ANSI)

1.1 Types numriques exacts et flottants


INTEGER [ZEROFILL] [UNSIGNED] DECIMAL (m,n) [ZEROFILL]

Les types numriques exacts sont ceux dont la prcision est dtermine l'avance comme INTEGER et DECIMAL. Ils acceptent l'option ZEROFILL qui permet de remplir avec des 0 l'espace restant. Le type UNSIGNED permet d'interdire les nombres ngatifs (en supprimant le bit de signe).

Le type DECIMAL permet de spcifier le nombre de chiffres avant et aprs la virgule mais il n'admet par l'option UNSIGNED.
FLOAT [(m,n)] [ZEROFILL]

Les numriques flottants en revanche ont une prsentation propre la machine: FLOAT correspond aux flottants en simple prcision. DOUBLE correspond aux flottants en double prcision.

1.2 Caratres et chanes de caractres


CHAR(m) [BINARY] VARCHAR(m) [BINARY]

Les chanes de caractres peuvent tre stockes dans les deux types: CHAR qui spcifie un nombre de caractres fixe infrieur 255 et VARCHAR qui spcifie un nombre de caractres maximal infrieur 65535. L'option BINARY permet les comparaisons de chaine prenant en compte la casse.
TEXT et BLOB permettent de rpondre la problmatique des chaines qui contiennent plus de 65535 caractres. TEXT ne prend pas en compte la casse contrairement BLOB.

Ces deux derniers types ne sont pas conformes la norme ANSI. Posez-vous toujours la question, avant de les utiliser, de savoir si vous avez rellement besoin de disposer de chanes de plus de 65535 caractres (soit l'quivalent de 40 pages standards).

1.3 Dates
Les dates de type DATE sont stockes selon le format AAAA-MM-JJ. Le type TIME stocke les informations d'heure de la manire suivante: HH:MM:SS. Quant au format DATETIME, il permet de combiner les deux prcdents avec un format du type: AAAA-MM-JJ HH:MM:SS. Seul le type DATE est conforme au standard SQL.

1.4 Les types ENUM et SET


ENUM (valeur1, valeur2, valeur3, ...) SET (valeur1, valeur2, valeur3, ...)

Les types ENUM et SET sont spcifiques MySQL. Ils permettent d'numrer la liste des valeurs disponibles pour un champ (jusqu' 65535 valeurs). SET (contrairement ENUM) autorise le choix de plusieurs valeurs la fois au sein de la liste. Ces types peuvent rendre service pour des champs admettant peu d'options dont vous tes sr qu'elles n'volueront pas. Par exemple: sexe ENUM ("Femme", "Homme") Peu de chance qu'une troisime option se prsente avant un certain temps.

2. Cration d'une table et contraintes associes 2.1 Crer une table


La syntaxe pour crer une table est des plus simple.
CREATE TABLE nom_table (nom_colonne type [DEFAULT valeur_defaut] [NOT NULL], nom_colonne type [DEFAULT valeur_defaut] [NOT NULL], ....);

Exemple:
CREATE TABLE batiment (id INTEGER NOT NULL, nom VARCHAR (100) NOT NULL, annee INTEGER DEFAULT 1900, adresse VARCHAR (100), architecte VARCHAR (100) NOT NULL);

La syntaxe est assez simple comprendre: il faut donner un nom chaque champs, le typer, et prciser un certains nombre de contraintes s'il y a lieu.

2.2 Dfinir des contraintes


Afin d'assurer l'intgrit de la base dans laquelle se trouve une table, on peut soumettre une table un certain nombre de contraintes. Les plus classiques sont les suivantes: - un champ doit toujours possder une valeur. - un champ sert de clef primaire la table. - un champ sert de clef trangre: il fait dans ce cas rfrence la clef primaire d'une autre table. - un champ doit tre unique dans une table. - un champ n'accepte que certaines valeurs.

2.2.1 Possder une valeur: NOT NULL et DEFAULT


Cette contrainte oblige toujours indiquer une valeur pour ce champ. DEFAULT permet de poser la mme contrainte en indiquant la valeur affecter par dfaut. Cette contrainte oblige toujours indiquer une valeur pour ce champ. DEFAULT permet de poser la mme contrainte en indiquant la valeur affecter par dfaut.
CREATE TABLE batiment (id INTEGER NOT NULL, nom VARCHAR (100) NOT NULL); adresse VARCHAR (100), CREATE TABLE batiment (id INTEGER NOT NULL, nom VARCHAR (100) DEFAULT 'toto'); adresse VARCHAR (100),

Le premier exemple indique que le champ nom doit tre rempli. Le second exemple indique que dans le cas o aucune valeur ne serait insre dans le champ nom, celui-ci vaudrait 'toto' (a nous fait une belle jambe hein!).

2.2.2 Clefs primaires


Une table peut contenir diffrentes clefs mais ne doit contenir qu'une seule clef primaire. Celle-ci permet de rfrencer un enregistrement de manire unique. Il va de soi qu'une clef primaire doit tre dclare comme NOT NULL. On la dclare l'aide de la syntaxe suivante
PRIMARY KEY (nomChamp)

ou encore
nomChamp PRIMARY KEY

MySQL fournit une option AUTO_INCREMENT qui lui est spcifique (non ANSI). Elle permet d'incrmenter automatiquement l'id dclar comme clef primaire chaque insertion.

2.2.3 Clefs trangres


Avant de jouer avec les clefs trangres, vous devez savoir que par dfaut, leurs contraintes ne sont pas prises en compte par MySQL. Il existe cependant plusieurs moteurs de stockage dans MySQL (c'est--dire de modules chargs de grer les tches de lecture et d'criture sur le disque et de grer les transactions). Les deux plus utiles (sur lesquels nous reviendrons) sont: - MyIsam: c'est le moteur par dfaut (qui ne gre pas l'intgrit rfrentielle). - InnoDB: c'est le moteur le plus volu qui gre l'intgrit rfrentielle.
MyIsam est utilis par dfaut mais il est possible de prciser le moteur que l'on souhaite au moment de la cration de

la table l'aide de la syntaxe suivante:


CREATE TABLE batiment ( definitions ) ENGINE=InnoDB;

Pour dclarer une clef trangre, c'est--dire qu'un champ de votre table fait rfrence un champ d'une autre table, on utilise la syntaxe: FOREIGN KEY (nomChamp) REFERENCES nomTable(nomChamp) Exemple:
CREATE TABLE batiment (id INTEGER NOT NULL AUTO_INCREMENT, nom VARCHAR (100) NOT NULL, annee INTEGER DEFAULT 1900, adresse VARCHAR (100), id_Architecte INTEGER NOT NULL, PRIMARY KEY (id), FOREIGN KEY (id_architecte) REFERENCES architecte(id)) ENGINE=InnoDB;

ou id_Architecte rfrence la clef primaire de la table architecte qui pourrait tre dfinie ainsi:
CREATE TABLE architecte (id INTEGER NOT NULL, nom VARCHAR (100) NOT NULL, prenom VARCHAR (100), anneeNais INTEGER, anneeMort INTEGER) ENGINE=InnoDB;

MySQL indexe automatiquement les clefs primaires et trangres. Les requtes qui se basent sur elles sont donc trs rapides. Dans cet exemple, on dfinit une relation de un plusieurs entre les tables architecte et batiment: un architecte peut avoir construit 0 ou plusieurs btiments et tout btiment a un architecte (ce qui relve dj de l'interprtation puisqu'un btiment pourrait ne pas avoir d'architecte connu). La dfinition d'une clef trangre permet en principe d'viter toute modification affectant un lien entre deux tables dans le cas d'une insertion, d'une modification ou d'une suppression (la requte est alors rejete). Mais cela n'est effectif que si votre table utilise un moteur qui respecte l'intgrit rfrentielle (InnoDB). Une mise jour ou une suppression peut alors tre rpercute en cascade sur les tables lies l'aide des vnements ON UPDATE et ON DELETE. La rpercussion consiste mettre la clef trangre NULL (SET NULL) ou rpercuter la mme opration qu' l'enregistrement auquel il est fait rfrence (CASCADE). Exemple:
CREATE TABLE batiment (id INTEGER NOT NULL AUTO_INCREMENT, nom VARCHAR (100) NOT NULL, annee INTEGER DEFAULT 1900, adresse VARCHAR (100), id_Architecte INTEGER NOT NULL, PRIMARY KEY (id), FOREIGN KEY (id_architecte) REFERENCES architecte(id) ON DELETE SET NULL); ON DELETE SET NULL permet lors de la suppression d'un architecte auquel il est fait rfrence via id_architecte de mettre le contenu de ce champ id_architecte NULL (mais on pourrait faire la mme chose lors d'une mise jour avec ON UPDATE). La syntaxe ON DELETE CASCADE sur la clef trangre entranerait la suppression de l'enregistrement batiment

correspondant lors de la destruction d'un architecte (ce qui en l'occurrence serait dangereux: si je supprime un architecte qui a fait 15 btiments, ces 15 btiments disparatraient en cascade!).

2.2.4 Contrainte d'unicit


La contraint d'unicit permet d'interdire la redondance d'information sur un ou plusieurs champs. La syntaxe est la suivante: UNIQUE (champ1[, champ2, ...]) Dans notre table batiment par exemple, il serait gnant, dans le cadre d'une application visant recenser les btiments d'architecture contemporaine, qu'il puisse y avoir deux btiments avec la mme adresse et la mme anne. On pourrait ajouter la contrainte:

UNIQUE (annee, adresse) En revanche, si notre application a une vise historique, il faudra prendre en compte que deux btiments de notre base ont pu au fil des sicles avoir t construits la mme adresse. Autrement dit une contrainte d'unicit portant sur la combinaison de ces deux champs invaliderait le fonctionnement de notre application.

2.2.5 Limiter les valeurs un ensemble prdfini


La dernire option CHECK permet de limiter le contenu d'un champ une liste de valeurs prdfinies. On pourrait ainsi limiter le contenu autoris dans les champs annee et adresse:
CREATE TABLE batiment (id INTEGER NOT NULL AUTO_INCREMENT, nom VARCHAR (100) NOT NULL, annee INTEGER CHECK (annee BETWEEN 1900 AND 1999) DEFAULT 1900, adresse VARCHAR (100) CHECK (adresse IN ('rue Vandrezanne', 'boulevard Auriol', 'rue de Tolbiac')) NOT NULL, id_Architecte INTEGER NOT NULL, PRIMARY KEY (id), FOREIGN KEY (id_architecte) REFERENCES architecte(id) ON DELETE SET NULL);

Le champ annee ne peut alors comprendre que des valeurs comprises entre 1900 et 1999 (ce qui peut avoir son intrt dans le cadre d'une base consacre au XXe sicle). Et le champ adresse ne peut alors comprendre que une des 3 adresses mentionnes (ce qui est videment excessivement restrictif). Attention: la contrainte CHECK est accept par MySQL mais ne donne lieu aucun contrle. MySQL dispose de types qui permettent le contrle: ENUM et SET (qui ne font pas partie de la norme SQL). Exemple: adresse ENUM ('rue Vandrezanne', 'boulevard Auriol', 'rue de Tolbiac') Si la valeur insre dans le champs adresse n'appartient pas l'ensemble dfini par ENUM, MySQL affecte une chane vide. Ce type de procd manque cependant de souplesse. Pour bien faire, il faudrait crer une nouvelle table rue contenant tous les noms de rues et lier cette table la table batiment l'aide d'une clef trangre id_rue. Cela permettrait d'uniformiser l'orthographe des noms de rue et de faciliter l'ajout de nouveaux noms. Ainsi on pourrait imaginer une table rue ayant la structure suivante: #type est l pour distinguer les 'rue de', 'rue de la', 'rue de l\'' #et permettre des requtes rapides sur le champ 'nom' dont l'ordre alphabtique est important pour l'utilisateur
CREATE TABLE rue (id INTEGER NOT NULL AUTO_INCREMENT, type VARCHAR (100) NOT NULL, nom VARCHAR (200) NOT NULL);

auquel la table batiment ferait dsormais rfrence de la manire suivante:


CREATE TABLE batiment (id INTEGER NOT NULL AUTO_INCREMENT, nom VARCHAR (100) NOT NULL, annee INTEGER CHECK (annee BETWEEN 1900 AND 1999) DEFAULT 1900, no INTEGER, id_rue INTEGER NOT NULL, id_architecte INTEGER NOT NULL, PRIMARY KEY (id), FOREIGN KEY (id_rue) REFERENCES rue(id), FOREIGN KEY (id_architecte) REFERENCES architecte(id) ON DELETE SET NULL);

2.3 Rsum des syntaxes disponibles pour la cration d'une table


CREATE [TEMPORARY] TABLE [IF NOT EXISTS] nomTable (commandeCration,...) [optionSelect] commandeCration:
nomChamp type [NOT NULL|NULL] [DEFAULT valeur] [AUTO_INCREMENT] [PRIMARY KEY] ou PRIMARY KEY (nomChamp,...) ou INDEX [nomIndex] (nomChamp,...)

ou UNIQUE [INDEX] [nomIndex] (nomChamp,...) ou [CONSTRAINT contrainte] FOREIGN KEY nomIndex (nomChamp,...) [rfrences] ou CHECK (valeurs);

optionSelect:
[IGNORE|REPLACE] SELECT ... (requte SQL)

rfrences:
REFERENCES nomTable(nomChamp) [ON DELETE optionRf] [ON UPDATE optionRf]

optRf: CASCADE|SET NULL|SET DEFAULT L'option TEMPORARY indique que la table est cre pour la connexion courante. L'option IF NOT EXISTS est utile lorsque vous stockez de nombreuses requtes de cration de table dans un fichier externe. Cela vite de supprimer ou remplacer de manire intempestive des tables qui existent dj lorsque vous lancez votre fichier. La commande INDEX permet de crer un index sur un ou une combinaison de champs.

3. Manipuler les tables


Attention: il existe des diffrences entre la syntaxe SQL standard et MySQL. Vous matrisez bien SQL? Alors jetez un coup d'oeil ce qui suit: MySQL ne respecte malheureusement pas plus la norme SQL que ses concurrents.

3.1 Copier des tables


Il est possible de crer une table partir d'une autre table en utilisant la syntaxe suivante:
CREATE TABLE copie_batiment AS SELECT * FROM batiment; copie_batiment est ici la copie conforme de batiment: la structure et le contenu de batiment ont t copis.

En revanche les contraintes de clef primaire et trangre ne sont pas reproduites. Mais on peut procder de manire plus slective en prcisant les champs que l'on veut copier. Exemple:
CREATE TABLE copie_batiment AS SELECT nom FROM batiment;

Dans ce cas on copie dans la nouvelle table copie_batiment uniquement le champ nom de la table batiment. On peut pousser encore plus loin et prciser sur quel critre se fait la copie: Exemple:
CREATE TABLE copie_batiment (nv_nom) AS SELECT nom FROM batiment WHERE nom LIKE 'L%';

Dans ce cas on copie dans la nouvelle table copie_batiment uniquement le champ nom des batiments dont le nom commence par 'L'.

3.2 Modifier des tables


Lorsqu'on veut modifier une table existante, on recourt au mot-clef ALTER. La syntaxe gnrale est la suivante : ALTER TABLE nomTable altrations

3.3 Renommer des tables


Pour renommer une table la syntaxe est la suivante:
ALTER TABLE batiment RENAME [TO|AS] nouveau_batiment;

Pour ajouter une colonne, on utilise le mot-clef ADD suivi du nom et du type de la colonne:
ALTER TABLE batiment ADD no VARCHAR(100);

On ajoute un champ no la table batiment. On peut galement modifier le type d'un champ existant avec MODIFY:
ALTER TABLE batiment MODIFY no VARCHAR(200);

Attention: MySQL se charge de faire la conversion de l'ancien vers le nouveau type de donne, pour le meilleur et pour le pire. Il existe des tables de conversion mais en la matire ne faites jamais confiance votre mmoire: faites toujours un test sur une copie de votre table avant de massacrer l'original. Enfin vous pouvez supprimer un champ l'aide de la commande DROP.
ALTER TABLE batiment DROP id;

Attention: la suppression d'un champ entraine la perte de toutes les donnes qu'il contient.

3.4 Synthse des commandes de modifications des tables


ALTER TABLE nomTable altrations

altrations:
ADD [COLUMN] commandeCration [FIRST|AFTER nomChamp] ou ADD INDEX [nomIndex] (nomChamp,...) ou ADD PRIMARY KEY (nomChamp,...) ou ADD UNIQUE [nomIndex] (nomChamp,...) ou ALTER [COLUMN] nomChamp ou CHANGE [COLUMN] ancienNomChamp commandeCration ou MODIFY [COLUMN] commandeCration ou DROP [COLUMN] nomChamp ou DROP PRIMARY KEY ou DROP INDEX nomIndex ou RENAME [AS|TO] nomTable

3.5 Supprimer des tables


Il est extrmement facile de supprimer une table en utilisant la syntaxe suivante (attention ne pas faire d'erreur): DROP TABLE [IF EXISTS] batiment; Distinguez bien la syntaxe qui prcde, qui supprime la table dans son ensemble de celle qui suit qui se contente de supprimer la totalit des enregistrements de la table mais conserve sa structure intacte: DELETE FROM batiment [WHERE conditions];

3.6 Remplir une table depuis un fichier externe: LOAD DATA


Pour charger le contenu d'un fichier texte l'intrieur d'une table, vous disposez de la syntaxe suivante:
LOAD DATA [LOW PRIORITY] [LOCAL] INFILE 'nomFichier' [REPLACE|IGNORE] INTO TABLE nomTable [FIELDS [TERMINATED BY caractre] [OPTIONNALY] [ENCLOSED BY caractre] [ESCAPED BY caractre]] [LINES TERMINATED BY caractre] [IGNORE entier LINES] [(nomColonne,...)]

4. Requtes MySQL

Les exemples qui suivent portent sur une base de donne de gestion de syndic constitue de 4 tables selon le schma suivant:

Cette base rpond aux problmatiques suivantes: - un appartement peut tre possd en indivision: c'est--dire qu'il peut tre la proprit de plusieurs personnes, chacune de ces personnes possdant une quote-part de l'appartement. - une personne peut possder plusieurs appartements - un appartement a un locataire et un seul (celui qui paye le loyer) - il peut y avoir plusieurs appartements par immeuble La relation entre la table PERSONNE et la table APPARTEMENT peut tre de deux natures: - soit une relation qui indique la possession et qui passe par la table intermdiaire POSSEDE qui rsulte d'une relation de plusieurs plusieurs (un appartement peut tre possd par plusieurs personnes et une personne peut possder plusieurs appartements), - soit une relation de location La relation entre la table APPARTEMENT et la table IMMEUBLE permet d'indiquer dans quel immeuble se trouve chaque appartement (en vitant la redondance d'information). Vous pouvez charger ces 4 tables et quelques donnes l'aide du fichier suivant: immeuble.sql. De manire gnrale, lorsque vous faites des requtes sur une base de donne, il est bon d'avoir sous les yeux le schma de cette base. N'hsitez pas vous crayonner le schma de la base de gestion de syndic sur une feuille de papier pour suivre correctement les exemples.

4.1 Structure d'une slection: les trois tapes


La syntaxe gnrale des requtes de slection est la suivante:
SELECT liste_expressions FROM source_donnees [WHERE liste_conditions]

Ainsi la syntaxe suivante renvoie tous les champs de la table personne


SELECT id, nom, prenom, profession, id_appartement FROM personne

Mais on aurait galement pu utiliser la syntaxe suivante o l'toile est une syntaxe raccourcie qui dsigne l'ensemble des champs:
SELECT * FROM personne

Ne vous affolez pas si la syntaxe des requtes vous parait complexe: dans cette partie il s'agit de saisir la structure gnrale des requtes, nous revenons sur le dtail de la syntaxe dans les chapitres suivants (4.2 et 4.3). Notez que la machine ne travaille pas du tout dans l'ordre nonc. Elle commence par dterminer les sources mentionnes par FROM, puis elle slectionne les donnes conformes aux conditions nonces dans le WHERE et s'occupe finalement d'afficher les champs recenss dans le SELECT. Concrtement, c'est comme si vos donnes passaient au travers de trois tamis avant d'tre affiches: - le premier tamis consiste slectionner les tables dont vous avez besoin (et vous avez rarement besoin de toutes vos tables) - le second tamis slectionne les donnes dans ces tables selon certains critres logiques - le troisime tamis slectionne les donnes afficher dans le rsultat final

4.1.1 L'espace de recherche: clause FROM (ou premier tamis)


Cet espace peut tre une table base, c'est dire immdiatement disponible dans la base ou une table calcule, c'est--dire une table qui est elle-mme le rsultat d'une slection comme dans l'exemple qui suit:
SELECT * FROM (SELECT nom, adresse FROM IMMEUBLE WHERE id=1) AS KOUDALOU;

Si on a souvent recours une table calcule, il peut tre judicieux de crer ce qu'on appelle une vue (disponible partir de MySQL 5.0).
CREATE VIEW Koudalou AS SELECT nom, adresse FROM immeuble WHERE id=1; SELECT nom, adresse FROM Koudalou;

Enfin on peut vouloir slectionner le contenu de plusieurs tables. Par dfaut, la requte qui suit renvoie toutes les associations possibles entre les lignes de la table immeuble et les lignes de la table appartement. C'est ce qu'on appelle le produit cartsien de deux tables et c'est rarement tel quel que vous en aurez besoin.
SELECT * FROM immeuble, appartement;

qui peut s'crire galement


SELECT * FROM immeuble CROSS JOIN appartement;

La plupart du temps vous chercherez raliser des jointures, c'est--dire un produit cartsien restreint par une condition qui peut s'crire de la manire suivante:
SELECT * FROM immeuble JOIN appartement ON (immeuble.id=appartement.id_immeuble);

qui ne renvoie que les appartements rfrencs dans la table immeuble. Pas de panique devant cette syntaxe que vous n'avez probablement jamais vu: il faudra vous y habituer, SQL permet souvent d'crire une mme opration de plusieurs faons (dans le cas prsent vous auriez prfr un WHERE, a tombe bien, on y vient justement).

4.1.2 La condition: la clause WHERE (second tamis)


La clause WHERE permet d'exprimer des conditions portant sur les lignes de la ou des table(s) dfinie(s) par la clause FROM. Ces conditions prennent la forme classique des tests combins par les oprateurs logiques classiques AND, OR, NOT. Les rgles de priorit s'expriment entre parenthses pour viter toute ambiguit. Ainsi l'exemple de jointure qui prcde pourrait galement s'crire avec une clause WHERE de la manire suivante:
SELECT * FROM immeuble, appartement WHERE immeuble.id=appartement.id_immeuble;

Les tests les plus traditionnels sont possibles: Afficher les appartements de plus de 50 m2:
SELECT * FROM appartement WHERE surface > 50;

Afficher les appartements de plus de 50 m2 et situs au-dessus du 3me tage:


SELECT * FROM appartement WHERE surface > 50 AND etage > 3;

Afficher les appartements de plus de 50 m2 et situs au-dessus du 3me tage ou les appartements situs dans l'immeuble n2:
SELECT * FROM appartement WHERE (surface > 50 AND etage > 3) OR id_immeuble=2;

Afficher les personnes qui habitent en-dessous du 3me tage:


SELECT * FROM personne WHERE id_appartement IN (SELECT id FROM appartement WHERE etage < 3);

Les requtes imbriques comme cette dernire sont viter. Il y a en gnral des solutions plus lgantes et surtout plus lisibles.

4.1.3 Les expressions: la clause SELECT (ou troisime tamis)


Une fois slectionnes les lignes du FROM qui satisfont la clause WHERE, on affiche le rsultat final d'une certaine manire l'aide de la clause SELECT. Une expression peut tre un nom d'attribut, une constante, ou le rsultat d'un calcul plus complexe. SELECT surface, etage, 18 AS 'euros/m2' FROM appartement La commande AS permet ici de donner un nom la colonne qui accueillera la constante 18 qui sera rpt pour toutes les lignes retournes. Mais on pourrait galement inclure une expression calcule comme le loyer, en se basant sur la surface et sur l'tage.
SELECT no, surface, etage, (surface,*18)*(1+(0.03*etage)) AS loyer FROM appartement

La documentation MySL prcise toutes les fonctions et oprateurs disponibles. Vous pouvez d'ailleurs utiliser MySQL uniquement pour afficher le rsultat d'une opration en omettant la clause FROM comme dans l'exemple qui suit:
SELECT 2 + 2; SELECT ROUND(1.235,2);

Attention: il ne doit pas y avoir d'espace entre la fonction MySQL et la premire parenthse ouvrante qui suit.

4.2 Recherche avec MySQL


La rechercherche la plus simple est, nous l'avons vue, celle qui renvoie tous les champs d'une table: elle ne ncessite pas de clause WHERE et utilise l'toile '*' pour dsigner tous les champs.
SELECT * FROM appartement;

affiche tous les champs de la table appartement.

Construction d'expression
Si on indique explicitement les champs sans utiliser l'toile '*', ceux-ci dterminent le nombre de champs afficher. Par dfaut le nom de chaque colonne est celui du champ mais on peut modifier ce nom l'aide de l'alias AS. La fonction MySQL CONCAT() vous permet galement de prsenter plusieurs champs au sein d'une seule colonne comme le montre l'exemple suivant:
SELECT CONCAT(nom, ' (', prenom, ')') AS 'Nom et prnom' FROM personne;

L'exemple prcdent retourne un rsultat NULL. Pour viter ce type d'affichage, MySQL fournit la fonction IFNULL() qui permet d'attribuer une valeur par dfaut aux valeurs NULL comme dans l'exemple suivant:
SELECT IFNULL(prenom, 'rien') AS 'Prenom' FROM personne;

Vous pouvez galement effectuer des calculs dans la clause SELECT comme l'exemple suivant qui calcule le loyer de chaque appartement sur la base de 18 euros du mtre carr.
SELECT id AS 'Appartement', CONCAT(surface*18, ' euros') AS 'Loyer' FROM appartement;

La clause WHERE
La clause WHERE utilise les oprateurs de comparaison standards savoir: <, <=, =, !=, >=, > ainsi que les oprateurs logiques: AND, OR, NOT et IN qui teste l'appartenance un ensemble comme dans l'exemple qui suit:
SELECT * FROM personne WHERE profession='Acteur' OR profession='Rentier';

qui peut s'crire galement avec IN:


SELECT * FROM personne WHERE profession IN ('Acteur','Rentier');

Pour les comparaisons portant sur des chanes de caractre, vous disposez de l'oprateur LIKE, qui fait partie de la norme SQL et qui fonctionne avec le '%' (qui remplace n'importe quelle chaine) et le '_' (qui remplace n'importe quel caractre).
SELECT * FROM personne WHERE nom LIKE '%m_t';

MySQL fournit galement l'oprateur REGEXEP qui permet d'utiliser les expressions rgulires. Attention: REGEXP n'est pas un standard SQL.
SELECT * FROM personne WHERE nom REGEXP 'Ramut';

Attention: la comparaison de chane, par dfaut, ne tient pas compte de la casse, sauf si vous le prcisez avec l'oprateur BINARY.
SELECT * FROM personne WHERE nom LIKE BINARY 'r%';

ne retourne rien puisque la premire lettre des noms est toujours en majuscule.

Grer les valeurs nulles


D'une valeur nulle on ne peut strictement rien faire: dans le cas d'une comparaison, la prsence d'un NULL ne renvoie ni TRUE ni FALSE mais UNKNOWN (une valeur boolenne intermdiaire). Ainsi, les requtes complmentaires suivantes (l'une avec LIKE, l'autre avec NOT LIKE) ne renvoient pas le locataire Ross dont le champ prenom a pour valeur NULL:
SELECT * FROM personne WHERE prenom LIKE '%'; SELECT * FROM personne WHERE prenom NOT LIKE '%';

Rsultat des courses, si on veut slectionner des champs qui ont une valeur nulle, on recoure au test IS NULL:
SELECT * FROM personne WHERE prenom LIKE '%' OR prenom IS NULL;

Tris
Lorsque vous faites une requte globale, MySQL ne vrifie pas si certaines informations sont redondantes:
SELECT surface FROM appartement;

l'expression DISTINCT permet d'liminer les doublons du rsultat:


SELECT DISTINCT surface FROM appartement;

Mfiez-vous du DISTINCT dans le cas de tables importantes: cette fonction utilise beaucoup de ressource et peut ralentir notablement vos requtes.
MySQL permet galement de trier par ordre croissant (ASC, tri par dfaut) ou dcroissant (DESC) les rsultats retourns pour un champ l'aide de la syntaxe ORDER BY qui vient se placer la fin de la requte: SELECT * FROM appartement ORDER BY surface, etage;

ou

SELECT * FROM appartement ORDER BY surface DESC, etage ASC;

La clause LIMIT
Attention, la clause LIMIT, qui permet de spcifier le nombre de lignes retournes par la requte est une spcificit MySQL que vous ne retrouverez pas chez tous les autres SGBD.
LIMIT premiereLigne, nbLigne

ou
LIMIT nbLigne [OFFSET premiereLigne]

4.3 Les jointures


La jointure consiste restreindre le produit cartsien de plusieurs tables en ne conservant que les associations qui prsentent un intrt pour la requte. Il y a beaucoup de manire de faire des jointures. Nous nous limitons ici aux plus conventionnelles.

4.3.1 Syntaxe classique pour tablir une jointure


Pour viter le problme d'identification des champs homonymes (ceux qui portent le mme nom dans des tables diffrentes), on cr un nom raccourci pour chaque table au niveau du FROM (on appelle cela un alias) et on le concatne au nom du champ avec un '.' de la manire suivante:
SELECT p.id, nom, prenom, id_appart, a.id, surface, etage FROM personne p, appartement a WHERE nom='DUPONT' AND prenom='William' AND a.id=id_appartement;

Nous avons pris l'exemple du cas le plus gnral: celui o la jointure se fait entre clef primaire et clef trangre. Dans cet exemple, il tait ncessaire de prciser de quelles tables relevaient les champs id homonymes. Mais d'autres cas peuvent se prsenter. Si par exemple vous vouliez connatre les appartements d'un mme immeuble qui ont une mme surface, vous seriez amen comparer les enregistrements de la table appartement avec eux-mmes. Vous tes alors conduit crer deux alias de la mme table pour rsoudre le problme:
SELECT a1.id, a1.surface, a1.etage, a2.id, a2.surface, a2.etage FROM appartement a1, appartement a2 WHERE a1.id_immeuble=a2.id_immeuble AND a1.surface=a2.surface AND a1.id!=a2.id;

Essayez de rsoudre la srie d'exercices qui suit sur les jointures. Faites-l et refates-l jusqu' ce que le raisonnement qui conduit au rsultat soit fluide pour vous. N'hsitez pas vous faire un petit schma sur papier de l'organisation de vos tables: Qui habite un appartement de plus de 200m2?
SELECT nom, prenom FROM personne, appartement a WHERE surface > 200 AND id_appartement=a.id;

Qui habite l'immeuble Barabas?


SELECT p.nom, prenom FROM personne p, appartement a, immeuble i WHERE i.nom='Barabas' AND a.id=p.id_appartement AND a.id_immeuble=i.id;

Qui habite un appartement qu'il possde et avec quelle quote-part?


SELECT p.nom, prenom, quote FROM personne p, possede P2, appartement a WHERE p.id=p2.id_personne AND p2.id_appartement=a.id AND p.id_appartement=a.id;

De quels appartements Alice Black est-elle propritaire et dans quel immeuble?

SELECT i.nom, no, etage, surface FROM personne p, possede p2, appartement a, immeuble i WHERE p.id=p2.id_personne /*Jointure personne possede*/ AND p2.id_appartement = a.id /*Jointure possede appartement*/ AND a.id_immeuble=i.id /*Jointure appartement immeuble*/ AND p.nom='Black' AND p.prenom='Alice';

4.3.2 Syntaxe avec les tables calcules dans le FROM


Mme si je vous dconseille de l'utiliser, il existe un autre moyen d'exprimer les jointures que vous devez tre au moins capable de lire, celui des tables calcules places dans le FROM. Les exemples prcdents pourraient s'crire ainsi: Quel est l'appartement de Dupont?
SELECT no, surface, etage FROM appartement, (SELECT id_appartement FROM personne WHERE nom='Dupont') AS Dupont WHERE id=id_appartement;

Attention: il faut toujours donner un alias une table calcule (mme si on ne s'en sert pas). Qui habite un appartement de plus de 200m2?
SELECT nom, prenom FROM personne AS p, (SELECT id_appartement FROM appartement WHERE surface>200) AS a WHERE p.id=a.id_appartement;

Qui habite le Barabas?


SELECT nom, prenom FROM personne AS p, (SELECT appartement.id FROM appartement, immeuble WHERE id_immeuble=immeuble.id AND nom='Barabas') AS a WHERE p.id_appartement=a.id;

4.3.3 Autres syntaxes pour les oprateurs de jointure


La virgule qui spare deux tables dans un FROM exprime un produit cartsien: toutes les combinaisons de lignes sont considres puis soumises aux conditions du WHERE. MySQL fournit d'autres syntaxes pour exprimer la jointure sous la forme: table1 oprateur table2 [condition] ou oprateur appartient la liste suivante: - CROSS JOIN qui est le synonyme de la virgule ',' - JOIN est une jointure accompagne de conditions. - LEFT [OUTER] JOIN et RIGHT [OUTER] JOIN pour les jointures externes. - NATURAL [LEFT|RIGHT[OUTER]] JOIN pour les jointures 'naturelles'. Si on reprend les exemples prcdents avec cette syntaxe, cela nous donne: Quel est l'appartement de Dupont?
SELECT no, surface, etage FROM personne JOIN appartement ON (appartement.id=id_appartement) WHERE nom='Dupont';

Qui habite un appartement de plus de 200m2?


SELECT nom, prenom FROM personne AS p JOIN appartement AS a ON (a.id=p.id_appartement AND surface > 200);

Quoique cela fonctionne, MySQL dconseille cette pratique qui consiste inclure une condition de slection dans la jointure. En thorie la jointure est l uniquement pour faire les comparaisons de clefs.

4.3.4 Les jointures externes


Les jointures externes ne trouvent pas d'quivalent dans les formules qui prcdent. Elles permettent en effet de grer les cas o toutes les lignes d'une table n'ont pas de correspondant dans l'autre table. Si par exemple je fais une requte qui affiche tous les appartements avec leurs occupants, je n'obtiendrais que les appartements qui ont un occupant mais pas les appartements vides (or il y en a un).

Dans ce cas je dtermine une table directrice (celle de gauche par convention) dont toutes les lignes, mme celles qui ne trouvent pas de correspondance dans l'autre table seront prises en compte. La table de droite est dite optionnelle. Afficher tous les appartements avec leur locataire ventuel s'crit donc de la manire suivante:
SELECT id_immeuble, no, etage, surface, nom, prenom FROM appartement a LEFT OUTER JOIN personne p ON (p.id_appartement=a.id);

4.3.5 Les oprations ensemblistes


La norme SQL ANSI comprend des oprations qui considrent les tables comme des ensembles entre lesquels on peut effectuer des intersections avec les mot-clefs UNION, INTERSECT et EXCEPT. Chaque oprateur s'applique des tables de schma identique (mme nombre de champs, mmes noms, mmes types). MySQL ne dispose que de l'oprateur UNION (les deux autres peuvent s'exprimer d'une autre manire). Il y a en ralit peu de cas qui ncessitent l'usage de l'oprateur UNION. Ainsi l'exemple suivant:
SELECT nom FROM immeuble UNION SELECT nom FROM personne;

retourne une liste comprenant les noms des immeubles et des personnes qui sont dans la base. Mais pourquoi faire?

4.4 Agrgation
On appelle agrgats des regroupements de lignes en fonction de certains champs. Ce regroupement est spcifi par la clause GROUP BY. Si on ne mentionne aucun groupe, SQL considre par dfaut qu'il s'agit de la table tout entire (c'est un groupe sommaire mais c'est un groupe). Les fonctions d'agrgation s'appliquent alors la table tout entire comme le montre l'exemple suivant:
SELECT COUNT(*), COUNT(prenom), count(nom) FROM personne;

La clause GROUP BY permet de spcifier sur quel champ doit se faire le regroupement. Ds lors, tous les enregistrements possdant la mme valeur pour ce champ sont regroups. Ainsi, on peut obtenir la somme des quote-parts pour chaque appartement:
SELECT id_appartement, SUM(quote) FROM possede GROUP BY id_appartement;

Dans un premier temps, MySQL regroupe les enregistrements qui ont le mme id_appartement dans la table possede. Puis pour chacun de ces regroupements on affiche l'id_appartement et la somme des quote parts des diffrents enregistrements regroups. Si vous avez bien saisi le principe, vous devez comprendre que la requte prcdente doit retourner 100 pour chaque appartement (puisqu'il s'agit de la somme des parts de chacun des propritaires de l'appartement). Il est possible galement d'exprimer des conditions sur ces valeurs agrges pour ne conserver qu'un ou plusieurs des groupes constitus. Ces conditions portent sur des groupes de lignes et non sur des lignes prises une une, c'est pourquoi on emploie ici la clause HAVING plutt que WHERE. Par exemple on peut slctionner les appartements pour lesquels on connat au moins deux copropritaires:
SELECT id_appartement, COUNT(*) FROM possede GROUP BY id_appartement HAVING COUNT(*) >=2;

Ici la clause HAVING porte sur le rsultat de la fonction d'agrgation GROUP BY. On peut ainsi calculer la surface possde par chaque propritaire dans l'immeuble 1 en fonction de la quote-part qu'ils ont dans chaque appartement possd. On regroupe les appartements par propritaire et on trie sur la surface possde:

SELECT nom, prenom, SUM(quote*surface/100) AS 'Surface possedee' FROM personne p1, possede p2, appartement a WHERE id_immeuble=1 AND p1.id=p2.id_personne AND a.id=p2.id_appartement GROUP BY p1.id ORDER BY 'Surface possedee' DESC;

Vous remarquez au passage un autre usage possible d'un alias portant sur un champ calcul.

4.5 Requte de mises jour


4.4.1 Insertion
L'insertion s'effectue avec la commande INSERT. Si l'on ne prcise pas les champs dans lesquels se fait l'insertion, MySQL suppose que la requte concerne tous les champs et que les valeurs seront passes dans l'ordre adquat. Nb: Si un des champs est auto-incrment (option AUTO_INCREMENT), il est inutile de le passer en paramtre. Insrer des donnes dans la table immeuble (o il n'y a pas de champ auto-incrment) s'crit donc:
INSERT INTO immeuble VALUES (1, 'Koudalou', '3, rue Blanche');

Si l'insertion ne concerne que certains champs, il faut alors les numrer comme dans l'exemple suivant: INSERT INTO immeuble(id, nom, adresse) VALUES (1, 'Koudalou', '3, rue Blanche');

4.4.2 Destruction
La destruction s'effectue avec clause DELETE et selon la syntaxe suivante:
DELETE FROM table WHERE condition;

4.4.3 Modification
La modification s'effectue avec la clause UPDATE et selon la syntaxe suivante:
UPDATE table SET A1=v1, A2=v2, ... WHERE condition;

ou An sont les noms de champ et vn les nouvelles valeurs. Attention: tout ce qui suit n'est disponible qu'avec la version 5 de Mysql.

4.5 Les vues


Lorsque vous faites une requte MySQL, le rsultat qui s'affiche est une table. Les vues ne sont rien d'autres que des requtes dont on a stock le rsultat dans des tables 'virtuelles'. La cration d'une vue n'induit en ralit aucun stockage (les informations qu'elle extrait sont toujours dans les tables de votre base). Elle permet seulement d'obtenir facilement une reprsentation diffrentes des donnes contenues dans les tables de votre base. Les vues permettent donc: - une plus grande lisibilit de votre base l'aide de ces requtes prdfinies - une meilleure scurisation des donnes car vous pouvez restreindre l'interrogation de votre base uniquement aux requtes que vous avez crer. Autrement dit l'utilisateur lambda de pourra pas faire de recoupement d'information que vous n'ayez autoris.

4.5.1 Crer et utiliser une vue

Une vue se construit et s'utilise comme une table ceci prs qu'elle est une table dynamique puisqu'elle repose sur d'autres tables. Sa syntaxe n'a donc rien de surprenant par rapport ce que vous avez dj vu:
CREATE [OR REPLACE] VIEW nomVue [(listeAttibuts)] AS requete [WITH CHECK OPTION]

Pour crer une vue affichant le nom, l'adresse et le nombre d'appartements grs dans l'immeuble Koudalou, on peut crire:
CREATE OR REPLACE VIEW koudalou AS SELECT nom, adresse, COUNT(*) AS nbAppartement FROM immeuble i, appartement a WHERE i.id=a.id_immeuble AND i.id=1 GROUP BY i.id;

On appelle ensuite cette vue comme on appelle une table:


SELECT * FROM koudalou;

Dsormais cette vue apparait au mme titre que les tables de votre bases lorsque vous faites un SHOW TABLES;. La seule limite des vues par rapport aux tables est qu'on ne peut insrer des donnes que de manire extrmement limit: les vues qui peuvent servir l'insertion ne doivent porter que sur une table o les colonnes non rfrences dans la vue doivent pouvoir tre mises NULL ou disposer d'une valeur par dfaut. Autrement dit ces vues d'insertion n'ont d'utilit que sur le plan de la scurit (si vous dcidez de limiter l'accs votre base aux vues que vous avez cres).