3 valeurs possibles pour expressions booléennes SQL: Vrai, Faux, Inconnu
2=2: Vrai
2=NULL: Inconnu
NULL= NULL: Inconnu
SQL utilise une logique à 3 valeurs pour évaluer les conditions:
NOT Inconnu= Inconnu
OR retourne Vrai si un des arguments est
Vrai, Faux si les deux arguments sont
Faux, Inconnu sinon
AND retourne Vrai si les deux arguments sont
Vrai…
Pour tester si un attribut est défini: attr IS NULL/IS NOT
NULL
Les expressions arithmétiques mettant en jeu un null s'évaluent à
null:
2+NULL renvoie NULL
NULL in SQL: traps
Réécrire les requêtes suivantes
SELECT * WHERE (name <> 'Jean') OR name='Jean';
SELECT * WHERE name = name;
SQL: Langage de Définition de Données
SQL: LDD
Création de schéma
plus exactement, création d'une table vide.
CREATE TABLE Film (Titre CHAR(20), MeS CHAR(20), Acteur VARCHAR(20))
Contraintes
NOT NULL
valeurs uniques
clefs primaires
clefs étrangères
condition de valeurs (check)
Contraintes: NOT NULL
CREATE TABLE Film (Titre CHAR(20) NOT NULL,Acteur VARCHAR(20),
Realisateur CHAR(20) NOT NULL DEFAULT 'Kurosawa')
TITRE ACTEUR REALISATEUR
-----------------------------------------------
Les petits mouchoirs Cotillard Canet
La plage Canet <--
Mon Idole Canet Canet
Bienvenus chez les ch'tis Boon Boon
↪ 2$^{ème}$ instance impossible car la
contrainte sur réalisateur n'est pas respectée.
Contraintes: clef /clef primaire
Elles créent un index implicite.
Contraintes: clef étrangère
La clef étrangère doit être clé primaire (ou unique) dans la table référencée.
Chaque titre de film au programme doit apparaître dans une des lignes
de la table Film.
Vérifié à chaque modification
de Prog ET chaque modification de Film
Récapitulatif des contraintes d'intégrité
Considérons les contraintes :
# dans Cine:
Telephone CHAR(8) NOT NULL CONSTRAINT pk_nc PRIMARY KEY (Nom_Cine)
# dans Prog:
CONSTRAINT fk_cine FOREIGN KEY (Nom_Cine) REFERENCES Cine(Nom_Cine)
UNIQUE (Nom_Cine,Titre, Horaire)
Les tables ci-dessous violent des contraintes (donc instance
impossible) :
Prog
NOM_CINE ADRESSE TELEPHONE
--------- --------- ---------
ugc bercy 3 rue... 06043494
le champo 17 av... 01049059
ugc bercy 18 bd...
Cine
NOM_CINE TITRE SALLE HORAIRE
--------- --------------------- ----- -------
ugc bercy Le discours d'un roi 1 20h00
ugc bercy Le discours d'un roi 3 20h00
ugc bercy Le discours d'un roi 2 22h00
ugc bercy Inception 1 14h00
le champo Le discours d'un roi 1 18h00
le campo Inception 1 20h00
Contraintes: restriction du domaine
Évalue une condition; retourne une erreur si le résultat est
Faux:
CREATE TABLE Prog ( Nom_Cine CHAR(20), Titre CHAR(20),
Salle INT NOT NULL CHECK (1<=salle AND salle<10), Horaire TIME)
La condition peut porter sur plusieurs colonnes de la table, faire
appel à une requête SQL sur une autre table, etc. :
CREATE TABLE Prog ( ..., CHECK ('France'= SELECT pays FROM Cine
WHERE Prog.Nom_Cine=Cine.nom))
Vérifié à chaque modification
de Prog, mais pas de Cine.
Modifier/Détruire des tables (au niveau du schéma)
DROP TABLE Prog; # Erreur si d'autres objets dépendent de la table
En présence de clefs étrangères, respecter l'ordre pour détruire les
tables, ou bien:
DROP TABLE Prog CASCADE;
# Détruit aussi les objets faisant référence à Prog
ALTER TABLE Prog ADD COLUMN jour: DATE
SQL: Langage de Manipulation des Données
LMD
Langage de Manipulation de
Données
( DML: Data Manipulation Language)
SELECT : pour interroger
INSERT : pour insérer des tuples dans une
table
UPDATE : pour modifier des données dans une
table
DELETE : pour supprimer des tuples dans une
table
L'instance de la base est (définitivement) modifiée
…pourvu que l'on ait fait un “commit”.
Les contraintes d'intégrité
peuvent empêcher INSERT, UPDATE, DELETE.
SQL Mises à jour
UPDATE
UPDATE Prog SET Heure = '21h00'
WHERE Nom_Cine LIKE 'ugc%' AND Titre= 'Dersou Ouzala';
# Autres expressions possibles:
UPDATE Prog SET Heure = Heure+1;
# les séances seront retardées
UPDATE Produits SET PrixTTC = PrixHT * TVA;
Prog avant
NOM_CINE TITRE SALLE HEURE
ugc bercy Dersou Ouzala 1 20h00
ugc bercy Dersou Ouzala 2 22h00
ugc bercy Kagemusha 1 14h00
le champo Dersou Ouzala 1 18h00
le champo Kagemusha 1 20h00
Prog après mise à jour
NOM_CINE TITRE SALLE HEURE
ugc bercy Dersou Ouzala 1 21h00
ugc bercy Dersou Ouzala 2 21h00
ugc bercy Kagemusha 1 14h00
le champo Dersou Ouzala 1 18h00
le champo Kagemusha 1 20h00
Insertions
INSERT
INSERT INTO Prog (Nom_Cine, Titre, Salle, Horaire)
VALUES ('ugc', 'Dersou Ouzala', 1, '20h00'); % ne pas oublier
les ' ' pour les chaînes de caractères
Préciser les noms de colonnes n'est pas nécessaire ici, mais permet
en général
d'insérer la valeur par défaut (NULL sauf mention explicite d'un
autre DEFAULT) pour les colonnes non spécifiées.
de donner les valeurs dans le désordre.
Selon le SGBD, on trouve des commandes mixtes Update-insert.
Suppressions
DELETE
DELETE FROM Prog WHERE Heure >= '20h00';
DELETE FROM Prog WHERE Titre in (SELECT Titre FROM Film
WHERE LOWER(Acteur) Like 'Jean-%');
# Comportements possible en cas de Foreign Key: échec ou cascade.
Pour vider complètement une table, TRUNCATE est plus
rapide.
TRUNCATE Prog;
Ne parcourt pas la table. À utiliser avec prudence !
(pas d'entrée dans le journal ⇒
perturbe MVCC, ne déclenche pas les triggers).
Langage de requête
syntaxe d'une requête SQL
(simplifiée)
SELECT
<liste d'attributs>
attributs du schéma cible ↔︎
π
FROM
<liste de relations>
relations du schéma
source
WHERE
<condition>
conditions de sélection ↔︎
σ
Clause WHERE optionnelle. Garde les tuples évaluant
condition à “Vrai”.
Clause FROM aussi optionnelle pour PostgreSQL (pas
Oracle: FROM DUAL)
SELECT Nom_Cine FROM Prog WHERE Titre='Marion'
SELECT 2+3
Les doublons ne sont pas
éliminés
SQL: requêtes simples
Select Project Join (SPJ)
SELECT * FROM FILM WHERE Acteur='Lonsdale'
↔ σActeur = ′Lonsdale (FILM)
SELECT Titre FROM FILM WHERE Acteur='Lonsdale' OR Acteur='Astaire'
NOM_CINE TITRE SALLE HORAIRE
--------- --------------------- ----- -------
ugc bercy Le discours d'un roi 1 20h00
ugc bercy Le discours d'un roi 2 22h00
ugc bercy Inception 1 14h00
le champo Le discours d'un roi 1 18h00
le champo Inception 1 20h00
SELECT Nom_cine, Titre
FROM Prog
WHERE Nom_cine = 'ugc bercy' AND HORAIRE < 23h00 AND HORAIRE > 10h00
NOM_CINE TITRE
--------- --------------------
ugc bercy Le discours d'un roi
ugc bercy Le discours d'un roi
ugc bercy Inception
SQL: requête simple
Select Project Join (SPJ)
SELECT Nom_Cine, Film.Titre, Horaire FROM Film,
Prog WHERE Film.Titre = Prog.Titre AND Acteur = 'M.Freeman'
Select
Project Join (SPJ): ambiguïté sur la table d'un attribut
SELECT Nom_Cine, Film.Titre, Horaire
FROM Film, Prog
WHERE Film.Titre = Prog.Titre AND Acteur = 'M.Freeman'
Table ajoutée automatiquement par le système pour chaque
attribut
Inférence impossible si l'attribut apparait dans plusieurs
tables: en ce cas l'utilisateur doit impérativement spécifier la
table. ↪ sinon
erreur
Illustration de requête SQL: cas multi-relation
Prog
NOM_CINE TITRE SALLE HORAIRE
--------- --------------------- ----- -------
ugc bercy Le discours d'un roi 1 20h00
ugc bercy Le discours d'un roi 2 22h00
ugc bercy Inception 1 14h00
le champo Le discours d'un roi 1 18h00
le champo Inception 1 20h00
Toutes les personnes ayant participées au tournage du film
“Marion”:
SELECT Acteur AS Personne FROM Film WHERE Titre = 'Marion'
UNION
SELECT MeS AS Personne FROM Film WHERE Titre = 'Marion'
Renommage de table
Table Table_alias
Intérêt:
distinger plusieurs copies d'une même table
donner un nom à une table résultant d'un calcul intermédiaire
(sous requête) …
Les films avec leur MeS et leurs acteurs dans lesquels joue M-F
Pisier ?
$\pi_{\rm Titre}(\sigma_{\rm Actrice=M-F.
Pisier}(\mathbf{film}))\Join\mathbf{film}$
SELECT F2.Titre , F2.MeS, F2.Acteur
FROM FILM F1, FILM F2
WHERE F1.Titre = F2.Titre AND F1.Acteur = 'M-F. Pisier'
Interprétations de F1 et F2:
F1 et F2 sont des copies virtuelles de film
F1 et F2 sont des variables utilisées pour désigner n'importe
quel couple de n-uplets de film
Manipulation des données
Élimination des doublons
SELECT DISTINCT
Liste des films projetés dans chaque cinéma:
SELECT Nom_Cine, Titre
FROM Prog
NOM_CINE TITRE
--------- --------------------
ugc bercy Le discours d'un roi
ugc bercy Le discours d'un roi
ugc bercy Le discours d'un roi
ugc bercy Inception
le champo Le discours d'un roi
le champo Inception
SELECT DISTINCT Nom_Cine, Titre
FROM Prog
NOM_CINE TITRE
--------- --------------------
ugc bercy Le discours d'un roi
ugc bercy Inception
le champo Le discours d'un roi
le champo Inception
Opérations sur les attributs
Dans la clause SELECT ou dans les conditions une expression peut être:
une constante
un attribut
expr1 * expr2 (ou
+,-,/)
une opération sur les chaînes de caractères
ch1 || ch2 : concaténation
LOWER(ch) : met en minuscules
UPPER(ch) : met en majuscules
SUBSTR(ch,i,j) : extrait la sous chaîne
de longueur j débutant à
l'indice i
CASE WHENconditionTHEN exprELSEexprEND
…
SELECT 3*montant FROM Ventes;
SELECT SUBSTR('ABCDEFG',3,4) FROM DUAL; # (oracle): 'CDEF'
SELECT substring('Thomas' from 2 for 3); # (postgresql): 'hom'
Contenu de la clause WHERE
attrIS NULL
expropexpr ∈ (=,<,<=,>=,<>)
exprBETWEENval1ANDval2
exprIN(val1,val2,…)
exprLIKEstring-pattern
% : n'importe quelle chaîne de caractère
_ : n'importe quel caractère
Films
TITRE ACTEUR
------------------------- ------
Rien à Declarer Boon
La plage Canet
Bienvenus chez les ch'tis Boon
SELECT Titre
FROM Films
WHERE LOWER(Titre) LIKE '%bien%'
OR Titre LIKE '%declarer%'
# LOWER: convertir en minuscule
TITRE
-------------------------
Bienvenus chez les ch'tis
Piège 1: produit cartésien
Sémantique de la requête ci-dessous $\stackrel{?}{=}R.A\cap (S.A\cup
T.A)$?
SELECT R.A FROM R,S,T WHERE R.A=S.A OR R.A=T.A
Piège 2: NULLs
Sémantique de la requête ci-dessous?
SELECT P.name FROM Personnes P WHERE P.age > 10 OR P.age <= 10
Trier le résultat de la requête
Relation = multi-ensemble ⟹ ordre
d'affichage dans SQL arbitraire si il n'est pas spécifié.
Liste des films projetés dans chaque cinéma triés par titre:
SELECT Nom_Cine, Titre
FROM Prog
ORDER BY Titre
NOM_CINE TITRE
--------- --------------------
ugc bercy Inception
le champo Inception
ugc bercy Le discours d'un roi
ugc bercy Le discours d'un roi
ugc bercy Le discours d'un roi
le champo Le discours d'un roi
SELECT Nom_Cine, Titre
FROM Prog
ORDER BY Titre DESC,
Nom_Cine ASC
NOM_CINE TITRE
--------- --------------------
le champo Le discours d'un roi
ugc bercy Le discours d'un roi
ugc bercy Le discours d'un roi
ugc bercy Le discours d'un roi
le champo Inception
ugc bercy Inception
tri croissant ( ASCending) par défaut.
ordre naturel de l'attribut dépend de son type (entier, chaîne de
caractères...)
tri sur plusieurs colonnes: lexicographique
Opérations ensemblistes
Opérations ensemblistes
Union, Intersection,
Différence
opérations ensemblistes: éliminent par défaut les
doublons
les relations doivent avoir même schéma
ajouter ALL pour garder les doublons
Les personnes ayant travaillé sur le film 'Marion':
SELECT Acteur AS Personne FROM Film WHERE Titre = 'Marion'
UNION SELECT MeS AS Personne FROM Film WHERE Titre = 'Marion'
Les personnes ayant travaillé sur le film 'Marion', comptées 1 fois
par rôle:
SELECT Acteur AS Personne FROM Film WHERE Titre = 'Marion'
UNION ALL SELECT MeS AS Personne FROM Film WHERE Titre = 'Marion'
Opérations ensemblistes (2)
Union, Intersection,
Différence
Les titres des films à l'affiche dans lesquels a joué M-F Pisier:
SELECT Titre FROM Film WHERE Acteur = 'M-F.
Pisier' INTERSECT SELECT Titre FROM Prog ORDER BY Titre
Les titres des films qui ne sont pas à l'affiche:
SELECT Titre FROM Film EXCEPT SELECT Titre FROM Prog
Remarque: MySQL supporte seulement UNION. Certains SGBD
utilisent MINUS au lieu de EXCEPT.
Sous-requêtes
Sous-requête
Principe: utiliser le résultat d'une requête comme relation ou comme
valeur dans une autre requête. Une sous-requête peut apparaître dans les
clauses
WHERE et HAVING
FROM (en renommant la relation résultante)
SELECT (à condition de ne retourner qu'une ligne pour chaque
ligne de la requête principale)
Supposons que FILM-DEB(Titre,Acteur) stocke le titre du
premier film de chaque acteur.
Les acteurs du premier film joué par M-F. Pisier:
SELECT Acteur FROM FILM WHERE Titre =
(SELECT Titre FROM FILM-DEB WHERE Acteur = 'M-F. Pisier')
La sous-requête doit
retourner exactement un résultat sinon erreur à l'exécution de
la requête.
Sous-requête
Sous-requête dans le
FROM
Les acteurs ayant joué avec M-F.Pisier dans le même film:
SELECT Acteur FROM FILM,
(SELECT Titre FROM Film Where Acteur = 'M-F. Pisier') F2
WHERE Film.Titre = F2.titre
Sous-requête avec opérateur
Sous-requête
à plusieurs lignes dans la clause WHERE/HAVING
Opérateurs exprimant des conditions avec des sous requêtes pouvant
retourner plusieurs lignes:
attr INsous-requête
vrai si la valeur apparaît dans le résultat de la
sous-requête
EXISTSsous-requête
vrai si le résultat de la sous-requête contient au moins un
tuple
attr op ANYsous-requête
vrai si il existe une valeur dans le résultat de la sous-requête qui
satisfait la comparaison
attr op ALLsous-requête
vrai si toutes les valeurs dans le résultat de la sous-requête
satisfont la comparaison
avec op ∈ {=,<,>, < =, > = ≠ } aussi : NOT IN, NOT EXISTS Ne pas en abuser: optimiseur
souvent inefficace
Sous-requêtes
Opérateur IN
Les titres des films dont un des MeS est acteur (pas forcément dans
le même film):
SELECT DISTINCT Titre FROM FILM
WHERE MeS IN (SELECT Acteur FROM FILM)
Formulation équivalente sans sous-requête?
Sous-requêtes
Opérateur EXISTS
Les films dirigés par au moins deux metteurs en scène:
SELECT DISTINCT F1.Titre FROM FILM F1
WHERE EXISTS (SELECT F2.MeS FROM FILM F2
WHERE F1.Titre=F2.Titre AND NOT F1.MeS=F2.MeS)
Remarque: on a ici une requête corrélée.
Formulation équivalente sans sous-requête?
Sous-requêtes
Comparaison avec ALL
Les films projetés à l'UGC plus tard que tous les films projetés au
Trianon.
SELECT DISTINCT Titre FROM PROG
WHERE Nom_Cine='UGC' AND
Horaire > ALL (SELECT Horaire FROM PROG WHERE Nom_Cine='Trianon')
Formulation équivalente sans sous-requête ?
Sous-requêtes
Comparaison avec ANY
Le téléphone des cinémas proposant une programmation après 23h:
SELECT Telephone FROM CINE AS C1
WHERE 23 < ANY ( SELECT Horaire FROM PROG
WHERE C1.Nom_Cine=PROG.Nom_Cine)
Sous-requêtes
Précisions sur la
sémantique de IN/NOT IN/=ANY
attr IN{x,y,z}↔︎attr= x OR
attr= y OR
attr= z
attr NOT IN{x,y,z}↔︎attr != x AND
attr != y AND
attr != z
résultat en présence de NULLs
peut surprendre…
Est-ce que l'opérateur IN est équivalent à
=ANY? Pouvez vous exprimer NOT IN en fonction
de ALL?
Jointures
Jointures en SQL
Différents types de jointure
Rappel :
Produit cartésien :
SELECT R.a,S.b
FROM R,S
Jointure :
SELECT R.a,S.b
FROM R,S
WHERE R.c=S.c
On peut utiliser d'autres types de jointures !
equi-jointure : condition de jointure est une égalité
↪ c'est le cas le plus
courant : ± tous les examples de ce
cours.
non equi-jointure : condition de jointure n'est pas une égalité : >,…,
LIKE
Très souvent lorsque l'on parle de jointures on parle des
équijointures.
Même pour des équijointures, il existe plusieurs formulations en
SQL.
Jointures en SQL
Différents types de
jointure en SQL
Instructions SQL pour spécifier le type de jointure :
jointures internes : (INNER) JOIN
jointures externes : LEFT/RIGHT/FULL(OUTER)
JOIN
produit cartésien : CROSS JOIN
Instructions SQL pour spécifier les conditions de jointure :
... JOIN ... ON: le plus général,
condition quelconque (pas forcément equi-jointure), colonnes non
fusionnées.
... JOIN ... USING : jointure naturelle
restreinte aux attributs listées, colonnes fusionnées.
NATURAL JOIN ... : jointure naturelle sur toutes les
colonnes de même nom.
Syntaxe jugée plus lisible qu'un produit cartésien suivi d'une
sélection dans la clause WHERE, et (à peu près) indispensable pour les
jointures externes.
Jointures en SQL
Jointure interne
SELECT F1.Titre, F2.Acteur FROM FILM F1
INNER JOIN FILM F2 ON F1.Titre = F2.Titre
WHERE F1.Acteur = 'M-F. Pisier'
Le mot-clé INNER est facultatif : lorsque l'on écrit une
jointure sans en préciser le type(JOIN) c'est bien
INNER JOIN qui est calculé.
Jointures en SQL : plusieurs tables
Jointure interne
SELECT Film.Titre, Pers.nom, Pers.taille
FROM Film JOIN Programme Prog ON Film.Titre = Programme.Titre
JOIN Personne Pers ON Film.acteur = Pers.nom
Pourquoi la requête ci-dessous ne calcule-t-elle pas les
triplets d'acteurs distincts qui ont collaboré sur un film?
SELECT F1.Titre, F1.Acteur, F2.Acteur, F3.Acteur
FROM FILM F1 JOIN FILM F2 ON F1.Titre = F2.Titre
JOIN FILM F3 ON F1.Titre = F3.Titre
WHERE F1.Acteur != F2.Acteur AND F1.Acteur != F3.Acteur
Jointures en SQL
Jointure naturelle
SELECT Nom_Cine,Film.Titre, Horaire FROM Film NATURAL JOIN Prog
WHERE Acteur = 'M.Freeman'
Jointure naturelle sur tous les attributs communs.
On peut restreindre la jointure naturelle à un sous ensemble
(attr_a,attr_b,…,attr_c)
des attributs communs avec la syntaxe:
# préciser les attributs d'une jointure naturelle est recommandé
# (par ex: le schéma risque de changer par la suite)
SELECT attr_a, attr_b, nom_table1.attr1... FROM nom_table1
INNER JOIN nom_table2 USING(attr_a,attr_b,...,attr_c)
Jointures en SQL
Jointure externe
SELECT attr1, attr2,... FROM nom_table1
LEFT OUTER JOIN nom_table2 USING(attr_a,attr_b,...,attr_c)
Permet d'afficher additionnellement les lignes de la table gauche (à
gauche du mot clé JOIN) qui n'ont pas de ligne correspondante à droite
pour la jointure, en complétant par des NULL à droite.
RIGHT OUTER JOIN: affiche les lignes de la table
droite sans correspondance
FULL OUTER JOIN: affiche les lignes des tables
gauche ou droite sans correspondance
Jointures en SQL
Jointure externe
Roles
TITRE ID_ACT PERSONNAGE
------------------------- ------- ---------------
It's a Wonderful Life 35 George Bailey
It's a Wonderful Life Mary Bailey
It's a Wonderful Life 36 Clarence Odbody
Rear Window 35 LB Jeffries
The Shawshank Redemption 40 red
Acteur
ID NOM PRENOM
-- -------- ------
35 Stewart James
40 Freeman Morgan
50 Serrault Michel
SELECT titre, personnage, nom FROM roles LEFT OUTER JOIN acteurs ON id_act=id;
TITRE PERSONNAGE NOM
------------------------- --------------- -------
Rear Window LB Jeffries Stewart
It's a Wonderful Life George Bailey Stewart
The Shawshank Redemption red Freeman
It's a Wonderful Life Mary Bailey
It's a Wonderful Life Clarence Odbody
Jointures en SQL
Jointure externe
Roles
TITRE ID_ACT PERSONNAGE
------------------------- ------- ---------------
It's a Wonderful Life 35 George Bailey
It's a Wonderful Life Mary Bailey
It's a Wonderful Life 36 Clarence Odbody
Rear Window 35 LB Jeffries
The Shawshank Redemption 40 red
Acteur
ID NOM PRENOM
-- -------- ------
35 Stewart James
40 Freeman Morgan
50 Serrault Michel
SELECT titre, personnage, nom FROM roles FULL OUTER JOIN acteurs ON id_act=id;
TITRE PERSONNAGE NOM
------------------------- --------------- -------
It's a Wonderful Life George Bailey Stewart <- in both
Rear Window LB Jeffries Stewart <- in both
The Shawshank Redemption red Freeman <- in both
It's a Wonderful Life Mary Bailey <- in LEFT OUTTER JOIN
It's a Wonderful Life Clarence Odbody <- in LEFT OUTTER JOIN
Serrault <- in RIGHT OUTTER JOIN
Agrégats
Fonctions d'agrégation
( Aggregates)
But: résumer les données en regroupant les tuples.
Exemple: calculer le nombre de film pour chaque réalisateur.
SELECT
<liste d'attributs>
attributs du schéma cible
FROM
<liste de relations>
relations du schéma source
WHERE
<condition>
conditions de sélection
GROUP BY
<liste d'attributs>
attributs de regroupement
ORDER BY
<liste d'attributs>
ordre d'affichage
Fonctions les plus courantes:
COUNT(): cardinalité du multiensemble
SUM(): somme
MAX/MIN(): valeur max/min
AVG(): moyenne
Fonctions d'agrégation: principe du regroupement
Film
TITRE ACTEUR
------------------------- ---------
Rien à Declarer Boon <--
Brice de Nice Cornillac
La vie de Chantier Boon <--
Ensemble c'est tout Canet
Mon Idole Canet
The dark knight rises Cotillard
Les petits mouchoirs Cotillard
La plage Canet
Inception Cotillard
Bienvenus chez les ch'tis Boon <--
Les tuples ayant même valeur de groupement sont regroupés sur une
ligne
la fonction est calculée pour chaque groupe
indépendamment
si fonction d'agrégation sans GROUP BY: 1
groupe=table entière
les attributs hors du GROUP BY ne peuvent apparaître
dans SELECT qu'à l'intérieur d'une fonction
d'agrégation
Sinon: erreur
"not a group by expression".
Fonctions d'agrégation (2)
Film
TITRE ACTEUR QT
------------------- -------- --
Rien à Declarer Boon 2
Brice de Nice Cornillac 5
La vie de Chantier Boon 7
Ensemble c'est tout Canet 2
Mon Idole Canet 3
Exemple de requête avec agrégat sans GROUP BY...
Attention: la clause WHERE filtre les données avant la création
des groupes.
SELECT COUNT(*) c, SUM(QT) s FROM film
c | s
--+--
5 | 19
SELECT SUBSTR(MAX(Titre),0,4) mx,
SUM(QT)/COUNT(*) s
FROM t WHERE Titre>'L'
mx | s
----+---
Rie | 4
Fonctions d'agrégation : ordre
Ordre d'évaluation intuitif des clauses :
FROM
WHERE
GROUP BY
HAVING
SELECT
ORDER BY
Donner le résultat de la requête:
SELECT acteur, nomrealisateur, COUNT(*) NB
FROM film
WHERE acteur < 'D'
GROUP BY acteur, nomrealisateur
ORDER BY NB
Film
TITRE ACTEUR NOMREALISATEUR
------------------------- -------- ---------------
Les petits mouchoirs Cotillard Canet
La plage Canet Boyle
Mon Idole Canet Canet
The dark knight rises Cotillard Nolan
La vie de Chantier Boon Boon
Brice de Nice Dujardin Dujardin
Ensemble c'est tout Canet Canet
Gran Torino Eastwood Eastwood
Inception Cotillard Nolan
Brice de Nice Cornillac Dujardin
Rien à Declarer Boon Boon
Bienvenus chez les ch'tis Boon Boon
COUNT
Que compter?
COUNT(*) retourne le nombre de lignes.
COUNT(a) retourne le nombre de lignes non nulles sur
colonne a.
COUNT(DISTINCT a) retourne le nombre de valeurs
distinctes sur la colonne a.
Film
titre | acteur | nomrealisateur
----------------------+-----------+---------------
Green Book | Mortensen | Farrelly
Seigneur des Anneaux | Mortensen | Jackson
Coda | Jones | Heder
Nomadland | |Zhao
SELECT COUNT(*) A,
COUNT(acteur) B,
COUNT(DISTINCT acteur) C
FROM film
WHERE Titre != 'Coda'
a | b | c
--+---+---
3 | 2 | 1
Compter en SQL les acteurs que chaque réalisateur a encadré
:
Il est possible de calculer SUM(DISTINCT a),
AVG(DISTINCT a).
Calculer dans une même requête le nombre maximal et moyen de
films par acteur. Résultat attendu:
NB_MAX NB_MOY
------ ------
3 2.5
Conditions sur les groupes
HAVING
SELECT
<liste d'expressions1>
attributs du schéma cible
FROM
<liste de relations>
relations du schéma source
WHERE
<conditions1>
conditions de sélection
GROUP BY
<liste d'attributs>
attributs de regroupement
HAVING
<conditions2>
conditions sur les groupes
ORDER BY
<liste d'expressions2>
ordre d'affichage
avec <liste d'expressions1> incluse dans
<liste d'attributs> sauf pour les colonnes
calculant une fonction d'agrégation.
HAVING permet de ne garder que les groupes satisfaisant
une condition:
SELECT acteur, COUNT(*) NB
FROM film
GROUP BY acteur
HAVING COUNT(*) > 2
ACTEUR NB
-------- --
Canet 3
Cotillard 3
Boon 3
Agrégats SQL: sémantique (1)
SELECT ... <-- évalué une fois par groupe (pas par ligne)
FROM ...
GROUP BY A_1
HAVING ... <-- évalué une fois par groupe (pas par ligne)
A_1 | A_2 | ...
---- + ---- + ---
... | ... | ... Le regroupement
---- + ---- + --- partitionne les bindings
the x_i group --> x_i | y_i1 | ... de lignes :
the x_i group --> x_i | y_i2 | ... - il n'y a pas de
---- + ---- + --- groupe vide
the x_j group --> x_j | y_j1 | ... - chaque ligne
the x_j group --> x_j | y_j2 | ... appartient à
---- + ---- + --- exactement un groupe
... | ... | ...
Agrégats SQL: sémantique (2)
Agrégat: opérateur commutatif et associatif (à qques détails près).
Pour calculer agg (comme fold en programmation
fonctionnelle): on initialise un accumulateur à la valeur
zagg.
Aggregate agg
∅agg
zagg
⊕agg(a, x)
COUNT
0
0
a + 1
SUM
NULL
0
a + x
AVG
NULL
<0, 0>
<a.1 + x, a.2 + 1>
MAX
NULL
−∞
max2(a, x)
MIN
NULL
+∞
min2(a, x)
bool_and
NULL
true
a ∧ x
bool_or
NULL
false
a ∨ x
...
...
...
...
source: cours de Torsten Grust
Agrégats SQL: exemples
SELECT a, b, count(*), max(c)
FROM t GROUP BY a, b
# nothing special there
SELECT a, count(*)
FROM t
GROUP BY a, b
# sometimes it makes sense not to display b
SELECT a, sum(a), max(b+d)
FROM t
GROUP BY a
/* we can group *and* aggregate on a,
though it seldom makes sense */
SELECT a, b, sum(a)
FROM t
GROUP BY a
/* Incorrect query:
b is not a group by expression */
Lorsqu'il existe une dépendance fonctionnelle a → b, certains SGBD (ex : PostgreSQL) peuvent la tolérer,
mais ce n'est pas sûr (partie optionnelle de la norme SQL) ; vous devez donc inclure b dans le
regroupement, si c'est votre intention.
NULLs in SQL aggregates
Aggregates (SUM, AVG, MAX) ignore null values.
Propose a table where c1 and c2 will differ:
SELECT SUM(a) + SUM(b) c1, SUM(a+b) c2 FROM t;
Quelques outils techniques
Guillemets: simple ou double
SELECT a FROM t; # la colonne nommée a
SELECT 'a'; # constant string 'a'
CREATE TABLE "ma table" ("select" int); # identificateur entre guillemets
SELECT "select" from "ma table"; # faisable mais à éviter.
Intérêt d'un identificateur entre guillemets ( “quoted identifier”):
sensible à la casse
permet d'utiliser des espaces
permet d'échapper des mots clés réservés par le SGBD
Mais je ne recommande pas de les utiliser, et recommande d'éviter les
mélanges. Remarque: les identifiants qui ne sont pas entre guillements
sont par défaut convertis en minuscules sous postgresql, en majuscule
sous oracle.
Dans une requête SQL, le symbole d'échappement est :
SELECT Titre FROM Film WHERE Acteur = 'O”Brien'; # cherche O'Brien
Mais les applications utilisent plus souvent une requête
préparée avec paramètres.
Un cluster de BD postgresql contient une ou plusieurs BD. Chaque BD
comporte un ou plusieurs schémas.
CREATE SCHEMA mon_schema;
CREATE TABLE mon_schema.t(id int) # voir: base.schema.table
SELECT a FROM mon_schema.t;
CREATE SCHEMA mon_schema2;
CREATE TABLE mon_schema2.t(id int) # valide car pas dans le même schéma
# DROP SCHEMA mon_schema CASCADE; # pour effacer un schéma non-vide
Par défaut, schéma public
En général on évite les noms qualifiés. Le schéma utilisé sera le
premier dans le chemin de parcours:
SET search_path TO mon_schema, mon_schema2, public;
SHOW search_path; # SELECT * FROM t utilisera la table dans mon_schema