Niveau physique : le langage SQL
Présentation du langage SQL¶
Qu'est-ce que c'est ?¶
-
Ce niveau concerne l'implantation et l'utilisation de la base de données.
-
C'est le langage SQL qui va permettre cela.
Définition : langage SQL
- Langage informatique standardisé, implémenté sur la plupart des SGBD relationnels principaux (Oracle, Access, MySQL, etc.) ;
- Il se décompose en 3 sous-langages, pour :
- la définition des données (LDD) ;
- leur manipulation (LMD)
- leur contrôle d'accès (LCD).
- SQL a été conçue en vue d’une intégration multi-langage (C, C++, Java, PHP, Python, etc.).
- C'est un langage déclaratif et non procédural.
- Le langage SQL décrit est 100% compatible avec MySQL.
Bref historique¶
- Provient du langage System R d’IBM (1976).
- Apparaît pour la première fois dans une application commerciale avec Oracle (fin 1970).
- 1ère normalisation ANSI : SQL-86.
- Normalisations ultérieures : SQL-89, SQL-92, SQL-99, SQL-1999, SQL-2003, SQL-2008.
- Norme actuelle : SQL-2011.
Le LDD : Langage de Définition de Données¶
Les types de données¶
Définition : type (de données) d'un champ
Dans une déclaration de table - en SQL - il est nécessaire d'affecter un type à chaque champ (ou colonne). Ce type détermine le domaine du champ, c'est-à-dire l'ensemble des valeurs qu'il peut prendre dans les différents enregistrements.
Les nombres entiers¶
BIGINT[(x)]
: 8 octets (x
désigne le nombre maximal de chiffres dans l'affichage)INTEGER[(x)]
ouINT[(x)]
: 4 octets
x = nombre minimal de chiffres affichés, siZEROFILL
MEDIUMINT[(x)]
: 3 octetsSMALLINT[(x)]
: 2 octetsTINYINT[(x)]
: 1 octetBIT
,BOOL
,BOOLEAN
=TINYINT(1)
Leur déclaration peut être suivie de :
- [UNSIGNED]
- [ZEROFILL]
: complétion du nombre par des 0 dans l'affichage ; implique UNSIGNED
.
Les nombres réels¶
- Ils supportent :
[UNSIGNED]
et[ZEROFILL]
.
Types approchés¶
FLOAT[(n,d)]
: 4 octets (entre parenthèses, le nombre de chiffres à afficher : après et avant la virgule)DOUBLE [(n,d)]
=REAL[(n,d)]
: 8 octets
Types exacts¶
-
DECIMAL[(n,d)]
=NUMERIC[(n,d)]
-
nombre stocké comme une chaîne de caractères
- 1 caractère par chiffre
Les chaînes de caractères¶
Champs texte courts¶
CHAR(n) [BINARY]
: chaîne de longueur fixe, occupant n caractères-
VARCHAR(n) [BINARY]
: chaîne de longueur variable, occupant au plus n caractères -
BINARY
: les comparaisons tiennent compte de la casse
Champs texte longs¶
-
Chaînes de caractères insensibles à la casse
TINYTEXT
: 2^8 (– 1) caractèresTEXT
: 2^16 caractèresMEDIUMTEXT
: 2^24 caractèresLONGTEXT
: 2^32 caractères
-
Chaînes sensibles à la casse
TINYBLOB
BLOB
MEDIUMBLOB
LONGBLOB
Les dates et temps¶
DATE
: AAAA-MM-JJ : jour entre 1/1/1000 et 12/31/9999YEAR
: AAAA-
TIME
: HH:MM:SS (format 24h) -
TIMESTAMP
: jour entre 1/1/1970 et 19/1/2038- si valeur non précisée, par défaut c’est la date courante
-
DATETIME
: AAAA-MM-JJ HH:MM:SS (date et heure) DATETIME
etTIMESTAMP
sont stockés suivant l'échelle de temps UTC.
Les valeurs manquantes : NULL
¶
Définition : « valeur » NULL
Un champ d'enregistrement peut (sauf si affecté par la propriété NOT NULL
) prendre la « valeur particulière » NULL
: elle désigne une valeur manquante. Cela n'est donc pas vraiment une valeur, simplement un code en spécifiant l'absence.
Création de la base et des tables¶
Création d’une base¶
CREATE DATABASE <nom_base>;
Définition de la « base de travail »¶
Pour créer des tables au sein d'une base, on peut éviter de mentionner leur appartenance à cette base, en la définissant comme « base de travail » :
USE <nom_base>;
Création d'une table¶
- Dans MySQL, chaque table est stockée dans un fichier
- Syntaxe simplifiée :
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] <nom_table>
(
<nom_colonne1> <type> [<propriété>]*,
<nom_colonne2> <type> [<propriété>]*,
…
<nom_colonne1> <type> [<propriété>]*,
[<contraintes_de_table>]
);
TEMPORARY
: permet la création d'une table dont la durée d'existence est limitée à la session courante.
Propriétés des colonnes de la table¶
-
Initialisation
AUTO_INCREMENT
: uniquement pour les types numériquesDEFAULT <valeur par défaut>
: sauf pour les textes longs
-
Contraintes d'intégrité : certaines de ces propriétés instaurent des vérifications automatiques qui garantissent la cohérence de la base
NOT NULL
(etNULL
par défaut) : autorise ou non lesNULL
UNIQUE
(si aussiNOT NULL
alors colonne = clé candidate)PRIMARY KEY
(définit clé primaire) (=NOT NULL
+UNIQUE
)CHECK(<condition>)
Propriétés de table = contraintes d’intégrité sur une table¶
PRIMARY KEY(<liste_de_champs>)
UNIQUE(<liste_de_champs>)
- (
INDEX
=KEY
) -
+ gestion des clés étrangères
-
ENGINE
: format de stockage de la base.- Valeur
INNODB
par défaut : permet les transactions sécurisées et la gestion des clés étrangères
- Valeur
Gestion des clés étrangères¶
- Syntaxe simplifiée :
FOREIGN KEY [nom_contrainte] (<liste_colonnes>)
REFERENCES <table> (<liste_colonnes>)
[ON DELETE CASCADE|SET NULL|NO ACTION|RESTRICT]
[ON UPDATE CASCADE|SET NULL|NO ACTION|RESTRICT]
-
La clé étrangère établit un lien entre une table parente (celle « référencée ») et une table fille (celle qui référence des enregistrements de la table parente)
- La déclaration se fait dans la table parente.
- Les champs mis en relations doivent être de même type (avec des propriétés compatibles).
- Pour des raisons d'efficacité, il faut obligatoirement des index sur les clés étrangères et leurs références (pas nécessairement des clés primaires). Mais les déclarations de clés suffisent à les créer.
-
RESTRICT
=NO ACTION
(pour MySQL) : rejet de l'effacement ou de la modification.
Exemple de définition d'une table, avec une contrainte de clé étrangère
DROP TABLE IF EXISTS Magasin;
CREATE TABLE Magasin
(
n_mag TINYINT(3) UNSIGNED NOT NULL AUTO_INCREMENT,
nom VARCHAR(100) NOT NULL,
adresse VARCHAR(100) NOT NULL,
tel VARCHAR(10),
code_postal MEDIUMINT(5) ZEROFILL NOT NULL,
PRIMARY KEY(n_mag),
INDEX Poste_Code_postal (code_postal), -- facultatif et peut être intégré à la commande suivante
FOREIGN KEY (code_postal) REFERENCES Poste(code_postal) ON UPDATE CASCADE ON DELETE CASCADE
) TYPE = InnoDB;
Modification (du schéma des) tables¶
- Suppression
DROP TABLE [IF EXISTS] <nom_table1>, …, <nom_tableN>
- Modification
ALTER TABLE <nom_table> <alteration>
-
Altérations possibles
- Type de colonne
MODIFY <nom_colonne> <nouvelle_definition_colonne>
- Nom et type de colonne
CHANGE <ancien_nom_colonne> <nouveau_nom_colonne> <nouvelle_definition_colonne>
- Ajout d’une colonne
ADD <nom_col> <def_col> [FIRST|AFTER <nom_col>]
- Suppression d’une colonne
DROP <nom_col>
- Renommage de la table
RENAME AS <nouveau_nom_table>
- Suppression ou ajout d’une valeur par défaut
ALTER <nom_col> {SET DEFAULT <valeur> |DROP DEFAULT}
- Suppression ou ajout de contraintes d’intégrité
DROP PRIMARY KEY ADD CONSTRAINT {PRIMARY KEY|UNIQUE} <liste_colonnes>
- Type de colonne
-
Le LMD : Langage de Manipulation de Données¶
Les premières requêtes¶
Définition : requête SQL
Une requête sert à extraire des données de la base, à partir d'une ou plusieurs tables. On les exprime à l'aide de l'instruction SELECT
.
L'instruction SELECT
¶
L'instruction SELECT
permet de construire une pseudo-table résultat (table sans nom, non persistante), à partir d'une ou plusieurs tables.
Voici sa syntaxe simplifiée :
SELECT [DISTINCT] <champ1>, <champ2>, …
FROM <table1>, <table2>, …
WHERE <conditions>
Une première requête : la liste complète des étudiants
SELECT Prenom, Nom, NumeroINE
FROM Etudiant
Pour comprendre le processus de construction de la requête, il est préférable de considérer (et rédiger) ses différentes clauses dans l'ordre, à l'exception du SELECT
dont l'action n'intervient qu'à la toute fin :
-
La clause
FROM
cible la table de travail, à partir de laquelle la pseudo-table résultat va être construite. Lorsque plusieurs tables sont listées, c'est leur produit cartésien qui servira de (pseudo-)table de travail (voir plus loin). -
La clause
WHERE
sert à filtrer les enregistrements (c.-à-d. les lignes) de la table de travail : seules celles vérifiant les conditions requises sont conservées. -
La clause
SELECT
elle-même permet de sélectionner les champs (c.-à-d. les colonnes) de la table de travail : seuls ceux listés seront conservés.- C'est la seule clause véritablement obligatoire de la requête.
- Comme son nom ne l'indique pas, il s'agit plutôt d'une clause de « projection » : sélectionner les champs revient en effet à réduire la « dimension » des enregistrements de la table résultat.
- Le champ optionnel
DISTINCT
permet d'éliminer les doublons parmi les enregistrements du résultat.
La clause WHERE
: sélection/restriction des enregistrements¶
La restriction des enregistrements de la table de travail s'effectue à l'aide de conditions sur leur contenu, à l'aide de différents opérateurs :
-
Les opérateurs de comparaison :
=
,!=
,<
,>
,<=
,>=
. -
Les prédicats (« opérateurs intégrés » ) :
BETWEEN
,IN
,LIKE
,IS NULL
-
BETWEEN
vérifie qu'un champ appartient à un intervalle donné :Exemple : liste des étudiants associés aux 10 premiers stages
SELECT * FROM Etudiant WHERE NumeroStage BETWEEN 1 AND 10
-
IN
vérifie l'appartenance à un ensemble de valeurs :Exemple : liste des étudiants effectuant les stages 1, 12 ou 18
SELECT * FROM Etudiant WHERE NumeroStage IN (1,12,18)
-
LIKE
vérifie qu'une donnée de type « chaîne de caractères » correspond à un modèle de chaîne. Un modèle s'élabore à partir d'une chaîne de caractères constante, dans laquelle les éventuels symboles spéciaux_
et%
représentent respectivement un caractère quelconque et une suite quelconque de caractères.Exemple : liste des étudiants dont le nom se termine par un « d » et dont la 2ième lettre est un « a »
SELECT * FROM Etudiant WHERE Nom LIKE "_a%d"
-
IS NULL
etIS NOT NULL
vérifient qu'un champ est manquant ou non :Exemple : liste des étudiants sans stage
SELECT Prenom, Nom, NumeroINE FROM Etudiant WHERE NumeroStage IS NULL
-
-
Enfin, les opérateurs logiques permettent de combiner les conditions,
AND
etOR
, ou de les inverser, avecNOT
.
La clause WHERE
et les sous-requêtes¶
Définition : sous-requête
- Dans la condition de sélection/restriction des enregistrements (clause
WHERE
), les données manipulées peuvent être obtenues par une requête complète (SELECT FROM WHERE
). - Cette requête utilisée par la requête principale est appelée sous-requête.
Sous-requêtes basées sur l'opérateur IN
¶
- Sous-requête et opérateur
IN
:
Exemple : noms et prénoms des stagiaires de M. Bellamy
SELECT Prenom, Nom
FROM Etudiant
WHERE NumeroStage IN (
SELECT NumeroStage
FROM Stage
WHERE Encadrant = "Bellamy"
)
- Plusieurs requêtes imbriquées :
Exemple : noms et prénoms des stagiaires des encadrants dont le nom commence par un « D ».
SELECT Prenom, Nom
FROM Etudiant
WHERE NumeroStage IN (
SELECT NumeroStage
FROM Stage
WHERE Encadrant IN (
SELECT Encadrant
FROM Stage
WHERE Encadrant LIKE "D%"
)
)
- Comme dans la plupart des langages informatiques, les requêtes imbriquées ont accès aux champs des requêtes qui les englobent ; mais pas l'inverse.
Exemple : noms et prénoms des étudiants dont l'encadrant porte le même nom
SELECT Prenom, Nom
FROM Etudiant
WHERE NumeroStage IN (
SELECT NumeroStage
FROM Stage
WHERE Encadrant = Etudiant.Nom
)
Sous-requêtes basées sur d'autres opérateurs¶
- Si une sous-requête renvoie une seule valeur, on peut utiliser les autres opérateurs de comparaison :
Exemple : numéros des stages encadrés par l'encadrant du stage 7
SELECT NumeroStage
FROM Stage
WHERE Encadrant = (
SELECT Encadrant
FROM Stage
WHERE NumeroStage = 7
)
- La sous-requête peut renvoyer le résultat d'une fonction d'agrégation (voir plus loin), comme un comptage. Dans cet exemple, notez que la même table est utilisée dans la requête et la sous-requête : on utilise alors des alias pour lever les ambiguïtés sur les tables.
Exemple : liste des encadrants ayant au moins de 2 stages
SELECT DISTINCT Encadrant
FROM Stage AS Stage_requete
WHERE 2 <= (
SELECT COUNT(*) -- comptage des lignes
FROM Stage AS Stage_sous_requete
WHERE Stage_sous_requete.Encadrant = Stage_requete.Encadrant
)
- Les opérateurs ensemblistes
EXISTS
etNOT EXISTS
Exemple : intitulés des stages affectés à plus d'un stagiaire
SELECT DISTINCT Titre
FROM Stage as Table_parent
WHERE EXISTS (
SELECT *
FROM Stage
WHERE NumeroStage != Table_parent.NumeroStage AND Titre = Table_parent.Titre
)
- Application des opérateurs de comparaisons à des listes de valeurs, à l'aide de
ALL
etANY
Exemple : prénom et nom de l'étudiant qui a le plus petit numéro de stage parmi ceux les stages affectés (il existe d'autres méthodes plus adaptées !)
SELECT Prenom, Nom
FROM Etudiant
WHERE NumeroStage <= ALL (
SELECT NumeroStage
FROM Etudiant
WHERE NumeroStage IS NOT NULL
)
Exemple : prénoms et noms des étudiants qui n'ont pas le plus petit numéro de stage parmi les stages affectés
SELECT Prenom, Nom
FROM Etudiant
WHERE NumeroStage > ANY (
SELECT NumeroStage
FROM Etudiant
WHERE NumeroStage IS NOT NULL
)
La clause FROM
et les requêtes multi-tables¶
Le produit cartésien¶
Définition : produit cartésien
- Mathématiquement, le produit cartésien de 2 ensembles est l'ensemble de tous les couples constitués d'un élément du 1er ensemble, et d'un élément du 2nd ensemble.
- Par exemple,
RxR
est l'ensemble des points du plan (R
désignant l'ensemble des réels).
- Par exemple,
- Pour appliquer ce produit en BDD, il suffit de considérer qu'une table est un ensemble d'enregistrements.
-
Le produit cartésien de 2 tables est donc une table dont les enregistrements sont définis en combinant (ou couplant) chaque enregistrement de la 1ère table avec chaque enregistrement de la 2nde.
- Combiner 2 enregistrements consiste à compléter le 1er par le 2nd (par concaténation de leurs champs).
- Le schéma de la table résultat est donc constitué de la réunion des champs des 2 tables.
-
Le produit cartésien de n>2 tables s'obtient en calculant le produit cartésien de la première table, avec le produit cartésien des autres tables.
Exemple de produit cartésien mathématique : liste de tous les devoirs d'élèves
Ensemble 1 : Élèves = {"Marie", "Alfred", "Blaise"}
Ensemble 2 : Devoirs = {"Commentaire de texte", "Dissertation"}
Produit cartésien des ensembles 1 et 2 :
Élèves x Devoirs = {
("Marie", "Commentaire de texte"),
("Marie", "Dissertation"),
("Alfred", "Commentaire de texte"),
("Alfred", "Dissertation"),
("Blaise", "Commentaire de texte"),
("Blaise", "Dissertation")
}
Exemple de produit cartésien BDD : liste de tous les devoirs d'élèves
On réalise le produit cartésien entre les 2 tables suivantes :
Table Élèves
Nom | Prenom |
---|---|
Curie | Marie |
Einstein | Alfred |
Pascal | Blaise |
Table Devoirs
Libellé | Matière |
---|---|
Commentaire de texte | Français |
Dissertation | Français |
Résultat du produit cartésien des 2 tables, noté : Élèves x Devoirs
--- instruction SQL qui calcule ce produit cartésien
SELECT *
FROM Eleves, Devoirs
Élèves.Nom | Élèves.Prénom | Devoirs.Libellé | Devoirs.Matière |
---|---|---|---|
Curie | Marie | Commentaire de texte | Français |
Curie | Marie | Dissertation | Français |
Einstein | Alfred | Commentaire de texte | Français |
Einstein | Alfred | Dissertation | Français |
Pascal | Blaise | Commentaire de texte | Français |
Pascal | Blaise | Dissertation | Français |
La jointure¶
Définition : jointure
- Formellement, une jointure est une restriction de produit cartésien. Cela signifie que contrairement à ce dernier, elle ne conserve pas toutes les combinaisons d'enregistrements, mais uniquement celles qui vérifient une condition de jointure.
- En BDD, on l'utilise fréquemment pour compléter les enregistrements contenant une clé étrangère, par l'enregistrement - de la table liée - dont la clé primaire lui correspond.
- Elle permet alors de recomposer des données dont le contenu a été réparti entre plusieurs tables dans l'étape de conception (la conception visant à minimiser la redondance des données de la base).
Exemple de jointure : liste des étudiants avec les informations de leur stage
SELECT NumeroINE, Prenom, Nom, Stage.Titre, Stage.Encadrant
FROM Etudiant JOIN Stage ON (Etudiant.NumeroStage = Stage.NumeroStage)
En considérant la jointure comme une restriction de produit cartésien, on peut aussi écrire :
SELECT NumeroINE, Prenom, Nom, Stage.Titre, Stage.Encadrant
FROM Etudiant, Stage
WHERE Etudiant.NumeroStage = Stage.NumeroStage
Sans la clause de jointure Etudiant.NumeroStage = Stage.NumeroStage
, chaque étudiant serait combiné à chacun des stages : cela n'aurait aucun sens !
Définitions : jointures internes et externes
-
- elles contiennent exclusivement les combinaisons d'enregistrements associés par la condition de jointure : les enregistrements orphelins des 2 tables initiales (c.-à-d. « non associés ») sont ainsi exclus du résultat.
- c'est la jointure par défaut : le mot clé
INNER
est implicitement associé àJOIN
lorsqu'il est seul.
Les jointures internes (
INNER JOIN
)Exemple de jointure interne : ni les étudiants sans stage, ni les stages sans étudiants, n'apparaissent dans le résultat
SELECT NumeroINE, Prenom, Nom, Stage.Titre, Stage.Encadrant FROM Etudiant JOIN Stage ON Etudiant.NumeroStage = Stage.NumeroStage
-
Les jointures externes (
OUTER JOIN
)- plus complètes que les jointures internes, elles lui ajoutent les enregistrement orphelins (c.-à-d. « non associés ») de l'une ou l'autre des relations, voire des deux.
- jointure gauche (
LEFT [OUTER] JOIN
) : jointure interne augmentée des enregistrements orphelins de la première table (ou encore : ensemble des enregistrements de la première table, complétés - si possible - par les enregistrements de la seconde). - jointure droite (
RIGHT [OUTER] JOIN
) : jointure interne augmentée des enregistrements orphelins de la seconde table. - jointure complète (
FULL [OUTER] JOIN
) : jointure interne augmentée de tous les enregistrements orphelins (de la première et de la seconde table).- Attention, elle n'existe pas dans
MySQl
.
- Attention, elle n'existe pas dans
Exemple de jointure externe droite : liste des stages non affectés
SELECT Stage.* FROM Etudiant RIGHT JOIN Stage ON Etudiant.NumeroStage = Stage.NumeroStage WHERE NumeroINE IS NULL
- Le schéma des jointures est défini comme la réunion des champs des 2 tables. Logiquement, les enregistrements supplémentaires de la jointure externe (ceux orphelins) ne sont caractérisés que par les champs d'une des 2 tables : les champs provenant de l'autre table sont automatiquement fixés à
NULL
.
Définition : jointure naturelle
Une jointure naturelle (NATURAL JOIN
) est une jointures sans condition de jointure explicite : une condition d'égalité est implicitement imposée entre tous les champs communs aux 2 tables jointes.
- Elle n'a donc pas de clause
ON
. - Elle peut être interne comme externe.
Exemple de jointure naturelle (interne) : le seul champ commun aux tables Etudiant
et Stage
étant NumeroStage
, l'exemple précédent se simplifie ainsi
SELECT NumeroINE, Prenom, Nom, Stage.Titre, Stage.Encadrant
FROM Etudiant NATURAL JOIN Stage
Les fonctions d'agrégation et groupements¶
Les fonctions d'agrégation¶
Définition : agréger, agrégat
- Pour le Larousse, agréger c'est : « réunir en un tout des parties distinctes ».
- L'agrégat désigne alors le résultat de cette opération : le « tout » obtenu.
Définition : fonction d'agrégation
Une fonction d'agrégation calcule une statistique sur un ensemble (un agrégat) d'enregistrements.
- En « stats », on appelle « statistique » une fonction d'un échantillon de valeurs, qui lui associe généralement une valeur réelle. C'est un indicateur synthétique, au sens où il caractérise la structure de l'échantillon, de manière condensée. Par exemple, le minimum (la plus petite valeur de l'échantillon), la moyenne (la valeur « centrale » de l'échantillon), l'écart-type (la « dispersion »), etc.
- Quelques fonctions d'agrégation
SQL
, qui s'appliquent généralement à une expression<expr>
(un calcul effectué sur chaque enregistrement, de type nombre, date ou chaîne de caractères) :MIN(<expr>)
,MAX(<expr>)
: minimum et maximum du champ ;SUM([DISTINCT] <expr>)
: somme du champ (qui doit être de type numérique) ;COUNT([DISTINCT] <expr>)
: nombre d'enregistrements dans lequel le champ est nonNULL
;COUNT(*)
: nombre total d'enregistrements de l'agrégat ;AVG([DISTINCT] <expr>)
: moyenne.VARIANCE(<expr>)
: variance.
- Les fonctions d'agégation se placent dans la clause
SELECT
. - L'ensemble d'enregistrements agrégé par défaut est la table résultat, toute entière.
- Sitôt qu'une fonction d'agrégation est projetée par le
SELECT
, l'ensemble d'enregistrements sur lequel elle opère disparaît de la table résultat : il est remplacé par un unique enregistrement « synthétique » (qui caractérise la globalité de ces enregistrements : l'agrégat).
Exemple de fonction d'agrégation : proportion d'étudiants sans stage
SELECT ( COUNT(*) - COUNT(NumeroStage) )/COUNT(*)
FROM Etudiant
Les groupements¶
Définition : groupement
- Les fonctions d'agrégation s'appliquent par défaut à la totalité des enregistrements. Un groupement permet de les agréger en ensembles plus petits.
- Les groupes (ou agrégats) sont constitués d'enregistrements ayant certains « points en commun ».
- En pratique, on propose une série d'expressions, et les enregistrements sont regroupés par égalité de valeurs sur toutes ces expressions.
- C'est la clause
GROUP BY
qui permet de les introduire. - Lorsqu'une expression n'est pas définie pour certains enregistrements (
NULL
), alors ces enregistrements s'agrègent ensemble. Autrement dit,NULL
se comporte comme une valeur.
- La clause
SELECT
se compose uniquement :- d'expressions (dont colonnes) mentionnées dans le
GROUP BY
; - de fonctions d'agégration.
- d'expressions (dont colonnes) mentionnées dans le
Exemple de groupement : nombre de stages par encadrant
SELECT Encadrant, COUNT(*)
FROM Stage
GROUP BY Encadrant
- Les stages sont regroupés par encadrant : 1 groupe par encadrant + 1 groupe pour les stages sans encadrant.
- Pour chacun de ces groupes, le nom de l'encadrant est projeté, ainsi que l'effectif du groupe (qui correspondant au nombre de stages de l'encadrant).
- Le
SELECT
contient la colonne duGROUP BY
, ainsi qu'une fonction d'agrégation.
Définition : sélection/restriction des groupes
- Il est possible d'éliminer certains groupes avant la phase de projection des expressions de groupe et des fonctions d'agrégation (par le
SELECT
). - Grâce à la clause
HAVING
, qui suit immédiatement la clauseGROUP BY
. - Cette clause agit pour les groupes de la même manière que
WHERE
agit pour les enregistrements. Notez que la clauseWHERE
opère avant leGROUP BY
, et donc avant leHAVING
.
Exemple de restriction de groupe : liste des encadrants ayant moins de 2 stages, par ordre alphabétique
SELECT Encadrant
FROM Stage
WHERE Encadrant IS NOT NULL
GROUP BY Encadrant
HAVING COUNT(*)<=2
ORDER BY Encadrant