Vous êtes sur la page 1sur 18

SQL

4 rubriques d'instructions :

- Language de definitions de donnes


Create table Crer une table
Alter table Modifier la structure d'une table
Drop table Supprimer une table
Create view Crer une vue, requette enregistre
Drop view Supprimer une vue
- Language transactionnel
insert => Crer des enregistrements dans une table
Executer des transactions : update => Modifier un enregistrement
delete => Supprimer un enregistrement

- Introgation de base de donnes


Select ... Lecture et mise en forme des donnes

- Language d'administration
create user
Gestion d'utilisateur alter user
drop user
Gerer des droits Grant Donner des droits ou des groupes de droit des
utilisateurs ou groupes d'utilisateur
Revoke Retirer les droits
Gerer des groupe de droit ou d'utilisateur create role
drop role

Instruction d'interrogation de BD : Select


- L'instruction select est la seule instruction premettant d'extraire de l'information d'une BD
- Une application cliente envoie un ordre select un serveur de BD (communication client/serveur)
Le serveur qui ecoute la requete traite celle ci en cherchant dans des tables les informations
demandes.

Ensuite le serveur produit et stocke en interne un tableau de resultat contenant autant de colonne
que de champs specifi par la requette select et autant de ligne spcifie par la clause where du
select.

Le serveur renvoie ensuite au client un curseur qui permet celui-i de consulter ligne par ligne le
contenu du tableau rsultat.

Quand le client a termin de consulter le tableau resultat il ferme le curseur et permet de la sorte au
serveur de librer l'espace mmoire utilis pour stocker le tableau de rsultat.

Ex : Php

$db = mysqlconnect(...) ; // Connexion au serveur de base de donnes


mysqlselect( $db, "nom BD"); //Selection de la base de donne
$curseur = mysql.query("select nom, prenom, age from etudiant") // Rcuperer le contenu de 3
champs de la table tudiant
=> Envoi la requette au serveur
=> Le serveur traite cette requette
Produit un tableau de resultat :
nom prenom age

Il contient 3 colonnes car dans Select on a mis 3 champs.


Au dpart le curseur sera plac sur la premire ligne du tableau de rsultat.

Examiner les informations du tableau l'aide d'une boucle :


while( $ligne = mysqlfetchrow( $curseur ) ) => Lire le contenu d'une ligne du tableau de resultat
=> Renvoi un tableau avec les valeur de la ligne
et passe la ligne suivante
{
echo ( $ligne [0] ) ;
echo ( $ligne [1] ) ;
echo ( $ligne [2] ) ; Affiche la deuxieme valeur de ligne lue
}

Clause select :
Syntaxe generale du select :
L'instruction select contient plusieurs clauses, certaines obligatoires, d'autres optionnelles.
Les clauses apparaissent toujours dans le mme ordre.

select ( expression 1 as alias 1, expression 2 as alias 2, ... => Colonnes du tableau de resultat
from table 1 as alias 1, table 2 as alias 2, vue 1 as alias 3, ...=> O on cherche les donnes
where condition => Filtrer les lignes de donnes
groupe by expression 1, expression 2 ,. .. => Regrouper les lignes de donnes
havinng conditions sur agrgat. => Filtrer sur opration agrgation
order by expression 1, expression 2 , .... =>Trier les lignes donnes.

Permet de definir les colonnes du tableau resultat, leur contenu et leur titre (avec alias)
Select expression 1 as titre 1, expression 2 as titre 2 , ...
- Il y autant de colonne dans le tableau resultat que d'expression dans la clause select.
- Les colonnes apparaissent dans le mme ordre que les expressions et sont souvent numrot
partir de 0.
- Le mot cl as permet de renommer le titre d'une colonne.

expression => Nom de champ de table ou de vue


Ex : select nom, prenom, age ...
=> nomdetable.nom de champ
Ex : Select etudiant.nom, etudiant.prenom from etudiant
=> nom d'alias de table . nom de champ
Ex : select e.nom, e.prenomfrom etudiant as e
On renomme localement la table etudiant avec l'alias e;
=> Valeur constante numrique, date, chine de carractre
Ex: Select 'monsieur' as civilite, nom, prenom ....
Cr une colonne nomm civilit qui contient pour chacun la valeur
Monsieur.
Civilit nom prenom
monsieur
monsieur

=> calcul avec champ de table, constante, etc ...


Ex : select prixht, prixht*1,196 as prix ttc, ...
=> calcul utilisant des fonctions
Souvent les fonctions sont spcifique au SGBD
Ex : Select to-char( ( sysdate -datenais ) / 365 , 'DD/MM/YYYY' ) as age
to-char : fonction de convertion d'une date en chaine de caractre
sysdate : date systeme
datenais : champ date de naissance
=> Fonction d'agrgats
=> sum ( expression )
Calcul la somme des valeurs donnes par l'expression
=> min ( expression) max (expression)
Calcul respectivement la valeur mini et maxi des valeurs donnes par
l'expression
Ex : Select min ( age ), max (age ) from etudiants where section = 'sio'

min(age) max(age)
18 34

Exercice :
lignefacture (numfacture#, reference#, qt)
articles( rfrence , libell, prix HT )

Cl etrangre : rajout d'un # aprs la variable


Cl primaire : soulign

select sum ( qte * prixht ) as total ht , sum( qte * prixht * 1,196 ) as total ttc ...

=> avg (expression)


Calcul de moyenne arithemtique (non pondr)
Ex : select avg( note ) as moyenne from evaluation where matiere =
MATH'
=> count ( expression )
Compte les valeurs distinctes donnes par l'expression.
Ex : select count( prenom ) from etudiants
nombre de prnom differents parmis les tudiants
=> count( * )
Compte le nombre de ligne du tableau intermdiaire issu du filtrage de
la clause where.
Ex : select count( * ) as nbfille from etudiants where section 'SIO' and
sexe = 'F'
Renvoi un tableau de resultat 1 colonne :
nbfille
2
Remarques :
- Le mot "distinct" permet de rcuprer des lignes distinctes dans le tableau de resultat :
select distinct nom, prenom from etudiants
- * : permet de ramener tous les champs de la table dans l'ordre de dfinition de celle ci
select * from etudiants
Avec des requettes sur plusieurs tables on peut specifier tous les champs d'une vue table avec :
nomtable.*

Clause from :
Permet de specifier la liste des tables et vues dans lesquelles le serveur de BD cherche les donnes
pour effectuer la requte.
from table1 as alias 1, table2 as alias2, ...

Dans le cas de plusieurs tables mentionnes dans la clause from le serveur construit un tableau
intermdiaire rempli par le resultat du produit cartsien de tous les enregistrements de toutes les
tables figurant dans la clause.

Le serveur cr toutes les combinaisons possibles d'enregistrements pris dans toutes les tables de la
clause from.
Ex :
Articles
Rfrence libell Code cat.# Catgories
123 carte rseau INF Code cat. Libcat

456 mmoire INF INF Informatique

789 lave linge ELT ELT Electromenager

Code cat. est une cl trangre qui fait rfrence une cl primaire d'une autre table, ici catgorie.

On veut ecrire la requette qui affiche la liste des articles selon : rfrence, libell, libell catgorie :

select reference, libell, libecat


from articles, catgories

Cette requette gnre le tableau intermediaire suivant :


Il rcupre les colonnes venant de article et catgories et va faire toutes les associations entre les
lignes des differents tableaux possibles => On parle de produit cartesiens entre la table article et
catgorie.

Article Catgorie
reference libell codecat codecat libcat
123 cartereseau INF INF Informatique
123 cartereseau INF ELT Electromenager
456 Memoire INF INF Informatique
456 Memoire INF ELT Electromenager
789 Lave linge ELT INF Informatique
789 Lave linge ELT ELT Electromenager
Le nombre de combinaison produite est :
nombre de ligne de la table article x nombre de ligne de la table catgorie = 3 x 2 = 6

Ce qui nous interesse est la liste des articles avec le libell et le libell de catgorie qui correspond
la catgorie de l'article.
Nous voulons retirer uniquement les lignes pour lesquel le code catgorie de la table article est gal
celui venant de la table catgorie.

Le Where nous permet de faire cette selection selon la condition mentionne dans le tableau
intermediaire gener par le produit cartsien.

where articles.codecat = categories.codecat

Dans l'absolu le moteur de BD genere un tableau intermediaire d'un produit cartsien des tables
selectionnesmais pour ne pas utiliser trop de ressource le moteur de SGBD va s'appuyer sur les
clauses where pour limiter le nombre de donnes.

Les conditions sont appells conditions de jointure :


- Jointure interne : cl etrangere pointant vers une cl primaire
- Jointure externe : champ hors cl etrangre pointant vers une cl primaire.

Ex :

Etudiants
Numetu nom prenom sexe section

Liste des couples d'tudiants possible :

Select filles.nom, filles.prenom, garon.nom, garon.prenom


from etudiants as filles, etudiants as garon => Permet de renomer une table avec un alias
where filles.sexe='F' and garon.sexe='M' (Permet egalement de raccourcir les requetes et
and filles.numetu <> garcons.numetu avoir moins taper pour les conditions.)

Generer de l'information par combinaison, qui est ensuite filtr a partir d'une seule et mme table.

Clause Where
where condition
Permet de selectionner les lignes du tableau intermdiaire qui nous interessent.
Les lignes slectionns sont celles pour qui l'execution de la condition donne un resultat vrai.

La condition est constitue d'un ensemble de sous conditions lementaires spars par ds oprateurs
logiques : Ordre de priorit
and condition and condition => Operateur binaire (2 operandes) 3
or condition or condition 4
not not condition => Operateur unaire (1 operande) 2
() ( condition ) 1
Ex : Liste des tudiants de 18 22 ans
select * from etudiants
where age >= 18 and age <= 22

Ex : Liste des filles ages de 18 20 ans et les garons ags de 20 24 ans.


select * from etudiants
where sexe = 'F' and age >=18 and age <= 20
or sexe = 'M' and age <= 20 and age <= 24

Condition lementaire :
- expression oprateur de comparaison expressions
- Oprateur de comparaison :
Egalit =
Differente <>
<, > , <= , >=
- Chaine de caractre : <, > , <= , >=
C'est l'ordre lexigographique qui est utilis.
- Dates : ordre temporel
- Expression :
Constante
Champ de table
Calcul
/ ! \ Mme type d'expression que la classe select sauf les agrgats sum, min, max, count

Remarques :
- Comparaison de chaine de caractre
select * from etudiants
where prenom = 'Kevin'
1) Les chaines de caractres sont dlimites par des cotes simples en SQL !
2) Attention la casse (minuscule, majuscule) avec les constantes !
select * from etudiants
where upper (prenom) = 'KEVIN' => upper() transforme les minuscule en majuscule
( ucase() avec Oracle )
- Comparaison de date
Attention au format de date utilis par le SGBD. Ils varient selon les moteurs de SGBD :
mySQL : 'YYYY-MM-DD'
Access, SQL Server : #YYYY/MM/DD#
DB2 : Calendrier julien
Il faut alors passer par des formules de convertions.

- champ like chaine de carractre


Like s'utilise avec 2 caractre magique :
- soulign _ : remplace n'importe quel autre carractre
-%: remplace n'importe quelle chane de carractre

Exemple :
- La liste des etudiants dont le nom commence par la la lettre M.
select * from etudiant where nom like 'M%'
- La liste des etudiants dont le nom se termine par ING
select * from etudiant where nom like '%ING'
- La liste des etudiants dont le nom contient TOTO
select * from etudiant where nom like '%TOTO%'
- La liste des etudiants dont le nom commence par MI et se termine par MI puis 3 caractres suivi
du caractre T et se terminant par X
select * from etudiant where nom like 'MI_ _ _ T%X'

Attention : Like n'est pas une expression rgulire mais pratique pour faire une recherche
notamment. Recherche d'un article contenant quelquechose.
Le moteur de BD va examiner toutes les occurences de la tables = pas de recherche par index =>
acccelerer les recherches (comme avec l'utilisation de =)

- Condition avec l'oprateur in :


1) expression in ( valeur1 , valeur2 , ... )

La condition est vrai si l'expression est egale l'une des valeurs mentionnes dans la liste.

Ex : Recherche de tous les tudians en SIO ou IG ou MUC


select * from etudiants where codesection in ( 'SIO' , 'IG' , 'MUC' )
Equivalent :
select * from etudiants where codesection = 'SIO' or codesection = 'IG' or codesection = 'MUC'

2) expression in ( select ... from .... )

sous requete qui ramene une liste de valeur

Ex : Recherche des etudiants prsent dans les sections dont le libell contient le mot
'informatique'
2 tables : Etudiants ( numetu, nom, prenom, ... codesec# ) Modle relationnel ou logique
Sections ( codesec, libsection ) de donn
select * from etudiants where codesec in ( select codesec from sections where libsection like
'%informatique%' )
La sous requete ramne la liste des codesec de toutes les dections dont le libell contient le mot
'informatique'.

Equivalent :
select etudiants.* from etudiants, sections where etudiants.codesec = sections.codesec and libsection
like '%informatique%'
etudiants.codesec = sections.codesec => Condition de jointure interne :
etudiant.* => ramene tous les champs de la table etudiant
libsection => on ne prcise la table (etudiant.) que lorsqu'il y a une ambiguit sur le champ
(1 mme champ dans 2 tables)

Parmis toutes les combinaisons gnrs je ne prend que les conditions pour lesquel la valeur de
codesec tudiants est egal la valeur de codesec sections. Plus rapide qu'avec l'oprateur in.

Remarque :
- Avec l'operateur in, la sous requette est execute pour chaque ligne ramene par la requette
principale (moins rapide)
- Une sous requette peut utiliser des champs venant de la requette principale.

Ex : Liste des tudiants presents dans les sections dont le libell de section contient le prnom de
l'tudiant
select * from etudiants where codesec in ( select codesec from sections where libesection like
'%' , prenom , '%' ) (sous MySQL) prenom provient de la table etudiants
Operateur de concatenation :
Oracle champ1 | champ2 | champ 3
MySQL champ1 , champ2 , champ 3

Remarque :
- Le plus souvent, l'operateur in est prcd d'un epression ou d'un champs et donc la sous requette
ramene une expression ou un champ.
On peut utiliser des couples ou triplet d'expression ou le champ precedent l'operateur in avec des
sous requette ramenant des couples ou tripets d'expression.
(expression1 , expression2 ) in ( select expression1 , expression2 from ... )

- Utilisation de not in :
Not in permet de chercher quelquechose qui ne figure pas dans autre chose. (c'est souvent le seul
moyen de raliser ce genre de requette.

Ex : Requette donnant la liste des sections ne contenant pas d'tudiants


Il faut traduire cette requette en la requette suivante :
Liste des sections dont le codesec n'appartient pas la liste des codesc utilis par des etudiants.

select * from sections where codesec not in ( select codesec from tudiants );

Pas possible de faire un select * from sections where etudiants.codesec <> sections.codesec ne
ramenera rien car le produits cartsiens ne trouvera pas de combinaisons valable entre des etudiants
et des sections.

- Utilisation d'une sous requette avec l'operateur = ou avec un operateur de comparaison :


expression = ( select ... )

Ex : Liste des etudiants dont le libell de section est 'Management des Units Commerciales'

select * from etudiants where codesec = ( select codesec from sections where libesection =
'Management des Units commerciales' )

Dans ce cas la sous requette doit obligoirement ramener strictement une seule valeur.
Il faut absolument que la sous requette ne ramene qu'une seule valeur.
La sous requette est ici aussi xecut chaque occurence.

Oprateur exists :
L'oprateur exists s'utilise avec une sous requette. Il renvoie une valeur boolenne, qui sera vrai si la
sous requette ramene au moins une ligne et fausse sinon.

Ex : Etudiants ( numetudiant, nom , prenom , .... )


Noteval ( dateeval , matiere# , numetud# , note )

dateeval matiere numetu note


01/04/12 maths 123 20
01/04/12 maths 456 20
Liste des tudiants ayant particip a au moins une evaluation de math durant l'anne 2012.
On cherche les tudiants pour lesquels il existe au moins une ligne dans la table noteval le
concernant.

select * from etudiants where exists ( select * from noteeval where noteeval.numetu =
etudiants.numetu and year ( dateeval ) = 2012 )

C'est plus efficace de remplacer la dernire condition par :


... and dateeval between '01/01/2012' and '01/01/2013'

Remarque : Les dates sont en fait des date/time quivalent :


'01/01/2013' = 01 janvier 2013 00h00m00s
En finalit la condition est vrai uniquement pour des dates de l'anne 2012

- Oprateur all (tous) et any (quelques un) :

expression oprateur de comparaison all ( select ... )


( =, < , > , <= , >= , <> ) any ( select ... )

Ex : On veut la liste des etudiants en SIO dont l'age est different de celui de tous les etudiants en
MUC
select * from etudiants where codesec = 'SIO' and age <> all ( select age from etudiants where
codesec = 'MUC' )

=> Avec all la condition est vrai si l'application de l'oprateur de comparaison prcdant all est vrai
pour chaque occurrence de la sous requette.
=> Avec any la condition est vrai si l'application de l'oprateur de comparaison precedant any est
vrai pour au moins une occurence de la sous requette.

Ex : Liste des tudiants de SIO ayant un age existant parmis ceux de MUC.
select * from etudiants where codesec='SIO' and age = any ( select age from etudiants where
codesec='MUC' )

- Oprateur is null ou is not null :


Pour rechercher des lignes par rapport un champ qui pourrait ou non tre renseign.
Un champs non renseign dans une occurence d'une table porte une valeur speciale : NULL.
On ne peut pas utiliser les oprateurs <> ou = avec NULL.
A la place on utilise isnull (est renseign) ou is not null (n'est pas renseign).

Ex : On cherche des etudiants dont l'age n'est pas renseign :


select * from etudiants where age is null ;

Clause group by :
syntaxe : groupe by expression1 , expression2 , ....

Le produit cartsien des tables cites dans la clause from produit un tableau intermediaire de ligne.
Celles-ci sont ensuite filtres par la condition de la clause where et enfin on peut oprer un
regroupement des lignes restantes avec la clause groupe by.

Le regroupement se fait sur des valeurs distinctes de la premiere expression (expression1 ). Les
lignes ayant la mme valeur pour l'expression1 subissent ensuite un regroupement interne selon les
valeurs distinctes de la deuxieme expression, et ainsi de suite.
Ex : Regroupement des etudiants par nom puis pour un mme nom par prnom
select * from etudiants groupe by nom , prenom

Remarque :
- Les paquets de lignes avec le mme nom mais elles ne sont pas tris.
- L'utilisation des oprations d'agrgat dans un select : min, max, sum, count, avg est calcul par
dfaut sur l'ensemble des lignes du tableau intermdiaire issus de l'xecutuion de la clause where.
La prsence d'une clause groupe by fait en sorte que le calcul des oprations d'agrgat s'effectue sur
des regroupements de ligne et non sur la totalit des lignes.

Ex : Exemple classique :
On veut la liste des sections; codesec ; libsection avec le nombre d'tudiants par section.
Comme on compte des tudiants on s'arrange pour obtenir un tableau intermediaire ayant autant de
ligne que d'tudiants.
De cette manire il suffit de compter le nombre de ligne avec un count(*)
En faisant un regroupement par codesec et par libesection on compte des lignes et donc des
etudiants par valeurs distinctes de regroupement, c'est dire par section.

select etudiants.codesec, libsection, count(*) as Nbetudiant


from tudiants, sections
where etudiants.codesec = sections.codesec // On obtient une ligne par tudiant
groupe by etudiants.codesec, libsection

Remarque :
Quand on mlange dans la clause select des expressions simples avec des oprations
! d'agrgat ( count ... ) il faut absolument regrouper en utilisant toutes les expressions
simples figurant dans le select.

Clause Having :
Syntaxe : Having condition,

- Pour des raisons d'optimisation, les oprations d'agrgats ne sont xcut qu'aprs les regoupement
de lignes.
- Ceci explique pourquoi on ne peut ecrire de conditions sur resultat d'agrgat dans la clause where
(Dans la clause where, les agrgats n'ont pas encore t calcul)
- SQL prevoit la clause having condition, qui s'executent aprs le clacul des agrgats permet d'ecrire
une condition de filtrage de ligne sur les resultats de ceux-ci.

Ex : Liste des sections avec le nombre d'tudiants mais uniquement les sections ayant plus de 5
etudiants.
select codesec, count(*) as nbetudiants from etudiants groupe by codesec having count(*) >= 5

Attention : Ne pas utiliser la liasse mais remettre l'opration d'agrgat !

Ex : Liste des sections avec nombre d'tudiants par section pour des sections de plus de 5
etudiants dont la moyenne d'age est comprise entre 20 et 22 ans.
select codesec, count(*) as Nbetudiant from etudiants groupeby codesec having count(*) >= 5 and
avg( age ) between 20 and 22

Conditions sur champ simple => Dans le where


Conditions sur agrgat => Dans le Having
Clause de tri : Order by
Syntaxe : order by expression1 asc , expression2 asc , ....
desc desc
Permet de trier les lignes du tableau resultat selon des ordres croissant ou dcroissant de valeur
donnes par des expressions.

Remarque :
- Le tri etant gourmand en CPU, il s'effectue en dernier avec le moins de ligne possible. (consomme
bcp de ressource).
- Le tri se fait d'abord pour la premire expression puis pour la deuxime, puis pour les suivantes.
Par dfaut, celui i est selon un ordre croissant numrique, lexicographique (alphabetique) ou
temporel. Le mot desc permet de le rendre dcroissant.
- Les expressions peuvent comporter des champs, des calculs, et mme des fonctions d'agrgat ...

Exercice :
2 tables : Etudiants ( numetu, nom, prenom, age, codesec# )
Sections ( codesec, libellesec )
Ecrire les requettes suivantes :
- liste des tudiants dont le libell de section se termine par 'tique' tri par ordre croissant de nom et
ordre dcroissant de prenom.
select * from etudiants where codesec in ( select codesec from sections where libesection like
'%tique' order by nom asc, prenom desc

select * from etudiants, sections where etudiants.codesec = sections.codesec and libellesec like
'%tique' order by nom asc, prenom desc

- liste des sections : codesec, libellesec tri par moyenne d'age des etudiants
select etudiants.codesec, libellesec from etudiants, sections
where etudiants.codesec=sections.codesec
groupe by etudiants.codesec, libellesec
order by avg( age )
Exercice :
5 tables : Client ( codecli, raisoc, adresse, ville, cp )
Articles ( ref, libelle, prixht, codecat# )
Catgrorie ( codecat, libcat )
Facture ( numfact, datefact, codecli# )
Lignefact ( numfact# , ref#, qte )

numfact ref qte


123 X700A 10
123 DF352B 3

Ecrire les requettes :


1) Liste des catgories libelle, codecat le nombre d'article, le prix mini et le prix maxi par catgorie
uniquement celles dont le prix maxi est inferieur 100 tri par prix mini croissant.

select catgorie.codecat, libecat, count(*) as nbarticle, min(prixht) as prixmini, maxi(prixht) as


prixmaxi from catgorie, articles
where categorie.codecat=articles.codecat
groupe by catgorie.codecat, libecat
having max(prixht) < 100 / ! \ Attention on utilise pas les alias dans les clauses !
order by min(prixht) asc Les alias ne sont que des noms de colonnes (pas de tri ...)

2) Nombre de facture du client dont la raison sociale est "dupond&co"


select count(*) as nbfacture from facture, client where facture.codecli=client.codecli and raisoc like
"dupond&co"

3) Liste des articles n'ayant jamais t achet


select article.ref, libelle *(1) from Article where article.ref (2) not in ( select lignefact.ref (2) from
lignefact )
(1) Lorsque rien n'est precis comme champs, mettre *
(2) Lorsque l'on selectionne uniquement une table pas besoin de preciser table.

4) Liste des articles, rfrence, libell, prix ht, prix ttc, avec un taux de TVA 19,6%, lib cat tri par
rfrence croissante
select libelle, articles.ref, prixht, prixht*1,196 as prix ttc, libcat from articles, catgories where
articles.codecat=categories.codecat order by ref asc

5) Calcul du total ht et du total ttc de la facture 1234


select sum ( qte * prixht ) as total ht , sum( qte * prixht * 1,196 ) as total ttc from articles, lignefact
where articles.ref=lignefact.ref and numfact = "1234"
Si on ne met pas sum() on va avoir comme resultat autant de ligne de resultat qu'il y a d'article dans
la facture

6) Liste des factures : numfact, datefact, codecli, raison sociale, ville, codepostal, total ht, total ttc
select factures.numfact, datefact, client.codecli, raisonsociale, ville, cp, sum ( qte * prixht ) as
totalht, sum( qte * prixht * 1,196 ) as totalttc
from articles, lignefact , factures, clients
where articles.ref=lignefact.ref and factures.numfact = lignesfact.numfact and
factures.codecli=client.codecli
Group By numfact, datefact, client.codeclient, raisoc, ville, cp
Exercice :
Eleves( numeleve, nom, prenom, section# )
Sections( section, libelle )
Matieres( codemat, libelle )
Notes( dateeval#, numeleve#, codemat# note )

1) Liste des lves nom, prenom, libelle de la section dont le nom commence par la lettre M tris
par ordre alphabetique inverse de prenom

select nom, prenom, sections.libelle


from eleves, sections
where eleves.section=sections.section and prenom like 'M%'
order by prenom desc

2) Liste des sections avec le nombre d'eleve par section uniquement les sections auant au moins 6
leve

select libelle, count(numeleve) from eleves, sections


where sections.section = eleves.sections //Jointure interne
groupeby libelle
having count(numeleve)>=6

3) Liste de matires avec le nombre d'valuation ralises par matire sur l'anne 2012

select codemat, count(*) from notes


where year(dateval) = 2012
groupby codemat, dateval //Compte le nombre d'evaluation differente par matiere

4) La liste des matieres pour lesquelles il n'y a pas d'valuation en 2012

select * from matiere where codemat not in ( select codemat from notes where year(noteval)=2012)

5) La liste des evaluations : libell de matire, date d'valuation, note moyenne, note mini, note
maxi

select libelle, dateeval, avg(note) as moyenne, min( note) as notemin, max(note) as notemax from
matiere, notes where matiere.codemat=notes.codemat groupeby libelle, dateval

6) Le nom et le prenom de l'lve ayant obtenu la meilleure note l'valuation de mathmatique


(codemat ='math') du 17/02/12

select nom, prenom // La requette principale renvoi la note de l'eleve en croisant les tables
from eleve, notes // notes et eleves restreint au note obtenu par l'eleve le jour demand en math
where eleve.numeleve=notes.numeleve and dateeval='17/02/12' and codemat='math'
and note in* ( select max( note ) as notemax // La sous requette renvoi la meilleure note obtenue
from notes
where codemat='math' // pour selectionner mathematique
and dateeval='17/02/12' ) // et la date du 17/02/12

* Ici on peut aussi mettre un = puisque la sous requette renvoie une seule valeur
7) Liste des lves matiere nom, prenom et la moyenne par matiere tris par matire et par moyenne
decroissante

select libelle, nom, prenom, avg(note) as moyenne


from matiere, eleve, notes
where matiere.codemat=notes.codemat and eleve.numeleve=note.numeleve
groupby libelle, nom, prenom
orderby libelle, avg(note)

Ordre de transaction
Partie transactionnelle du language SQL, les requetes insert, delete, update sont appells des
transactions

INSERT
insert into table ( champ1, champ2, ...)
values (valeur1, valeur2, ... )

Attention : Ne pas utiliser la forme insert into table values (valeur1, valeur2, ... ) car les champs
peuvent tre melangs

DELETE :
delete from table where conditions

Ex : delete from personnes where nom = 'Dupond'

UPDATE :
update table set champ1=expression1, champ2=expression2, ...
where condition

Ex : update personnes set prenom='Claude', age=age + 1


where nom='Meyer'

Validation et annulation de transaction :


Certains SGBD (Oracle, DB2, SQL Server, Postgress ... ) proposent un mecanisme de
validation/annulation de transaction groupes.
On parle de Commit/rollback (valider /annuler)
Ce mecanisme commence apparaitre sur MySQL

Ex : comptes ( numcpt, solde )


Transfert de 100 du compte n1234 vers le compte n5678

update comptes set solde=solde-100 where numcpt=1234;


update comptes set solde=solde + 100 where numcpt=5678;
commit;

=> Les 2 transactions sont valids ensemble

- L'ordre des transaction est stock dans des journaux (ReDoLog)

Ex : Revenir en arrire dans une transaction Delete


delete from personnes;
rollback;

=> Reviens la derniere transaction rollback efffectu

Acces concurrent et verrou :


Cas 1 :
Table : personnes (matricule, prenom)
Enregistrement matricule 1234, prenom Claude

User A User B
update personnes set prenom = 'Charles'
value matricule = '1234'
select * from personnes where matricule = 1234; select * from personnes where matricule = 1234;
=> Resultat : Charles => Resultat : Claude
Tant qu'il n'y a pas de concurent la transaction n'est pas effectue
commit;
select* from peronnes where matricule = 1234; select* from peronnes where matricule = 1234;
=> Resultat : Charles => Resultat : Charles

Cas 2 :
Table : personnes (matricule, prenom)
Enregistrement matricule 1234, prenom Claude

User A User B
update prenom set prenom='Charles' where
matricule = 1234;
select * from personnes where matricule = select * from personnes where matricule =
1234; '1234'
=> Charles => Claude
update personnes set prenom ='Henri'
where matricule = 1234
Verrou sur l'enregistrement 1234 Blocage de la transaction cause du verrou
pos sur cet enregistreur par la transaction
=> Charles non valide du UserA
Transaction en attente cause du verrou
commit; Le verrou est lev Le verrou tant lev, la transaction est
passe
=> Charles Nouveau verrou pos par la transaction de
User B
commit; Le verrou est lev
=> Henris => Henris

C'est le dernier qui valide sa transaction qui aura raison


Il y a dans tous les SGBD un systeme de verouillage lorsque 2 personnes accdent en mme temps
sur le mme enregistrement et sur le mme champs
Identifiant :

Contrainte d'intgrit : - cl primaire


- contrainte d'intgrit de rfrence

Modle relationnel de donne, schma de table :

table1 ( champ1, champ2, ...)


table2 (champ1, champ2, ...)

Ex : clients( codecli, nom, prenom, adresse )


factures( numfact, datefact, codecli#)
Le champ codecli de factures fait rfrence au client destinataire de la facture et contient donc une
valeur permettant d'identifier un client unique.

Client Factures
codecli nom prenoms numfact datefact codecli#
1 Meyer Charles 123 10/12/11 2
2 Dupond Henris 456 25/02/12 3
3 Durant Stephane 789 10/05/12 2

1) Il faut absolument que le champ codecli de client identifie un seul client de manire unique.
On parle d'identifiant et plus particulirement dans un schma relationel de cl primaire.
Les champs constituant la cl primaire sont soulign.

Considerons la requete suivante :


create table clients (codecli int, nom varchar(30), prenom varchar(30) )
insert into clients values ( 2, 'Meyer', 'Charles' )
insert into clients values (3, 'Dupond', 'Henri' )

Il y aura 2 clients pour le mme identifiant ce qui ne va pas.


On ajoute alors une specification Primary Key au champ codecli :
1) Soit directement lors de la creation de la table :
create table cients ( codecli int primary key, nom varchar(30), ...)
2) Soit aprs coup (exemple sur Oracle) :
alter table clients add constraint nom de contrainte primary key (codecli)
client_pk
Rq : Si aucun nom de contrainte est renseign, le SGBD se charge d'en donner un assez
complexe gnralement (suite de numro)

Le SGBD va alors refuser d'avoir 2 entre dans la table avec le mme codecli.
Les cl primaire sont l pour garantir l'unicit des enregistrement et permettre de referencer les
enregistrements.

Si le codecli n'est pas renseign la valeur sera NULL mais cela ne posera pas de problme
Par contre si le codecli fait reference un client qui n'existe plus ou a t supprim, il va y avoir un
probleme d'intgrit des donnes :
L'ide est de demander au SGBD de verifier si le codecli qu'on associe dans la table facture fait
reference un client existant et inversement si une requete de suppression de client devra tre
interdite pour ceux dont le codecli est associ un enregistrement de la table facture.
On pose alors une contrainte d'intgrit de rfrence :

3) alter table facture s add constraint factures_fk1 foreign key (codecli)


references clients(codecli);
foreign key (codecli) fait ici reference au champ codecli de la table facture
=> Je pose une contrainte sur le champ codecli de la table facture qui fait reference au
champ codecli de la table clients

Le SGBD va alors refuser les requetes update, delete, insert qui ne respecte pas cette contrainte
Garantie qu'il n'existera pas de factures associs des codecli qui n'existe pas.

RQ : Ces contraintes sur MySQL ne seront actives qu'avec le moteur de base de donnes INNODB.

On peut rajouter une option "on update cascade" qui va faire en sorte que s'il y a une modification
du codecli d'un client, les valeurs du champs codecli de la table factures rattach ce client seront
egalement modifi :
4) alter table factures add constraint factures_fk1 foreign key( code cli)
references clients(codecli) on update cascade
Requete pour modifier le codecli du client :
update clients set codecli=6 where codcli=2;

RQ : Existe egalement l'option "on delete cascade" qui va supprimer toutes les factures li au client
Attention dangereux !

Ex : Plusieurs champs en cl primaires :


article ( reference, libelle, prix )
factures( numfact, datefact, codecli#)
lignefactures( numfact#, reference#, quantite )

L'ide est de ne pas pouvoir crer 2 lignes differentes dans une mme factures faisant reference un
meme article.
- On met alors les 2 cl etrangres numfact et reference en cl primaires
- On mettra egalement 2 contraintes d'intgrit de reference pos sur le champ reference et numfact
de ligne facture faisant reference au champs correspondant dans les tables articles et factures.
- Enfin on mettra egalement une option on update cascade pour modifier toutes les references d'un
article dans lignefact lorsqu'une modification est faite sur un article partir de la table article.
- On mettra une option on delete cascade entre la facture et les lignesfactures : on peut dire que la
facture est "propritaire" des lignes de factures qui lui sont associs, la suppression est l logique

5) Contrainte NOT NULL :


- Empecher de pouvoir crer des factures avec des codecli non renseign.
RQ : Par dfaut en SQL, la valeur NULL est autoris (c'est l'inverse en PHP).
Par contre les champs defini en cl primaire ne peuvent pas tre NULL par dfaut.

Ces diffentes contraintes permettent d'avoir une base de donnes intgre.

RQ : Lors de sauvegarde ou de rcupration de base de donnes on peut desactiver les contraintes :


l'export se fait en lignes SQL de type insert de telle sorte que lors du rimport il n'y ai pas de
probleme de blocage du au fait que les lignes factures soit import avant les factures.
On garde la definition de toutes les contraintes mais on les desactive temporairement et on les
ractive une fois la restauration effectue.
Vue ou requette enregistr en base de donne

Au travers de l'instruction CREATE VIEW il est possible d'enregistrer dans la base de donnes une
requette SELECT
Celle-i pourra ensuite tre utilis dans un autre SELECT comme s'il s'agissait d'une table.

Syntaxe gnrale de cration d'une vue :

Create view nomdevue as


Select ....

alter view nomdevue pour modifier une vue


drop view nomdevue pour supprimer une vue

Exemple :

Create view listefactures as


Select f.numfact as numfact, codecli, datefact, sum(qte*prixunitaireHT) as total HT,
sum(qte*prixunitaireHT*tauxtva) as totalTVA, sum(qte*prixunitaireHT*(1+tauxtva)) as
totalTTC
From factures as f, articles as a, facligne as l
where f.numfact=l.numfact and a.codearticle=l.codearticle
groupby f.numfact, codecli, datefact

La rponse la question 9 du devoir en utilisant la vue listefact :

Select codecli, totalHT, as CAHT from listefactures where year(datefact) = 2011

Remarque :
Clich : requete associ une table et qui s'execute rgulierement pour raccourcir le temps
d'execution en ne rxecutant pas la requete SQL.