Vous êtes sur la page 1sur 12

Chapitre 6 Les sous-requtes

Une caractristique trs puissante de SQL est la possibilit dimbriquer une requte SQL
(SELECT) dans une autre. En effet, nous pouvons utiliser le rsultat dune requte pour formuler
une condition que lon utilise dans une autre requte dite requte principale.
Supposons quon veuille afficher les noms des employs qui sont mieux pays que ALLEN.
Pour rsoudre ce problme nous avons besoin de deux requtes ; la premire est dite sous-requte
et servira extraire le salaire de ALLEN. La deuxime est dite requte principale et servira
extraire les noms des employs en question en utilisant le rsultat de la sous-requte.
Il existe deux grandes familles de sous-requtes ; les sous-requtes corrles (synchronises, ou encore
dites dpendantes). Lexcution de ce type de requtes dpend de lexcution de la requte
principale do la corrlation. Ce type de requtes est complexe, il sera trait dans une section
ultrieure (dont worry). La deuxime famille est celle des sous-requtes non corrles, et dont
lexcution ne dpend pas de celle de la requte principale. La sous-requte est alors excute la
premire, son rsultat est utilis sparment pour lexcution de la requte principale.

6.1 Les sous-requtes simples (non corrles)


Une sous-requte simple peut tre incluse dans les clauses :
-

WHERE

HAVING

FROM.

Dans le cas o elle est incluse dans les deux premires clauses, le rsultat de la sous-requte est
utilis comme tant un critre de recherche. Utilise dans la 3me clause, la sous-requte retourne
une relation (table virtuelle) partir de laquelle on pourrait extraire nos donnes. Lorsque la sousrequte est utilise dans les deux premires clauses, la requte principale a la forme suivante :
SELECT colonne(s) FROM table
WHERE exp OPERATEUR (SELECT colonne FROM table) ;
Il est vident quil doit y avoir une certaine cohrence entre lexpression exp quon a besoin de
comparer (expression de recherche, gnralement une colonne), loprateur de comparaison
OPERATEUR et le rsultat de la sous-requte. En dautres termes, la condition de la clause
WHERE doit tre construite logiquement (on ne peut pas comparer une colonne une liste de
valeurs si loprateur est =).
Une sous-requte simple retourne une relation une seule ligne ou plusieurs lignes. La
famille des sous-requtes simples peut tre alors divise en deux sous-familles, les sous-requtes
produisant une seule ligne et les sous-requtes produisant plusieurs lignes.

Chapitre 6 : Les sous-requtes

28

6.1.1 Les sous-requtes produisant une seule ligne


Ce type de sous-requte produit une relation une seule ligne. Loprateur de comparaison
OPERATEUR est alors un oprateur de comparaison classique (=,>,,<, , !=).
REQ 45
Afficher les noms et les salaires des employs mieux pays que ALLEN ?
SELECT ENAME, SAL FROM EMP
WHERE SAL>(SELECT SAL FROM EMP
WHERE ENAME=ALLEN) ;
Ici, nous avons besoin dune seule valeur, le salaire de Mr ALLEN. Imaginez que la sousrequte retourne plusieurs lignes (plusieurs salaires). Dans ce cas la comparaison naura aucun
sens et la requte principale retourne une erreur.
REQ 46
Afficher lemploy le moins pay dans lentreprise ?
SELECT * FROM EMP
WHERE SAL=(SELECT MIN(SAL) FROM EMP) ;
Il faut savoir quon peut comparer par couples de valeurs (plus gnralement un uplet de
valeurs). Dans ce cas, la sous-requte est autorise produire une relation une seule ligne et
plusieurs colonnes, on ne peut utiliser que les oprateurs = ou !=.
REQ 47
Afficher les employs ayant le mme job et dpartement que MARTIN ?
SELECT ENAME, JOB, DEPTNO FROM EMP
WHERE (DEPTNO,JOB)=(SELECT DEPTNO, JOB FROM EMP
WHERE ENAME=MARTIN) ;

6.1.2 Les sous-requtes produisant plusieurs lignes


Ce type de sous-requte doit tre utilis avec les oprateurs convenables. Ces oprateurs sont :
-

IN suivie dune liste de valeurs, la condition est vraie si notre exp est gale lune des
valeurs de la liste.

op ANY suivie dune liste de valeurs, la condition est vraie si la comparaison (en utilisant
loprateur op) est vraie pour nimporte quelle valeur de la liste.

op ALL suivie dune liste de valeurs, la condition est vraie si la comparaison (en utilisant
loprateur op) est vraie pour chaque valeur de la liste.

(Ici, op est un oprateur de comparaison classique).


Le langage SQL version Oracle Document 1.1
Feedbacks anis.bach@isg.rnu.tn

Chapitre 6 : Les sous-requtes

29

REQ 48
Afficher les employs les moins pays pour chaque dpartement ?
SELECT ENAME, SAL, DEPTNO FROM EMP
WHERE SAL IN (SELECT MIN(SAL) FROM EMP
GROUP BY DEPTNO) ;
ENAME
SAL DEPTNO
SMITH
800
20
JAMES
950
30
MILLER 1300
10
Maintenant, supposons que lemploy ADAMS qui travaille dans le dpartement 20 a le
salaire 1300 au lieu de 1100. ADAMS sera affich, car son salaire figure parmi les valeurs que
retourne la sous-requte. Cette solution prsente donc une faille, elle affichera tous les employs
dont le salaire est 1300, et non seulement les employs du dpartement 10 et dont le salaire est
1300 (de mme pour les valeurs 950 et 800). La bonne solution doit prendre en compte le
DEPTNO dans la comparaison.
REQ 49
Afficher les employs les moins pays pour chaque dpartement ?
SELECT ENAME, SAL, DEPTNO FROM EMP
WHERE (SAL,DEPTNO) IN (SELECT MIN(SAL),DEPTNO FROM EMP
GROUP BY DEPTNO) ;
Les oprateurs ANY et ALL peuvent tre utiliss avec tous les oprateurs de comparaison
classiques si on veut comparer une colonne plusieurs valeurs. La requte aura la forme
suivante :
SELECT colonne(s) FROM table
WHERE exp OPERATEUR_CLASSIC ANY/ALL (SELECT colonne
FROM table) ;
REQ 50
Afficher les employs qui sont mieux pays que tous les employs du dpartement 30 ?
SELECT ENAME, SAL FROM EMP
WHERE SAL > ALL (SELECT SAL FROM EMP
WHERE DEPTNO=30) ;
On peut aussi comparer une liste de colonnes (uplet de colonnes) au rsultat dune sousrequte ramenant plusieurs colonnes et plusieurs lignes. La requte aura la forme suivante :
SELECT colonne(s) FROM table
Le langage SQL version Oracle Document 1.1
Feedbacks anis.bach@isg.rnu.tn

Chapitre 6 : Les sous-requtes

30

WHERE (exp1,exp2,,expn) OPERATEUR_CLASSIC ANY/ALL


(SELECT exp1,exp2,,expn FROM table) ;
Dans ce cas, loprateur classique ne peut tre que = et !=.
Il faut noter que :
-

= ANY IN

= ALL et != ANY non aucun sens.

!= ALL NOT IN

Une ligne et une colonne

Une ligne et plusieurs colonnes

=, !=,>,,<,

=, !=

Plusieurs lignes et une colonne

Plusieurs lignes et plusieurs colonnes

[NOT] IN
(=, !=,>,,<,) ANY/ALL

[NOT] IN
= ANY ; !=ALL

Rcapitulatif des sous-requtes simples :


Oprateurs utiliss selon le nombre de colonnes et de lignes retournes

REQ 51
Afficher les dpartements ayant une moyenne de salaires suprieure celle du dpartement
30 ?
SELECT DEPTNO, AVG(SAL) FROM EMP
GROUP BY DEPTNO
HAVING AVG(SAL)>(SELECT AVG(SAL) FROM EMP
WHERE DEPTNO=30) ;
REQ 52
Afficher le job ayant la plus grande moyenne de salaires ?
SELECT JOB, AVG(SAL) FROM EMP
GROUP BY JOB
HAVING AVG(SAL)=(SELECT MAX(AVG(SAL)) FROM EMP
GROUP BY JOB) ;
Il est noter quon ne peut pas trier une sous-requte. On ne peut utiliser la clause ORDER
BY qu la fin de la requte principale pour trier le rsultat final.

6.2 Les sous-requtes corrles (synchronises)


Une sous-requte corrle est une sous-requte dont lvaluation se fait pour chaque ligne de
la requte principale. Supposons quon veut afficher les employs dont le salaire est suprieur la
moyenne des salaires de leurs dpartements. La condition de la clause WHERE doit tre
Le langage SQL version Oracle Document 1.1
Feedbacks anis.bach@isg.rnu.tn

Chapitre 6 : Les sous-requtes

31

spcifique chaque employ, dans la mesure ou chaque employ a un dpartement, et chaque


dpartement a une moyenne de salaires diffrente.
REQ 53
Afficher les employs dont le salaire est suprieur la moyenne de salaires dans leurs
dpartements ?
SELECT * FROM EMP E
WHERE SAL>(SELECT AVG(SAL) FROM EMP
WHERE E.DEPTNO=DEPTNO) ;
Lexcution de cette requte se produit ainsi :
1- La requte principale fixe une ligne de la table EMP.
2- Ayant E.DEPTNO, la sous-requte est value.
3- La condition de la clause WHERE de la requte principale est value, la ligne est
retourne ou non suivant la valeur de la condition.
4- Itration des tapes 1, 2 et 3 pour les lignes restantes de la table EMP.

6.3 Loprateur EXISTS


Loprateur EXISTS est gnralement suivi dune sous-requte corrle. Cet oprateur prend
la valeur VRAI si la sous-requte ramne au moins une ligne, et la valeur FAUX si la sous-requte
ne ramne aucune ligne. Dans le cas o cet oprateur est suivi dune sous-requte simple, il y aura
excution de celle-ci et ds quelle ramne une ligne EXISTS prend la valeur VRAI et la requte
principale affiche toutes les lignes. Si la sous-requte ne ramne aucune ligne, alors la requte
principale ne retourne aucune ligne. Il en dcoule linutilit dune sous-requte simple venant
aprs loprateur EXISTS, car dans ce cas il y aura affichage de toute les lignes (si EXISTS est
VRAI) ou daucune (si EXISTS est FAUX).
REQ 54
Afficher les employs qui dirigent au moins un autre employ ?
SELECT * FROM EMP M
WHERE EXISTS (SELECT * FROM EMP E
WHERE M.EMPNO=E.MGR);
Ici, pour chaque employ de la table EMP, la sous-requte est excute. Pour SMITH, la
sous-requte (SELECT * FROM EMP WHERE MGR=7369 ) ne retourne aucune ligne,
EXISTS prend la valeur FAUX et notre employ ne sera pas affich.
Il faut noter quen gnral dans la sous-requte, la clause SELECT peut contenir nimporte
quelle colonne, expression, fonction ou mme littral (constante) car ce qui importe pour notre
oprateur, cest le nombre de lignes retournes (0 ou au moins 1).
Le langage SQL version Oracle Document 1.1
Feedbacks anis.bach@isg.rnu.tn

Chapitre 6 : Les sous-requtes

32

La requte prcdente peut tre ralise par la jointure ou par loprateur IN :


REQ 55
SELECT DISTINCT M.EMPNO, M.ENAME, M.JOB, M.DEPTNO
FROM EMP E, EMP M
WHERE E.MGR=M.EMPNO ;
REQ 56
SELECT EMPNO, ENAME, JOB, DEPTNO
FROM EMP
WHERE EMPNO IN (SELECT DISTINCT MGR FROM EMP) ;
EMPNO ENAME
756
6

769

778

778

783

REQ 57

790

JOB

JON
ES
KE
RK
TT
G
D

BLA
CLA
SCO
KIN
FOR

DEPTNO

MANAGE

20

MANAGE

30

MANAGE

10

ANALYS

20

PRESID
ENT
ANALYS
T

10

R
R
R
T

20

Afficher les employs qui nexistent dans aucun dpartement de DEPT ?


SELECT * FROM EMP
WHERE NOT EXISTS (SELECT DEPTNO FROM DEPT
WHERE EMP.DEPTNO=DEPT.DEPTNO);
Aucune ligne slectionne.
REQ 58
Afficher les dpartements dans lesquelles nexiste aucun employ ?
SELECT * FROM DEPT
WHERE NOT EXISTS (SELECT * FROM EMP
WHERE EMP.DEPTNO=DEPT.DEPTNO);
REQ 59
Afficher les dpartements qui ont au moins un employ ayant un salaire suprieur 10.000 ?
SELECT DNAME FROM DEPT
WHERE EXISTS(SELECT * FROM EMP
Le langage SQL version Oracle Document 1.1
Feedbacks anis.bach@isg.rnu.tn

Chapitre 6 : Les sous-requtes

33

WHERE DEPTNO=DEPT.DEPTNO AND SAL>1000);

6.4 NOT EXISTS vs NOT IN


Les deux oprateurs peuvent tre utiliss pour rsoudre la mme interrogation, mais il existe
une diffrence entre les deux.
REQ 60
Afficher les employs qui ne dirigent aucun autre employ ?
SELECT M.EMPNO, M.ENAME FROM EMP M
WHERE NOT EXISTS (SELECT * FROM EMP E
WHERE E.MGR=M.EMPNO);
Cette solution nous affiche huit employs dont lEMPNO ne figure pas dans la colonne MGR
(ne sont donc pas des managers).
REQ 61
SELECT EMPNO, ENAME FROM EMP
WHERE EMPNO NOT IN (SELECT MGR FROM EMP) ;
Cette solution, apparemment correcte, naffiche aucune ligne, car la sous-requte simple
retourne la valeur NULL.
Ecrivons la mme requte en dveloppant loprateur NOT IN :
SELECT EMPNO, ENAME FROM EMP
WHERE EMPNO!=7566 AND EMPNO!=7566 AND AND EMPNO!=NULL ;
Or toute expression logique comparant la valeur NULL une colonne est mise FAUX, et
puisque les expressions logiques de la clause WHERE sont connectes par des AND, alors cest
toute la condition qui portera la valeur FAUX.
Le problme peut tre corrig en utilisant la fonction NVL, ou en restreignant les valeurs
NULL via la clause WHERE, ou tout simplement en utilisant loprateur NOT EXISTS.

6.5 La division et le NOT EXISTS


Cest une opration algbrique dont on na pas spcifi doprateur. Il sagit de diviser une
relation R par une autre relation S sur les colonnes qui sont communes. Le rsultat est une
relation D compos par les colonnes non communes entre R et S.
La division de R par S sur lattribut B est la relation D dfinie par :
D = { a R[ A] / b S , (a, b) R } = { a R[ A] / b S , (a, b) R }

R
Le langage SQL version Oracle Document 1.1
Feedbacks anis.bach@isg.rnu.tn

Chapitre 6 : Les sous-requtes


A
B
a1 b1
a1 b2
a2 b1

34

/B

B
b1
b2

D
A
a1

Remarquez que le produit cartsien de S et D est inclus dans la relation R. Ici, D contient les ai
qui sont en relation avec tous les bi de S.
D est alors le rsultat de la question suivante : Donnez les ai de R qui sont en relation avec
tous les bi de S ?
Mais on peut reformuler cette question dune autre manire : Donnez chaque ai de R tel quil
nexiste aucun bi de S qui ne soit pas en relation avec ai ?
Ainsi la traduction de la division dans le langage SQL se fait ainsi :
REQ 62
SELECT A FROM R R1
WHERE NOT EXISTS(SELECT B FROM S
WHERE NOT EXISTS(SELECT A, B FROM R R2
WHERE R2.A=R1.A AND R2.B=S.B);

Lexcution de cette requte est la suivante :

Requte principale
Excution

Rsultat
de
lexcution

1re sous-requte
Excution

Rsultat
de
lexcution

2me sous-requte
Excution

Fixer la 1re valeur


de A qui est a1.
Pour retourner a1,
nous sommes
obligs de passer
la 1re sous-requte
pour valuer la 1re
clause WHERE.
a1 sera retourn
sil nexiste aucune
ligne dans cette
sous-requte.

Le langage SQL version Oracle Document 1.1


Feedbacks anis.bach@isg.rnu.tn

Rsultat
de
lexcution

Chapitre 6 : Les sous-requtes

Requte principale
Excution

Rsultat
de
lexcution

35

1re sous-requte
Excution

Rsultat
de
lexcution

2me sous-requte
Excution

Rsultat
de
lexcution

Fixer la 1re valeur


de B qui est b1.
Pour retourner b1,
il faut que la 2me
sous requte ne
retourne aucune
ligne, cette
dernire est
(SELECT *
FROM R
WHERE A=a1
AND B=b1).

b1 ne sera pas
retourne.

Celle-ci retourne
une ligne.

(a1,b1)

Celle-ci retourne
une ligne.

(a1,b2)

aucune ligne

Fixer la 2me valeur


de B qui est b2.
Pour retourner b2,
il faut que la 2me
sous requte ne
retourne aucune
ligne, cette
dernire est
(SELECT *
FROM R
WHERE A=a1
AND B=b2).

b1 ne sera pas
retourne.

aucune ligne

Tous les bi sont


vrifis. Retour
la requte
principale.

aucune ligne

Le langage SQL version Oracle Document 1.1


Feedbacks anis.bach@isg.rnu.tn

Chapitre 6 : Les sous-requtes

Requte principale
Excution

NOT EXISTS est


vrai pour a1

Rsultat
de
lexcution

36

1re sous-requte
Excution

Rsultat
de
lexcution

2me sous-requte
Excution

Rsultat
de
lexcution

a1

Fixer le 2me A qui


est a2
Fixer la 1re valeur
de B qui est
b1.Pour retourner
b1, il faut que la
2me sous requte
ne retourne
aucune ligne, cette
dernire est
(SELECT *
FROM R
WHERE A=a2
AND B=b1).

b1 ne sera pas
retourne.

Celle-ci retourne
une ligne.

(a2,b1)

Celle-ci ne
retourne aucune
ligne.

aucune ligne.

aucune ligne

Fixer la 2me valeur


de B qui est
b2.Pour retourner
b2, il faut que la
2me sous requte
ne retourne
aucune ligne, cette
dernire est
(SELECT *
FROM R
WHERE A=a2
AND B=b2).

Le langage SQL version Oracle Document 1.1


Feedbacks anis.bach@isg.rnu.tn

Chapitre 6 : Les sous-requtes

Requte principale
Excution

Rsultat
de
lexcution

37

1re sous-requte
Excution

b2 sera alors
retourne

Rsultat
de
lexcution

2me sous-requte
Excution

Rsultat
de
lexcution

b2

il existe une ligne


dans la 1re sousrequte. Donc a2
sera rejete.

Rsultat final D={a1}


Le mme rsultat peut tre obtenu en utilisant le langage algbrique :
R[A]
MINUS
((R[A] TIMES S[B])
MINUS
R[A,B])[A]
La traduction en langage SQL est la suivante :
REQ 63
SELECT A FROM R
MINUS
SELECT A FROM (SELECT R.A, S.B FROM R, S
MINUS
SELECT A, B FROM R)

On peut aussi calculer pour chaque ai, la diffrence entre (tous les bi de S) et (les bi avec qui il
est en relation). Si cette diffrence donne lensemble vide, cest que notre ai est en relation avec
tous les bi de S :

Le langage SQL version Oracle Document 1.1


Feedbacks anis.bach@isg.rnu.tn

Chapitre 6 : Les sous-requtes

38

REQ 64
SELECT A FROM R R1
WHERE NOT EXISTS ( SELECT B FROM S
MINUS
SELECT B FROM R R2
WHERE R2.A=R1.A);

Finalement, la division peut aussi se produire de cette manire ; calculer le nombre de bi


distincts pour chaque ai et le comparer avec le nombre total de bi dans S. Cette mthode nest pas
aussi robuste que les trois qui ont prcd car non efficace dans certaines situations.
REQ 65
SELECT A FROM R
GROUP BY A
HEVING COUNT(DISTINCT B) = (SELECT COUNT(B) FROM S);

Ou encore :
REQ 66
SELECT A FROM R R1
WHERE (SELECT COUNT(DISTINCT B) FROM R R2
WHERE R2.A=R1.A)=(SELECT COUNT(B) FROM S);

Soient les tables suivantes :


F (NF, NOMF, VILLE)
P (NP, NOMP, COULEUR, POIDS, VILLE)
J (NJ, NOMJ, VILLE)
FPJ (NF, NJ, NP, QTE)
REQ 67
Donner les fournisseurs qui livrent toutes les pices de P ?
SELECT NF FROM FPJ X
WHERE NOT EXISTS(SELECT NP FROM P
WHERE NOT EXISTS(SELECT NF, NP FROM FPJ Y
WHERE Y.NF=X.NF AND Y.NP=P.NP));

Le langage SQL version Oracle Document 1.1


Feedbacks anis.bach@isg.rnu.tn