Bases de donn ´ees – cours 3 Introduction en SQL
Catalin Dima
Pr ´esentation de SQL
◮ SQL est un LDD :
◮ Cr ´eation/modification/suppression de tables.
◮ Cr ´eation d’utilisateurs et gestion des droits.
◮ Impl ´ementations en architectures client-serveur : MySQL, PostgreSQL.
◮ SQL est un LMD :
◮ Impl ´ementation de l’alg `ebre relationnelle.
◮ Langage de requ ˆetesselect-from-where.
◮ Variables de type tuple et attributs r ´ef ´erenc ´es `a la C/Java.
◮
◮ Notre initiation commence par la partie LMD.
◮ SQL est “case-insensitive”.
◮ ... mais nous allons mettre les mots-cl ´e en majuscules pour les diff ´erencier des autres constructions.
Premi `ere version de SELECT
◮ Partons de notre table “Employ ´es”, de sch ´ema Employ ´es(Id, Nom, Pr ´enom, Dept, Salaire).
◮ Afficher les tuples correspondant aux employ ´es du 1er d ´epartement dont le salaire d ´epasse les 34kE :
SELECT * FROM Employ´es
WHERE Dept = 1 AND Salaire >= 34;
◮ Forme de requ ˆete de base en SQL,select-from-where:
◮ La clauseFROMdonne la (ou les) relation(s) sur laquelle (lesquelles) la requ ˆete s’applique.
◮ La clauseWHEREest uneconditionjouant le m ˆeme r ˆole que la condition d’une op ´eration de s ´election, typeσC.
◮ La clauseSELECTpermet d’indiquer quelsattributssont `a garder et `a afficher lors du calcul du r ´esultat, similaire `a une op ´eration de projectionπA1,...,Ak.
◮ Utiliser*dans unSELECTindique que tous les attributs produits pendant le calcul seront retenus.
◮ R ´esultat pour notre requ ˆete ....
Projection en SQL
◮ Comme indiqu ´e, la partieSELECTde toute requ ˆete de type select-from-where permet d’impl ´ementer l’op ´eration de projection.
◮ Attention donc ! La clauseSELECTne correspond pas `a une s ´election !
◮ Afficher les noms et pr ´enoms des employ ´es du 1er d ´epartement dont le salaire d ´epasse les 34kE :
SELECT Nom, Pr´enom FROM Employ´es
WHERE Dept = 1 AND Salaire >= 34;
◮ Syntaxe permettant d’impl ´ementer une projection suivie d’un renommage : afficher les ID des employ ´es du 1er d ´epartement dont le salaire d ´epasse les 34kE, tout en renommant la colonne de la table r ´esultat enNoCrt:
SELECT Id AS NoCrt FROM Employ´es
WHERE Dept = 1 AND Salaire >= 34;
Projection en SQL (2)
◮ Encore une autre variante de syntaxe, permettant de recalculer un nouvel attribut (iciSalMens) et de cr ´eer un autre nouvel attribut poss ´edant une valeur constante (iciMonnaie) :
◮ Afficher les ID des employ ´es du 1er d ´epartement dont le salaire d ´epasse les 34kE, et afficher aussi leur salaire mensuel (en Euro cette fois-ci) plus une colonne suppl ´ementaire contenant la chaˆıne
’Euro’:
SELECT Id AS NoCrt, Salaire/12*1000 AS SalMens,
’Euro’ AS Monnaie FROM Employ´es
WHERE Dept = 1 AND Salaire >= 34;
S ´election en SQL
◮ La partieWHEREpermet de filtrer des tuples selon la condition d ´eclar ´ee.
◮ Conditions construites `a l’aide d’op ´erateurs sur les types primitifs.
◮ Variables utilis ´ees dans les conditions =noms d’attributsde la (des) relation(s) indiqu ´ee(s) dans la clauseFROM.
◮ D ´esambiguation parfois n ´ecessaire (on en reviendra).
◮ Op ´erateurs arithm ´etiques et pr ´edicats de comparaison comme en C ou Java sur les donn ´ees de type entier ou flottant.
◮ Particularit ´e :<>pour repr ´esenter le pr ´edicat “diff ´erent”, au lieu de!=.
◮ Op ´erateurs bool ´eens pour la construction de contraintes complexes :AND, OR, NOT.
◮ Concat ´enation de chaˆınes de caract `eres : op ´erateur binaire||.
◮ Comparaisons de chaˆınes de caract `eres : op ´erateurs<, <=, >,
>=faisant r ´ef ´erence `a l’ordrelexicographique.
S ´election en SQL
◮ Conditions de typeLIKEdans les comparaisons de chaˆınes de caract `eres :
◮ s LIKE p: la valeur de l’attributsrespecte le patronp.
◮ Patrons de chaˆınes de caract `eres :%remplace n’importe quelle chaˆıne de caract `eres, remplace un seul caract `ere, et’’d ´enote un seul apostrophe.
◮ Les attributs de typeDATEpeuvent ˆetre compar ´es avec des valeurs constantes de la formeDATE ’2011-12-31’.
◮ Similaire pourTIME.
◮ Exemple pour comparer un attributAttrde typeTIMEavec l’heure 23h45m18s2/10 :
WHERE Attr > TIME ’23:45:18.2’;
Comparaisons impliquant la valeur NULL et valeur bool ´eenne UNKNOWN
◮ Les attributs peuvent prendre la valeurNULL.
◮ Exemple : jointure externe.
◮ Pour cela,WHEREdoit permettre la manipulation et la comparaison de cette valeur.
◮ Deux r `egles importantes pour la prise en compte de cette valeur :
1. Le r ´esultat de chaque op ´eration devientNULLlorsqu’au moins une op ´erande estNULL.
2. Le r ´esultat de chaque comparaison devientUNKNOWNlorsqu’au moins une op ´erande estNULL.
3. MaisNULLne peut pas ˆetre utilis ´e en tant que constante !
◮ ValeurUNKNOWN=troisi `emevaleur de v ´erit ´e !
Logique `a trois valeurs de v ´erit ´e
◮ Tables de v ´erit ´e pour les op ´erateurs bool ´eens :
x y xANDy xORy NOTx
TRUE TRUE TRUE TRUE FALSE
TRUE UNKNOWN UNKNOWN TRUE FALSE
TRUE FALSE FALSE TRUE FALSE
UNKNOWN TRUE UNKNOWN TRUE UNKNOWN UNKNOWN UNKNOWN UNKNOWN UNKNOWN UNKNOWN UNKNOWN FALSE FALSE UNKNOWN UNKNOWN
FALSE TRUE FALSE TRUE TRUE
FALSE UNKNOWN FALSE UNKNOWN FALSE FALSE FALSE FALSE FALSE FALSE
Produit cart ´esien et jointure naturelle en SQL
◮ La clauseFROMforce l’utilisation de plus d’une seule table dans le reste de la requ ˆete.
◮ Les param `etres deFROMforment une liste de tables...
◮ ... lesquelles sont combin ´es parproduit cart ´esien, avant de passer au traitement du reste de la requ ˆete.
◮ Pour deux relationsAetB, le produit cart ´esienA×Bse calcule en SQL comme suit :
SELECT * FROM A, B;
◮ ClauseWHEREoptionnelle !
◮ Pour calculer la jointure naturelle, il faut utiliser l’impl ´ementation de la projection parSELECTet la s ´election parFROM.
◮ En supposant que les sch ´emas des deux tables sontA(X,Y,Z) etB(U,X,V,Y), leur jointure naturelle se calcule en SQL comme suit :
SELECT A.X, A.Y, Z, U, V FROM A, B
WHERE A.X=B.X AND A.Y=B.Y;
Utilisation de select-from-where sur plusieurs relations
◮ Prenons notre table “Employ ´es” de sch ´ema Employ ´es(Id, Nom, Pr ´enom, Dept, Salaire).
◮ Et une deuxi `eme table “D ´epartements”, de sch ´ema D ´epartements(NoDept, Nom, Projet, Budget).
◮ Afficher les personnels qui travaillent dans un projet de plus de 500kE et gagnent moins de 34kE :
◮ Il faut rassembler les deux tables pour avoir toutes les informations.
◮ Rassembler = produit cart ´esien.
SELECT Nom, Pr´enom
FROM Employ´es, D´epartements
WHERE Dept=NoDept AND Budget>=500 AND Salaire<=34;
◮ Expression en alg `ebre relationnelle :
πNom,Pr ´enom
σDept=NoDept∧Budget≥500∧Salaire≤34 Employ ´es×D ´epartements
Op ´erations bool ´eennes en SQL
◮ Intersection :
(SELECT Nom, Pr´enom FROM Employ´es WHERE Dept = 1) INTERSECT
(SELECT Nom, Pr´enom FROM Employ´es
WHERE Salaire >= 34);
◮ Union : similaire, mot-cl ´eUNION.
◮ Diff ´erence : similaire, mot-cl ´eEXCEPT:
◮ Afficher les tuples correspondant aux employ ´es du 1er d ´epartement dont le salaire est inf ´erieur `a 34kE : (SELECT Nom, Pr´enom
FROM Employ´es WHERE Dept = 1) EXCEPT
(SELECT Nom, Pr´enom FROM Employ´es
WHERE Salaire >= 34);
Variables de type tuple
◮ Parfois on a besoin de r ´ef ´erencer la m ˆeme relation deux fois dans la m ˆeme requ ˆete.
◮ Afficher les personnels qui travaillent dans au moins deux projets.
◮ Il nous faut pouvoir r ´ef ´erencer la table “Employ ´es” deux fois.
◮ La syntaxe deFROMpermet de d ´efinir desvariables de type tuple, prenant comme valeur une table et pouvant ˆetre r ´ef ´erenc ´ee `a l’int ´erieur de la requ ˆete :
SELECT Nom, Pr´enom
FROM Employ´es, D´epartements Dep1, D´epartements Dep2 WHERE Dept=Dep1.NoDept AND Dept=Dep2.NoDept
AND Dep1.Projet<>Dep2.Projet;
◮ Petit probl `eme : le personnel qui travaille sur trois ou plusieurs projets apparaˆıt au moins deux fois...
◮ Construire une relation sans duplicats :SELECT DISTINCT
SELECT DISTINCT Nom, Pr´enom
FROM Employ´es, D´epartements Dep1, D´epartements Dep2 WHERE Dept=Dep1.NoDept AND Dept=Dep2.NoDept
AND Dep1.Projet<>Dep2.Projet;
Imbrication des requ ˆetes dans les conditions WHERE
◮ On peut utiliser des sous-requ ˆetes pour construire des valeurs/tables sur lesquelles on peut v ´erifier certaines conditions.
◮ Retrouver les d ´epartements qui sont impliqu ´es dans le d ´eveloppement du jeu en r ´eseau peut se faire dans une sous-requ ˆete, dont le r ´esultat peut ˆetre utilis ´e dans la clause WHERE:
SELECT Nom, Pr´enom FROM Employ´es WHERE Id IN
(SELECT NoDept FROM D´epartements
WHERE Projet = ’Jeu en r´eseau’
);
Conditions dans les clauses WHERE
◮ Autres conditions sur les tables obtenues par sous-requ ˆetes :
◮ Test d’ ´egalit ´es = R,erreursi le r ´esultatRde la sous-requ ˆete contient plus d’une seule ligne ou plus d’une seule colonne.
◮ EXISTS R, vrai siRn’est pas vide.
◮ s > ALL R, vrai sisest plus grand que toutes les valeurs de la tableRunaire(c. `a.d.ayant une seule colonne).
◮ ErreursiRcontient deux colonnes ou plus !
◮ Similaire avec toutes les autres pr ´edicats de comparaison,<, <=,
>=, <>.
◮ s > ANY Rvrai s’il existe une valeur dansR(encore une fois relation unaire) qui est plus petite ques. (Aurait d ˆu ˆetre nomm ´e SOME...).
◮ NOTpeut ˆetre employ ´e sur n’importe quelle condition.
Requ ˆetes corr ´el ´ees
◮ Prenons une table de sch ´ema Projets(PrjId,Nom,Ann ´ee).
◮ On cherche les projets qui se sont d ´eroul ´es sur deux ann ´ees ou plus.
◮ Solution en utilisant desrequ ˆetes corr ´el ´ees:
SELECT DISTINCT PrjId, Nom FROM Projets OldPrj WHERE Ann´ee < ANY
(SELECT Ann´ee FROM Projets
WHERE PrjId=OldPrj.PrjId );
◮ Hypoth `ese :PrjIdest une cl ´e primaire.
◮ La sous-requ ˆete est ´evalu ´eepour toute instance de l’attribut Old.PrjId.
Sous-requ ˆetes dans les clauses FROM
◮ Revenons aux tables Employ ´es et D ´epartements.
◮ Rajoutons une table RespProj de responsables de projets, de sch ´ema RespProj(Nom, Pr ´enom,Projet).
◮ Afficher les personnels qui travaillent dans les projets dont le responsable est M. Untel Quelqun :
◮ Retrouver d’abord les ProjId dont le responsable est ce monsieur,
◮ ... en mettant le r ´esultat dans une relation.
◮ Construire en parall `ele une relation qui indique qui travaille dans quel projet.
◮ Enfin, combiner les deux relations et afficher le r ´esultat.
SELECT Nom, Pr´enom
FROM RespProj, (SELECT Nom, Pr´enom, Projet FROM Employ´es, D´epartements
WHERE Dept=NoDept) PersProj
WHERE RespProj.Nom=’Quelqun’ AND RespProjet.Pr´enom=’Untel’
AND RespProj.Projet = PersProj.Projet;
◮ Remarquer l’utilisation d’une variable de type tuple r ´ecup ´erant le r ´esultat de la sous-requ ˆete.
Construction de nouvelles relations par diff ´erentes variantes de jointure
◮ La clauseFROMest cens ´ee s’appliquer `aune relation.
◮ La virgule remplace le produit cart ´esien.
◮ CROSS JOINest un synonime pour le produit cart ´esien, donc la clause suivante :
FROM Employ´es, D´epartements
est ´equivalente `a :
FROM Employ´es CROSS JOIN D´epartements
Construction de nouvelles relations par diff ´erentes variantes de jointure (2)
◮ Laθ-jointure est aussi impl ´ement ´ee :
Employ´es JOIN D´epartements ON
Employ´es.Dept = D´epartement.NoDept
◮ Enfin, si on veut calculer la jointure naturelle des deux tables, il suffira de projeter le r ´esultat pr ´ec ´edent sur les attributs
non-r ´edondants, c. `a.d. :
SELECT Id, Nom, Pr´enom, Dept, Salaire, D´epartements.Nom, Budget, Projet FROM Employ´es JOIN D´epartements ON
Employ´es.Dept = D´epartement.NoDept;
◮ Et enfin, les jointures externes sont impl ´ement ´ees aussi :
◮ La jointure externe bilat ´erale :NATURAL FULL OUTER JOIN.
◮ La jointure externe gauche :NATURAL LEFT OUTER JOIN.
◮ La jointure externe droite :NATURAL RIGHT OUTER JOIN.
Aggr ´egation en SQL
◮ SQL offre cinq op ´erateurs d’aggr ´egation :SUM, AVG, MIN, MAXetCOUNT.
◮ Ils sont appliq ´es, habituellement, `a un nom d’attribut (colonne), construisant une table ayant une seule unaire et ayant une seule ligne.
◮ Exception pour l’expressionCOUNT(*), qui calcule le nombre de tuples obtenus par les clausesFROM/WHILEde la requ ˆete.
◮ Afficher la moyenne des salaires et le nombre d’employ ´es : SELECT AVG(Salaire), COUNT(*)
FROM Employ´es;
◮ On peut ´eliminer les duplicats en mettant le mot-cl ´eDISTINCT devant l’op ´erande, comme dansCOUNT(DISTINCT Salary).
Groupement en SQL
◮ Afficher la liste des salaires dans l’entreprise, et pour chaque valeur de salaire le nombre de salari ´es ayant le salaire respectif.
◮ Il nous faut grouper les tuples par salaire,
◮ ... puis, pour chaque groupe, appliquer un op ´erateurCOUNT.
◮ Solution pour grouper :GROUP BY, suivi par le nom d’attribut sur lequel le groupement se fait.
SELECT Salaire, COUNT(Id) FROM Employ´es
GROUP BY Salaire
◮ Une table “interm ´ediaire” est construite, dans laquelle les lignes sont group ´ees selon la valeur de l’attribut Salaire.
◮ On peut imaginer qu’on aura, dans cette nouvelle table, autant de lignes que de valeurs de salaire diff ´erentes, et, dans chaque ligne, des “sous-lignes” contenant les tuples de notre table initiale.
◮ L’op ´erateur aggr ´eg ´eCOUNTproduira alors un r ´esultat pour chaque groupe, donc pour chaque (macro)-ligne.
Clauses de type HAVING
◮ En groupant, il peut ˆetre utile de filtrer les groupes par une condition.
◮ C’est l’utilit ´e du mot cl ´eHAVING.
◮ Exemple : produire la liste des d ´epartements avec, pour chacun, la somme des budgets des projets dans lesquels l’employ ´e respectif participe, le tout seulement pour des budgets sup ´erieurs `a 500kE :
SELECT Nom, SUM(Budget) FROM D´epartements GROUP BY Budget
HAVING MIN(Budget) > 500;
◮ A noter que l’aggr ´egation dans la clause` HAVINGs’applique seulement aux tuples du groupe en cours de construction.
◮ Tout attribute des relations dans la clauseFROMpeut ˆetre utilis ´e dans la clauseHAVING, mais seulement les attributs dans la clauseGROUP BYpeuvent apparaˆıtre non-aggr ´eg ´es dans HAVING.
Trier les r ´esultats
◮ Enfin, on peut trouver parfois utile de trier les r ´esultats d’une requ ˆete.
◮ Mots-cl ´eORDER BY, suivis par la liste d’attributs sur lesquels le tri est fait.
◮ Si plusieurs attributs dans la liste, alors on utilise l’ordre lexicographique sur les tuples :
◮ Si deux tuples t1et t2ont les m ˆemes valeurs pour les attributs A1,A2, alors le premier `a ˆetre affich ´e sera celui qui a la valeur de l’attribut A3la plus petite.
Ex ´ecution des requ ˆetes SQL
◮ Supposons une requ ˆete simple SQL :
SELECT A, B FROM R1, R2 WHERE C
◮ L’ ´evaluation et la r ´eponse `a cette requ ˆete est construite ainsi : 1. On prend chaque tuple dans la relationR1,
2. ... et chaque tuple dans la relationR2, 3. Si les deux tuples satisfont la clauseWHERE,
4. ... alors on ´evalue les expressions dans la clauseSELECT, 5. ... et on construit les tuples de valeurs calcul ´es dans leSELECT.