Vous êtes sur la page 1sur 12

Chapitre 2

SQL Approfondi

1 Introduction
Ce chapitre est dédié au langage SQL sous ses facettes LDD (Langage de Définition
de Données), LMD (Langage de Manipulation de Données), et LCD (Langage de
Contrôle de Données).
Loin d’être une référence exhaustive, ce chapitre se veut néanmoins être un
ensemble de généralités de ce langage et un point de départ pour une maitrise de Nous utiliserons MariaDB
(Un SGBD compatible avec
SQL. Il est donc impératif que l’étudiant fasse sa part du travail en se documentant
MySQL) dans ce chapitre,
et en apprenant les détails de ce langage par ses propres efforts. mais la syntaxe demeure
presque la même à travers
les autres SGBDs qui utilisent
2 SQL : LDD SQL comme langage de re-
quêtes.

2.1 Gestion des bases de données


Pour les SGBDs permettant de gérer plusieurs bases de données comme MySQL
ou PostgreSQL et contrairement à un SGBD embarqué tel que SQlite, SQL nous
permet de créer et de supprimer des bases de données comme suit :

Création, suppression, affichages de bases de données Ces requêtes peuvent être


soumise directement au pro-
gramme mysql sur le serveur,
CREATE DATABASE db; --Créer la base db.
ou via une interface telle que
phpmyadmin ou autre client.
Au fait, les commentaire en
DROP DATABASE db; --Supprimer la base db.
SQL sont précédés de deux
tirets (--).
SHOW DATABASES; --Lister les BDDs sur le serveur.

USE db; --Utiliser la base db.

1
2.2 Gestion des tables
Création de tables

La syntaxe générale de création de tables en SQL est comme suit :

CREATE [OR REPLACE] TABLE table_name(


-- Définition des colonnes:
column1 TYPE(taille) [NOT [NULL]] [UNIQUE] Ce qui est entre [CROCHETS]
[DEFAULT valeur] [PRIMARY KEY] est optionnel.
[REFERENCES table (colonnes)] [CHECK condition];
...
...
-- Contraintes de table:
[PRIMARY KEY (liste de colonnes)];
[UNIQUE (liste de colonnes)];
[FOREIGN KEY (liste de colonnes) REFERENCES table(colonnes)]
[ON DELETE {RESTRICT, CASCADE, SET NULL}]
[ON UPDATE {RESTRICT, CASCADE, SET NULL}],
[CHECK (condition)]

);

Ci-dessous un exemple de création de table.


Exemple: Création d’une table

CREATE TABLE produits(


id INTEGER NOT NULL AUTO_INCREMENT, -- id du produit.
categorie_id INTEGER REFERENCES categories(id),
libelle VARCHAR(30) NOT NULL DEFAULT ’’,
prix DECIMAL(6,2) NOT NULL DEFAULT 0.00
);

Principaux types de donnés

Les types de données carient souvent avec le SGBD utilisé, mais en général, nous
avons :
CHAR(n) : Chaine de caractère de taille fixe (n caractères).
VARCHAR(n) : Chaine de caractère de taille variable (n caractère). Veuillez vous référer à la do-
TINYINT : Entier entre -128 et 127. (Ou 0 255 pour les nombres non signés). cumentation de votre SGBD
pour les différents types qu’il
INT (ou INTEGER) : Entier (signé ou pas) sur 4 octets. propose.

DECIMAL(n, m) : Nombres décimaux avec n chiffres significatifs et m chiffres


après la virgule.
DATE : Date (AAAA-MM-JJ)
TIME : heure (HH :mm :SS :ssss).
...

2
Les contraintes d’intégrité

NOT NULL : Les valeurs nulles ne sont pas autorisées (le champ doit être rensei-
gné).
UNIQUE : La colonne ne peut contenir la même valeur plus d’une fois.
PRIMARY KEY : La colonne est une clé primaire.
CHECK : La, ou les colonnes, doivent satisfaire une certaine condition.
CASCADE : Cascader la suppression quand l’enregistrement de la clé étrangère
est supprimé.
SET NULL : Mettre à NULL la colonne quand l’enregistrement de la clé étrangère
est supprimé.
SET DEFAULT : Affecter la valeur par défaut lorsque la colonne quand l’enregis-
trement de la clé étrangère est supprimé.
RESTRICT : Rejeter la suppression (ou la mise à jour).

Ces contraintes peuvent être définies pour une seule colonne (au niveau de la
colonne elle-même) ou de plusieurs colonnes (comme des contraintes de table).
Elles peuvent être établie à la création de la table, ou à sa modification (ALTER
TABLE).

Modification de tables

Pour supprimer une table :

DROP TABLE table_name;

Pour renommer une table :


ALTER TABLE table_name RENAME TO new_table_name;

Pour ajouter ou modifier une colonne :

ALTER TABLE table_name {ADD/MODIFY} ([col type [constraint], ...]);

Pour renommer une colonne :


ALTER TABLE table_name RENAME COLUMN old_name TO new_name;

Pour supprimer une colonne :

ALTER TABLE table_name DROP COLUMN col;

Pour ajouter une contrainte de table :

ALTER TABLE table_name ADD [CONSTRAINT constraint_name ] constraint;

Pour supprimer une contrainte :

ALTER TABLE table_name DROP CONSTRAINT constraint_name;

3
Création et suppression d’index

Les index permettent d’optimiser les requêtes sur les tables. Ils peuvent être définis
sur une seule ou plusieurs colonnes à la fois. Notez que la contrainte [PRIMARY
KEY] créé automatiquement un index sur la colonne en question.
Pour créer un index :

CREATE INDEX iindex_name ON table_name(col1, [col2, ..]);

Pour en supprimer :

DROP INDEX index_name;

Exemple :
Exemple: Création d’un index

CREATE TABLE users(


id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
username CHAR(12) NOT NULL DEFAULT ’’,
-- 123 is a bad password.
password VARCHAR(100) NOT NULL DEFAULT ’123’
)
CREATE INDEX username_idx ON users(username);

2.3 Gestion des triggers


Les déclencheurs, ou triggers, sont un mécanisme qui nous permet d’automatiser
certains traintements suite à certains évènements qui surgissent sur les tables de la
base de données.
Ces évènements peuvent concerner l’insertion de nouveaux enregistrements dans
une table, la modification, ou la suppression d’enregistrements. Il faut envisager les triggers
comme un outil qui permet de
définir une business logic en
Syntaxe générale pour la création de triggers SQL au lieu de l’implémenter
avec du code dans vos applica-
CREATE TRIGGER [IF NOT EXISTS] trigger_Name tions.
(BEFORE | AFTER) [INSERT | UPDATE | DELETE] ON [nable_Name]
FOR EACH ROW
[trigger_body]

Si le corp du trigger (trigger_body) est composé de plusieurs commandes SQL,


ces dernières peuvent être enveloppées entre BEGIN et END à condition de redéfinir
le délimiteur de commandes momentanément comme suit :

4
DELIMITER // -- Le délimiteur n’est plus le point-virgule
CREATE TRIGGER [IF NOT EXISTS] trigger_Name
(BEFORE | AFTER) [INSERT | UPDATE | DELETE] ON [nable_Name]
FOR EACH ROW
BEGIN
[trigger_body]
END//
DELIMITER ; -- Le délimiteur est remis à sa valeur (point-virgule).

Comme vous l’aurez devité, la syntaxe précédente créé le trigger trigger_name


pour exécuter les instructions dans trigger_body avant (BEFORE) ou après (AFTER)
l’insertion, la mise à jour, ou la suppression d’enregistrements de la table table_name
Par exemple, imaginez que l’on veuille garder trace des dates de changement
des profils des utilisateurs d’une application. Pour ce, nous avons une table users
définie comme suit :
Exemple: Création d’un trigger

CREATE TABLE users(


id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
username CHAR(12) NOT NULL DEFAULT ’’,
password VARCHAR(100) NOT NULL DEFAULT ’123’,
changed DATETIME
);

-- Création du trigger de la mise à jour de l’utilisateur.


CREATE TRIGGER IF NOT EXISTS user_changed
AFTER UPDATE ON users
FOR EACH ROW
UPDATE users SET changed = now() WHERE users.id = new.id;

Nouveaux et anciens enregistrements

Comme vous l’avez remarqué dans l’exemple précédent, nous avons utilisé le
mot-clé new. Nous avons aussi un autre : old. Ces deux mots-clés réfèrent aux
enregistrements (nouveaux ou anciens) de la table en question. Par exemple : new
n’est défini que pour les commandes INSERT et UPDATE, alors que old n’est défini
que pour les instructions UPDATE et DELETE. Ce qui est tout à fait normal.
Car à l’insertion, il n’y a pas
d’enregistrement ancien (donc
pas de old et à la suppression,
3 SQL : LMD il n’y a pas de nouveau en-
registrement et donc pas de
Nous verrons dans ce qui suit les principales opérations de manipulations de new.
données offertes par SQL. Notons que cette revue n’est pas exhaustive car le langage
SQL est assez vaste, mais donne une idée générale de ce qui est possible.
Les commandes SQL permettant de manipuler les données sont : INSERT, UPDATE,
DELETE, et SELECT. Elles permettant respectivement d’insérer de nouveaux enregis-
trements, de les mettre à jour, de les supprimer, et de les afficher (rechercher).

5
3.1 Insertion de nouveaux enregistrements
L’insertion de nouveaux enregistrements obeït à la syntaxe suivante :

INSERT INTO table_name [(col1, col2, ...)]


VALUES (v1, v2, ...)[, (v1a, v2a,...)];

La liste des colonnes est optionnelle, elle spécifie quelles colonnes sont renseignées
et dans quel ordre. Si cette liste de colonnes est omise, les valeurs doivent être
renseignées dans l’ordre de leur définition lors de la création de la table.
Remarque : Les colonnes non renseignées se verront affecter la valeur NULL.
Exemple: Insertion de plusieurs enregistrements

INSERT INTO users (username, password)


VALUES (’admin’, ’passe’),
(’gestion’, ’gpass’),
(’albert’, ’emc2’);

L’insertion peut aussi se faire avec des tuples issus d’un SELECT comme suit :

INSERT INTO table_name [(col1, col2, ...)]


SELECT ...

Exemple: Insertion de plusieurs enregistrements

INSERT INTO users (username, password)


SELECT M.login, M.passwd FROM members AS M
WHERE M.typecompte = ’USER’;

3.2 Mise à jour d’enregistrements


La mise à jour se fait avec la commande UPDATE comme suit :

UPDATE table_name SET col1=val1[, col2=val2, ...]


[WHERE condition]

Par exemple, pour modifier le username d’Einstein en Alber, nous effectuons :


Exemple: Mise à jour d’enregistrements.

UPDATE users SET username=’Albert’ WHERE username=’Einstein’;

3.3 Suppression d’enregistrements


Pour supprimer des enregistrements, nous utilisons DELETE :

DELETE FROM table_name [WHERE condition];

Par exemple, pour supprimer tous les produits en rupture de stock, nous pouvons
faire ceci :

6
Exemple: Suppression d’enregistrements qui satisfont une condition.

DELETE FROM produits WHERE (quantite < quantite_seuil);

Quand on ne précise pas de clause WHERE, tous les enregistrements seront affectés
que cela soit pour un UPDATE ou un DELETE.

3.4 Sélection d’enregistrements


La commande SELECT nous permet d’interroger la base de données pour récupérer
les enregistrements (ou colonnes, ou encore composition de colonnes de différentes
tables) qui satisfont une éventuelle condition, de les trier, de les regrouper, etc.
La syntaxe du SELECT est complexe, mais on peut résumer les options les plus
utilisées comme suit :

SELECT [ALL | DISTINCT | DISTINCTROW] [colonnes]


[ FROM table_references
[WHERE where_condition]
[GROUP BY {col_name | expr | position} [ASC | DESC], ... ]
[HAVING where_condition]
[ORDER BY {col_name | expr | position} [ASC | DESC], ...]

où tables_references peut exprimer une table, plusieurs tables séparées par


des virgules, ou bien des jointures.

WHERE : est une clause qui spécifie une condition (ou combinaison de condi-
tions) que les enregistrements doivent satisfaire pour être retournés par la
requête.
GROUP BY : Permet de regrouper des enregistrements qui ont des colonnes (ou
des valeurs calculées) en commun.
HAVING : Permet de filtrer les groupes (issus de GROUP BY) selon une condition
donnée.
ORDER BY : Permet de trier les résultats de la requête sur une ou plusieurs
colonnes (par ordre ascendant ASC ou descendant DESC.

Ci-dessous quelques exemples de requêtes SELECT pour illustrer ces différentes


options.
Nous commençons par la table des catégories.
Exemple: Une table de catégories

DROP TABLE IF EXISTS categories;


CREATE TABLE categories(
id INTEGER AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL DEFAULT ’NO CATEGORY’
)
-- Création d’une catégorie par défaut.
INSERT INTO categories (id, name) VALUES (0, ’NO CATEGORY’);

Ensuite les produits.

7
Exemple: Une table de produits.

DROP TABLE IF EXISTS categories;


CREATE TABLE produits(
id INTEGER AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL DEFAULT ’NO CATEGORY’,
quantitie INTEGER NOT NULL DEFAULT ’0’,
quantitie_seuil INTEGER NOT NULL DEFAULT ’0’,
cat_id INTEGER NOT NULL DEFAULT ’0’
)

Nous voulons afficher tous les produits dont la quantité est supérieure à 10 :
Exemple:

SELECT * FROM produits WHERE quantite > 10;

Nous voulons récupérer les produits en rupture de stock :


Exemple:

SELECT * FROM produits WHERE quantite <= quantite_seuil;

Afficher les produits ainsi que leurs noms de catégories :


Exemple:

SELECT P.name, C.name


FROM produits AS P
LEFT JOIN categories AS C ON (P.cat_id = C.id);

Afficher les catégories ainsi que le nombre de produits par catégorie, mais n’affi-
cher que les catégories qui ont plus de 5 produits.
Exemple:

SELECT C.name, COUNT(P.id) AS nombre


FROM produits AS P
RIGHT JOIN categories AS C ON(C.id = P.cat_id)
GROUP BY C.id
-- N’afficher que les catégories ayant plus d’un produit.
HAVING nombre > 1
ORDER BY nombre DESC;

Notez aussi que les résultats des requêtes SELECT peuvent être combinés avec des
opérateurs d’ensembles comme l’union (UNION), l’intersection (INTERSECT), etc.
Par ailleurs, les requêtes SELECT peuvent être imbriquées.
Par exemple, pour afficher les catégories des produits en rupture de stock, nous
pouvons faire :

8
Exemple:

SELECT name FROM (


SELECT C.name FROM produits AS P
LEFT JOIN categories AS C ON (P.cat_id = C.id)
WHERE (P.quantite < P.quantite_seuil)
);

Pour revenir un peu sur les triggers, imaginez que l’on veuille réaffecter les
produits dont les catégories ont été supprimées à la catégorie (1, ’NO CATEGORY’),
nous écrivons ceci :
Exemple:

CREATE TRIGGER IF NOT EXISTS categorie_deleted


BEFORE DELETE ON categories
FOR EACH ROW
UPDATE produits SET cat_id = 1 WHERE cat_id = old.id;

3.5 Les vues en SQL


Définition et avantages

SQL nous offre la possibilité de définir des vues sur les données, ces vues sont
souvent appelées tables virtuelles car elles n’ont pas d’existence physique proprement
dite.
Les vues offrent plusieurs avantages tels que :

Independance logique : les applications sont indépendantes du schéma interne


des données en ce sens qu’elles n’aperçoivent pas réellement les tables mais
des représentations de celles-ci. En d’autres termes, on peut bien modifier le
schéma interne sans que les applications n’en soient affectées.
Simplification des traitements : En définissant une vue comme une suite de
jointures complexes, l’application n’a pas à définir ces jointures de façon
explicite, et le code est donc plus simplifié.
Confidentialité des données : On peut créer des vues qui ne renvoient que les
données essentielles et cacher ainsi les données sensibles dont l’application n’a
pas besoin —et ne doit pas connaitre.

Création et suppression de vues

Pour créer une vue, nous utilisons la commande CREATE VIEW dont la syntaxe
simplifiée est comme suit :

CREATE [OR REPLACE] VIEW [IF NOT EXISTS] view_name [(columns)] AS


select_statement;

Autrement dit, la vue est céée comme un raccourci pour un SELECT aussi complexe
puisse-t-il être. Par exemple, nous pouvons reprendre l’exemple de la jointure des
produits et des catégories ci-dessus comme suit :

9
Exemple: Exemple de vues.

CREATE VIEW produits_categories (id, libelle, qte, cnom) AS


SELECT P.id, P.libelle, P.quantite, C.name FROM
produits AS P
LEFT JOIN categories AS C ON (C.id = P.cat_id);

Et désormais les applications peuvent utiliser cette vue comme si c’était une table
réelle comme suit :
Exemple:

SELECT * FROM produits_categories WHERE (qte > 10)

Pour supprimer une vue, il suffit d’utiliser la commande DROP VIEW comme suit :

DROP VIEW [IF EXISTS] view_name [, view_name2, view_name3, ...]

4 SQL : LCD
En plus des contraintes d’intégrité citées plus haut, SQL offre aussi la possibilité
de définir des règles de contrôle d’accès aux données. En effet, dans un contexte
client-serveur, où plusieurs clients peuvent se connecter au serveur (SGBD) et y
soumettre des requêtes, il serait judicieux de définir qui peut faire quoi avec les
données stockées et gérées par le SGBD.
Pour ce, SQL définit des utilisateurs (USER) et des des privilèges.

4.1 Gestion des utilisateurs


Pour cérer un utilisateur, nous avons la syntaxe suivante :

CREATE [OR REPLACE] USER [IF NOT EXISTS] user@host


IDENTIFIED BY [PASSWORD] password;
Nous nous référons à la docu-
Si [PASSWORD] a été spécifié, SQL s’attends à ce que le mot de passe ait été haché mentation de MariaDB dans
auparavant, sinon SQL le fera pour vous. cette section.

Exemple:

CREATE USER IF NOT EXISTS user1@localhost IDENTIFIED BY ’SGBD’;

Dans cet exemple, le mot de passe ’SGBD’ sera haché avant d’être mis sur le
serveur.
Exemple:

SELECT PASSWORD(’SGBD’)

Sette requête renvoie la valeur *3A1AEF69D234762A6F9EB885A602E4EFE238AC88.


Ensuite, nous l’utilisons comme suit :

10
Exemple:

CREATE USER IF NOT EXISTS user2@localhost IDENTIFIED BY PASSWORD


’*3A1AEF69D234762A6F9EB885A602E4EFE238AC88’;

Pour supprimer un utilisateur, il suffit de soumettre la requête :

DROP USER IF EXISTS user1@localhost;

Pour éditer un utilisateur, nous avons ALTER USER :

ALTER USER user1@localhost IDENTIFIED BY ’NEW PASSWORD’;


-- Idem, on peut spécifier PASSWORD avec un hash.

Pour lister les utilisateurs des SGBD MySQL (ou MariaDB), il suffit d’effectuer un
SELECT sur la table mysql.user :

SELECT User FROM mysql.user;

4.2 Gestion des privilèges


Ces utilisateurs peuvent se voir accorder des privilèges différents sur les tables de
la base de données (voire les colonnes d’une table donnée).

Accorder des privilèges

La commande GRANT permet d’accorder ces privilèges avec la syntaxe suivante :

GRANT privilege [(columns)]


[privilege [(columns)], ...]
ON table, privilege_level
TO user;

Où privilege peut concerner une base de données ou des tables. Par exemple,
parmi les privilèges sur les base de données, nous pouvons citer : CREATE, DROP,
CREATE TEMPORARY TABLE, etc.
Et les privilèges sur les tables : ALTER, CREATE, DROP, INDEX, INSERT, SELECT,
UPDATE, DELETE, etc.
Quant à la spcéfication de columns dans la syntaxe sus-citée, elle permet de
préciser des privilèges sur les colonnes d’une table donnée, et peut être utilisée dans
INSERT (columns), SELECT columns, ou UPDAET columns.
Par ailleurs, privilege_level permet de spécifier de façon générale le niveau de
privilèges, tel qu’indiqué ici :

*.* : Permet de tout gérer : les bases, les tables, les utilisateurs, etc.
db_name.* : Permet de gérer toutes les tables d’une base de données db_name.
db_name.table_name : Permer de gérer la table table_name de la base de
données db_name.

11
Voyons quelques exemples de la commande GRANT :
Exemple: Tous les droits à l’utilisateur dba

GRANT ALL PRIVILEGES ON *.* TO ’dba’@’%’ ;

Par exemple, on peut accorder le droit à l’utilisateur moi de modifier les valeurs
le % à la place du host signifie
de la colonne name de la table categories de la base de données joins. quelque soit le host.
Exemple:

GRANT UPDATE(name) ON joins.categories TO moi@localhost;

Pour afficher les privilèges accordés à un utilisateur donné, nous utilons la com-
mande SHOW GRANTS comme suit :
Exemple:

SHOW GRANTS for moi@localhost;

Révoquer des privilèges

La commande REVOKE permet de retirer des privilèges à un ou plusieurs utilisa-


teurs comme suit :
REVOKE
priv_type [(column_list)]
[, priv_type [(column_list)]] ...
ON table, priv_level
FROM user [, user]

Par exemple, pour retirer à l’utilisateur test le droit de supprimer des catégories,
nous pouvons faire ceci :
Exemple:

REVOKE DELETE ON joins.categories FROM test@localhost;

5 Références
1. https://mariadb.com/kb/en/documentation/
2. https://sqlite.org/lang.html
3. https://www.postgresql.org/docs/current/sql.html

Rédaction collaborative

Vous êtes vivement invités à commenter ce chapitre sur le forum et à y poser


vos questions. Vos remarques, et vos éventuelles améliorations/corrections
sont les bienvenues.

12

Vous aimerez peut-être aussi