Pr. EL HADIQ Zouhair
ModÚle relationnel, modÚle entité-association, clés primaires et étrangÚres, et manipulation des données avec le langage SQL sous SQLite.
Tous les exemples utilisent une petite base d'une université, composée de quatre tables :
Departement(id, nom)Etudiant(id, nom, prenom, age, id_dep)Module(code, intitule, credits)Inscription(id_etudiant, code_module, note)Une base de données est un ensemble structuré de données mémorisées de façon durable et partagées par plusieurs utilisateurs. Un SGBD (SystÚme de Gestion de Base de Données) est le logiciel qui gÚre cette base : il en assure le stockage, la cohérence et l'interrogation. Dans ce cours, le SGBD utilisé est SQLite, un SGBD léger qui stocke toute la base dans un seul fichier.
Dans le modÚle relationnel, les données sont organisées en tables. Le vocabulaire est le suivant :
| Terme | Synonyme | Signification |
|---|---|---|
| Table | relation | Tableau à deux dimensions décrivant une catégorie d'objets. |
| Attribut | colonne, champ | Une propriété décrivant les objets (ex. : nom, age). |
| Enregistrement | ligne, n-uplet, tuple | Un objet de la table (une valeur par attribut). |
| Domaine | type | Ensemble des valeurs possibles d'un attribut (entier, texteâŠ). |
| SchĂ©ma | â | Description de la table : nom + liste des attributs et de leurs domaines. |
Le schéma de la table des étudiants se note : Etudiant(id, nom, prenom, age, id_dep). Voici un extrait du contenu (les enregistrements) :
| id | nom | prenom | age | id_dep |
|---|---|---|---|---|
| 1 | Alami | Sara | 19 | 1 |
| 2 | Bennani | Karim | 20 | 1 |
| 3 | Chraibi | Yasmine | 21 | 2 |
INTEGER (entiers), REAL (rĂ©els), TEXT (chaĂźnes), NULL (valeur absente). La valeur spĂ©ciale NULL signifie « information inconnue ou non renseignĂ©e » ; elle n'est Ă©gale Ă rien, pas mĂȘme Ă NULL.
Avant de créer les tables, on conçoit la base au moyen d'un modÚle entité-association (modÚle E/A, ou modÚle entité-relation). C'est un schéma de conception, indépendant du SGBD, qui décrit ce que représente la base.
| Notion | Définition |
|---|---|
| EntitĂ© | Un type d'objet du monde rĂ©el que l'on veut dĂ©crire (ex. : Ătudiant, Module). |
| Attribut | Une propriété d'une entité ou d'une association (ex. : nom, age). |
| Identifiant | Un (ou plusieurs) attribut qui distingue de façon unique chaque objet de l'entité. |
| Association | Un lien sémantique entre deux entités (ex. : un étudiant s'inscrit à un module). |
| Cardinalités | Combien d'objets de chaque cÎté participent à l'association (1-1, 1-*, *-*). |
Une cardinalité indique, pour une entité, combien d'occurrences de l'autre entité lui sont reliées :
La clĂ© primaire d'une table est un attribut (ou un groupe d'attributs) dont la valeur identifie de façon unique chaque enregistrement. Deux lignes ne peuvent pas avoir la mĂȘme valeur de clĂ© primaire, et celle-ci ne peut jamais ĂȘtre NULL. Dans Etudiant, la clĂ© primaire est id.
Inscription, le couple (id_etudiant, code_module) joue le rÎle de clé primaire : un étudiant ne s'inscrit qu'une fois à un module donné.
Une clé étrangÚre est un attribut d'une table qui référence la clé primaire d'une autre table. Elle matérialise le lien entre deux tables et garantit la cohérence référentielle : une valeur de clé étrangÚre doit correspondre à une ligne existante dans la table référencée.
Dans Etudiant, l'attribut id_dep est une clé étrangÚre qui référence Departement(id) : il indique à quel département appartient chaque étudiant.
CREATE TABLE Departement (
id INTEGER PRIMARY KEY,
nom TEXT NOT NULL
);
CREATE TABLE Etudiant (
id INTEGER PRIMARY KEY,
nom TEXT NOT NULL,
prenom TEXT,
age INTEGER,
id_dep INTEGER,
FOREIGN KEY (id_dep) REFERENCES Departement(id)
);
| Clé primaire | Clé étrangÚre |
|---|---|
| Identifie une ligne de SA table. | Pointe vers une ligne d'UNE AUTRE table. |
Unique, jamais NULL. | Peut se rĂ©pĂ©ter, peut ĂȘtre NULL. |
| Une seule par table. | Plusieurs possibles par table. |
On transforme le schéma E/A en tables selon des rÚgles systématiques.
Chaque entitĂ© devient une table. Ses attributs deviennent des colonnes et son identifiant devient la clĂ© primaire. Ainsi : Ătudiant ⇒ Etudiant(id, nom, prenom, age) et Module ⇒ Module(code, intitule, credits).
Pour une association 1 - *, on ajoute dans la table du cÎté « plusieurs » une clé étrangÚre référençant la clé primaire du cÎté « un ». Un département contient plusieurs étudiants (1-*) : on ajoute donc id_dep dans Etudiant.
Une association * - * ne peut pas se traduire par une simple clé étrangÚre. On la décompose en deux associations 1 - * en créant une table de liaison (table d'association). Sa clé primaire est composée des deux clés étrangÚres vers les entités liées ; les attributs de l'association y sont ajoutés.
CREATE TABLE Module (
code TEXT PRIMARY KEY,
intitule TEXT NOT NULL,
credits INTEGER
);
CREATE TABLE Inscription (
id_etudiant INTEGER,
code_module TEXT,
note REAL,
PRIMARY KEY (id_etudiant, code_module),
FOREIGN KEY (id_etudiant) REFERENCES Etudiant(id),
FOREIGN KEY (code_module) REFERENCES Module(code)
);
Le SQL (Structured Query Language) est le langage standard d'interrogation et de manipulation des bases relationnelles. Une instruction SQL s'appelle une requĂȘte. Cette section prĂ©sente les trois requĂȘtes qui modifient les donnĂ©es.
INSERT INTO Etudiant (id, nom, prenom, age, id_dep)
VALUES (1, 'Alami', 'Sara', 19, 1);
-- plusieurs lignes d'un coup :
INSERT INTO Departement (id, nom) VALUES
(1, 'Mathematiques'),
(2, 'Informatique');
'âŠ'. Si l'on omet la liste des colonnes, il faut fournir une valeur pour chaque colonne, dans l'ordre du schĂ©ma.
UPDATE Etudiant SET age = 22 WHERE id = 3;
UPDATE (ou DELETE) sans clause WHERE s'applique à toutes les lignes de la table. Toujours vérifier la condition avant d'exécuter.
DELETE FROM Etudiant WHERE age < 18;
La requĂȘte SELECT extrait des donnĂ©es sans les modifier. Sa forme de base :
SELECT <colonnes> -- projection FROM <table> WHERE <condition>; -- sélection
La projection garde certaines colonnes. En algĂšbre relationnelle on la note π (pi). SELECT nom, prenom FROM Etudiant; correspond Ă πnom, prenom(Etudiant). Le symbole * sĂ©lectionne toutes les colonnes.
La sĂ©lection garde les lignes vĂ©rifiant une condition. En algĂšbre relationnelle on la note σ (sigma). SELECT * FROM Etudiant WHERE age ≥ 20; correspond Ă σage ≥ 20(Etudiant).
Le mot-clé DISTINCT supprime les lignes en double dans le résultat. Pour obtenir la liste des ùges sans répétition :
SELECT DISTINCT age FROM Etudiant;
| Opérateur | RÎle | Exemple |
|---|---|---|
= != < > <= >= | Comparaisons | age >= 20 |
AND OR NOT | Connecteurs logiques | age > 18 AND id_dep = 1 |
IN | Appartenance Ă une liste | id_dep IN (1, 3) |
BETWEEN ⊠AND ⊠| Encadrement (bornes incluses) | age BETWEEN 19 AND 21 |
LIKE | Motif texte (% = toute suite, _ = un caractĂšre) | nom LIKE 'A%' |
LIKE. 'A%' = commence par A ; '%i' = finit par i ; '%ar%' = contient « ar » ; '_a%' = a un « a » en 2ᔠposition.
On peut combiner les rĂ©sultats de deux requĂȘtes SELECT qui ont le mĂȘme nombre de colonnes, de types compatibles, par les opĂ©rateurs ensemblistes :
| Opérateur | Ensemble | Résultat |
|---|---|---|
UNION | A ∪ B | Lignes de l'une OU l'autre (doublons supprimĂ©s). |
INTERSECT | A ∩ B | Lignes prĂ©sentes dans les deux. |
EXCEPT | A − B | Lignes de A absentes de B (diffĂ©rence). |
SELECT nom FROM Etudiant WHERE id_dep = 1 EXCEPT SELECT nom FROM Etudiant WHERE age > 20;
Le produit cartĂ©sien de deux tables associe chaque ligne de la premiĂšre Ă chaque ligne de la seconde. Si A a m lignes et B a n lignes, le rĂ©sultat en a m × n. On l'obtient en listant deux tables dans le FROM :
SELECT * FROM Etudiant, Departement; -- toutes les combinaisons
Une jointure interne combine les lignes de deux tables en ne gardant que les couples qui vérifient une condition de liaison, typiquement l'égalité d'une clé étrangÚre et d'une clé primaire. C'est un produit cartésien immédiatement filtré.
SELECT Etudiant.nom, Departement.nom FROM Etudiant JOIN Departement ON Etudiant.id_dep = Departement.id;
On relie ainsi chaque Ă©tudiant au nom de son dĂ©partement. Pour une requĂȘte croisant trois tables (les notes par module), on enchaĂźne les jointures :
SELECT Etudiant.nom, Module.intitule, Inscription.note FROM Inscription JOIN Etudiant ON Inscription.id_etudiant = Etudiant.id JOIN Module ON Inscription.code_module = Module.code;
nom), on lÚve l'ambiguïté en écrivant Table.colonne.
Le mot-clĂ© AS donne un alias (nom temporaire) Ă une colonne ou Ă une table, le temps de la requĂȘte. Cela rend les rĂ©sultats plus lisibles et raccourcit les jointures.
SELECT E.nom AS etudiant,
D.nom AS departement
FROM Etudiant AS E
JOIN Departement AS D ON E.id_dep = D.id;
Ici la colonne rĂ©sultat s'appelle etudiant au lieu de nom, et l'on Ă©crit E et D Ă la place des noms complets. Le renommage de table est indispensable pour l'auto-jointure (joindre une table avec elle-mĂȘme).
Une fonction d'agrégation calcule une valeur unique à partir d'un ensemble de lignes :
| Fonction | Calcule |
|---|---|
COUNT(*) | le nombre de lignes |
SUM(col) | la somme |
AVG(col) | la moyenne |
MIN(col) / MAX(col) | le minimum / le maximum |
Sans GROUP BY, l'agrégat porte sur toute la table (un seul groupe) :
SELECT COUNT(*), AVG(age) FROM Etudiant; -- 1 ligne résultat
La clause GROUP BY partitionne les lignes selon une (ou plusieurs) colonnes, puis applique l'agrégat à chaque groupe. Pour la note moyenne par module :
SELECT code_module, AVG(note) AS moyenne FROM Inscription GROUP BY code_module;
La clause HAVING filtre les groupes aprÚs agrégation, comme WHERE filtre les lignes avant. Pour ne garder que les modules dont la moyenne dépasse 12 :
SELECT code_module, AVG(note) AS moyenne FROM Inscription GROUP BY code_module HAVING AVG(note) > 12;
| WHERE | HAVING |
|---|---|
| S'applique avant le regroupement. | S'applique aprĂšs le regroupement. |
| Filtre des lignes. | Filtre des groupes. |
| Ne peut pas porter sur un agrĂ©gat. | Peut porter sur un agrĂ©gat (AVG, COUNTâŠ). |
ORDER BY trie les lignes du résultat selon une ou plusieurs colonnes : ASC (croissant, par défaut) ou DESC (décroissant). LIMIT borne le nombre de lignes affichées, et OFFSET en saute un certain nombre au début.
SELECT nom, age FROM Etudiant ORDER BY age DESC, nom ASC LIMIT 5 OFFSET 2; -- saute 2 lignes, en affiche 5
ORDER BY age DESC, nom ASC : tri principal par ùge décroissant ; en cas d'égalité, tri secondaire par nom croissant.
Une sous-requĂȘte est une requĂȘte SELECT placĂ©e Ă l'intĂ©rieur d'une autre, entre parenthĂšses. Elle peut apparaĂźtre dans une clause WHERE, FROM ou HAVING. Elle sert Ă comparer avec une valeur ou un ensemble calculĂ©s dynamiquement.
Les étudiants plus ùgés que la moyenne :
SELECT nom, age FROM Etudiant WHERE age > (SELECT AVG(age) FROM Etudiant);
Avec IN / NOT IN, on compare Ă un ensemble de valeurs renvoyĂ© par la sous-requĂȘte. Les Ă©tudiants inscrits Ă au moins un module :
SELECT nom FROM Etudiant WHERE id IN (SELECT id_etudiant FROM Inscription);
Avec EXISTS / NOT EXISTS, on teste si la sous-requĂȘte renvoie au moins une ligne. Les dĂ©partements qui ont au moins un Ă©tudiant :
SELECT nom FROM Departement D WHERE EXISTS (SELECT 1 FROM Etudiant E WHERE E.id_dep = D.id);
| OpĂ©rateur | Usage avec une sous-requĂȘte |
|---|---|
=, <, >, !=, <=, >= | Comparaison à une valeur unique renvoyée. |
IN / NOT IN | Appartenance / non-appartenance à l'ensemble renvoyé. |
EXISTS / NOT EXISTS | Vrai si la sous-requĂȘte renvoie (n')au moins une ligne (aucune). |
INSERT INTO, UPDATE ⊠SET ⊠WHERE, DELETE FROM ⊠WHERE.SELECT = projection (π, colonnes) + sĂ©lection (σ, WHERE) ; DISTINCT ĂŽte les doublons.UNION, INTERSECT, EXCEPT, produit cartĂ©sien, et surtout la jointure JOIN ⊠ON âŠ.COUNT/SUM/AVG/MIN/MAX + GROUP BY, filtrĂ©s par HAVING.ORDER BY, LIMIT, OFFSET ; et sous-requĂȘtes dans WHERE/FROM/HAVING avec IN, EXISTSâŠInformatique CPGE MP/PSI · Les bases de donnĂ©es relationnelles