Pour parfaire ses connaissance de MySQL, voici quelques exercices à réaliser :
- Création d’un utilisateur
- Importation et rétro-ingénierie d’une base de données
- Requêtes SQL
- Procédures stockées
- Triggers
- Transactions
- Verrous
Exercice 1 : Création d’un utilisateur
Créez un utilisateur zoo
avec le mot de passe zoo
ayant tous les droits sur la base de données zoo
.
Étapes :
- Connectez-vous à MySQL en tant que root
mysql -u root -p
- Créez l’utilisateur
zoo
CREATE USER 'zoo'@'localhost' IDENTIFIED BY 'zoo';
Si MySQL 8.0 ou supérieur, il est possible que ce mot de passe, trop simple, ne soit pas accepté. Pour contourner ce problème, vous pouvez utiliser le plugin mysql_native_password
:
CREATE USER 'zoo'@'localhost' IDENTIFIED WITH mysql_native_password BY 'zoo';
- Donnez tous les droits à l’utilisateur
zoo
sur la base de donnéeszoo
GRANT ALL PRIVILEGES ON zoo.* TO 'zoo'@'localhost';FLUSH PRIVILEGES;exit;
Pour vérifier que l’utilisateur a bien été créé, vous pouvez vous reconnecter à MySQL en tant qu’utilisateur zoo
:
mysql -u zoo -pzoo
Le zoo
Pour la suite des exercices, nous allons utiliser une base de données nommée zoo
.
Vous pouvez télécharger le code SQL de cette base ici.
Exercice 2 : Importation de la base de données
Pour importer la base de données, vous pouvez utiliser la commande suivante :
mysql -u zoo -pzoo < zoo.sql
Remarque : cette commande va fonctionner car nous avons créé un utilisateur zoo
avec les droits nécessaires sur la base de données zoo
.
Rétro-ingénierie
Grâce à la commande db2dbml
, vous pouvez générer un fichier DBML à partir de la base de données zoo
.
db2dbml mysql 'mysql://zoo:zoo@localhost:3306/zoo' -o zoo.dbml
Prenez le temps de lire le fichier zoo.dbml
pour comprendre la structure de la base de données.
Exercice 3 : Requêtes SQL
- Affichez tous les animaux du zoo
- Affichez les repas ainsi que les animaux qui ont pu y avoir accès
- Affichez les animaux qui ont plus de 22 ans
- Extraire les données temporelles de la date de naissance des animaux (date, jour, jour du mois, jour de la semaine, nom du jour, jour de l’année, mois, année, heure, minute, seconde, semaine de l’année, quart d’heure, milliseconde, etc.)
Solutions
-- 1. Affichez tous les animaux du zooSELECT *FROM animal;
-- 2. Affichez les repas ainsi que les animaux qui ont pu y avoir accèsSELECT date_repas, nom_vulgaire, nom, designationFROM repas JOIN aliment ON repas.aliment_id = aliment.id JOIN mange ON mange.aliment_id = aliment.id JOIN animal ON mange.animal_id = animal.id JOIN espece ON animal.espece_id = espece.idORDER BY date_repas, nom_vulgaire, nom, designation;
-- 3. Affichez les animaux qui ont plus de 22 ansSELECT *FROM animalWHERE date_naissance < (CURDATE() - INTERVAL 22 YEAR);
-- 4. Extraire les données temporelles de la date de naissance des animaux (date, jour, jour du mois, jour de la semaine, nom du jour, jour de l'année)SELECT nom, DATE(date_naissance) AS date_naiss, DAY(date_naissance) AS jour, DAYOFMONTH(date_naissance) AS jour, DAYOFWEEK(date_naissance) AS jour_sem, WEEKDAY(date_naissance) AS jour_sem2, DAYNAME(date_naissance) AS nom_jour, DAYOFYEAR(date_naissance) AS jour_annee, WEEK(date_naissance) AS semaine, WEEKOFYEAR(date_naissance) AS semaine2, YEARWEEK(date_naissance) AS semaine_annee, MONTH(date_naissance) AS numero_mois, MONTHNAME(date_naissance) AS nom_mois, YEAR(date_naissance) AS annee, TIME(date_naissance) AS time_complet, HOUR(date_naissance) AS heure, MINUTE(date_naissance) AS minutes, SECOND(date_naissance) AS secondesFROM Animal;
Exercice 4 : Procédures stockées
- Créez une procédure stockée
get_animals
qui affiche tous les animaux du zoo - Créez une procédure stockée
get_animals_by_age
qui affiche les animaux qui ont plus de 22 ans - Créez une procédure stockée
get_animals_by_given_age
qui affiche les animaux qui ont plus de l’âge passé en paramètre
Proposez aussi le code pour appeler ces procédures.
Solutions
-- 1. Créez une procédure stockée `get_animals` qui affiche tous les animaux du zoo
DELIMITER //CREATE PROCEDURE get_animals()BEGIN SELECT * FROM animal;END //DELIMITER ;
-- 2. Créez une procédure stockée `get_animals_by_age` qui affiche les animaux qui ont plus de 22 ans
DELIMITER //CREATE PROCEDURE get_animals_by_age()BEGIN SELECT * FROM animal WHERE date_naissance < (CURDATE() - INTERVAL 22 YEAR);END //DELIMITER ;
-- 3. Créez une procédure stockée `get_animals_by_given_age` qui affiche les animaux qui ont plus de l'âge passé en paramètre
DELIMITER //CREATE PROCEDURE get_animals_by_given_age(IN age INT)BEGIN SELECT * FROM animal WHERE date_naissance < (CURDATE() - INTERVAL age YEAR);END //DELIMITER ;
-- Proposez aussi le code pour appeler ces procédures.
-- Appel de la procédure `get_animals`CALL get_animals();
-- Appel de la procédure `get_animals_by_age`CALL get_animals_by_age();
-- Appel de la procédure `get_animals_by_given_age`CALL get_animals_by_given_age(20);
Exercice 5 : Triggers
- Un trigger qui annule l’insertion d’un animal si la date de naissance est supérieure à la date actuelle
- Un trigger qui diminue la date de naissance d’un animal de 1 jour lorsque un repas est ajouté pour la zone à laquelle il appartient
Proposez aussi des requêtes pour tester ces triggers.
Solutions
-- 1. Un trigger qui annule l'insertion d'un animal si la date de naissance est supérieure à la date actuelle
DELIMITER //CREATE TRIGGER annuler_insertion_animalBEFORE INSERT ON animalFOR EACH ROWBEGIN IF NEW.date_naissance > CURDATE() THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Impossible d''ajouter un animal né dans le futur'; END IF;END;//DELIMITER ;
-- requête pour tester le triggerINSERT INTO animal (nom, date_arrivee, date_naissance, numero, espece_id, zone_id) VALUES ('Toto', CURRENT_DATE, CURRENT_DATE + INTERVAL 1 DAY, 1, 17, 1);
-- 2. Un trigger qui diminue la date de naissance d'un animal de 1 jour lorsque un repas est ajouté pour la zone à laquelle il appartient
DELIMITER //CREATE TRIGGER diminuer_date_naissanceAFTER INSERT ON repasFOR EACH ROWBEGIN UPDATE animal SET date_naissance = date_naissance - INTERVAL 1 DAY WHERE zone_id = NEW.zone_id;END;//DELIMITER ;
-- requête pour tester le trigger
-- Selection des animaux de la zone 1SELECT * FROM animal WHERE zone_id = 1;
-- insertion d'un repas pour la zone 1 à une date aléatoireINSERT INTO repas (date_repas, quantite, responsable_id, aliment_id, zone_id) VALUES (CURRENT_DATE - INTERVAL FLOOR(RAND() * 14) DAY, 100, 1, 1, 1);
-- Selection des animaux de la zone 1SELECT * FROM animal WHERE zone_id = 1;
Exercice 6 : Transactions
- Créez une transaction qui ajoute un nouvel animal et un repas pour ce dernier
- Créez une transaction qui ajoute un nouvel animal et un repas pour ce dernier, mais qui échoue lors de l’ajout du repas
- Créez une transaction qui ajoute un nouvel animal, puis un autre, puis qui annule l’ajout du second animal, puis qui ajoute un troisième animal
Solutions
-- 1. Créez une transaction qui ajoute un nouvel animal et un repas pour ce dernier
START TRANSACTION;
-- Ajout d'un nouvel animalINSERT INTO animal (nom, date_arrivee, date_naissance, numero, espece_id, zone_id) VALUES ('Toto', CURRENT_DATE, CURRENT_DATE - INTERVAL 1 DAY, 1, 17, 1);
-- Ajout d'un repas pour l'animalINSERT INTO repas (date_repas, quantite, responsable_id, aliment_id, zone_id) VALUES (CURRENT_DATE - INTERVAL FLOOR(RAND() * 14) DAY, 100, 1, 1, 1);
COMMIT;
-- 2. Créez une transaction qui ajoute un nouvel animal et un repas pour ce dernier, mais qui échoue lors de l'ajout du repas
START TRANSACTION;
-- Ajout d'un nouvel animalINSERT INTO animal (nom, date_arrivee, date_naissance, numero, espece_id, zone_id) VALUES ('Toto', CURRENT_DATE, CURRENT_DATE - INTERVAL 1 DAY, 1, 17, 1);
-- Ajout d'un repas pour l'animalINSERT INTO repas (date_repas, quantite, responsable_id, aliment_id, zone_id) VALUES (CURRENT_DATE - INTERVAL FLOOR(RAND() * 14) DAY, 100, 1, 1, 1);
ROLLBACK;
-- 3. Créez une transaction qui ajoute un nouvel animal, puis un autre, puis qui annule l'ajout du second animal, puis qui ajoute un troisième animal
START TRANSACTION;
-- Ajout d'un nouvel animalINSERT INTO animal (nom, date_arrivee, date_naissance, numero, espece_id, zone_id) VALUES ('Toto', CURRENT_DATE, CURRENT_DATE - INTERVAL 1 DAY, 1, 17, 1);
SAVEPOINT ajout_animal_1;
-- Ajout d'un autre animalINSERT INTO animal (nom, date_arrivee, date_naissance, numero, espece_id, zone_id) VALUES ('Titi', CURRENT_DATE, CURRENT_DATE - INTERVAL 1 DAY, 2, 17, 1);
-- Annulation de l'ajout du second animalROLLBACK TO ajout_animal_1;
-- Ajout d'un autre animal
INSERT INTO animal (nom, date_arrivee, date_naissance, numero, espece_id, zone_id) VALUES ('Tutu', CURRENT_DATE, CURRENT_DATE - INTERVAL 1 DAY, 3, 17, 1);
COMMIT;
Exercice 7 : Verrous
- Vérouillez les tables
animal
etespece
en lecture, puis essayez d’insérer un nouvel animal depuis un autre terminal - Vérouillez la table
animal
etespece
en écriture, puis essayez de sélectionner tous les animaux depuis un autre terminal
Rédigez des requêtes pour tester ces verrous.
Solutions
-- 1. Vérouillez les tables `animal` et `espece` en lecture
UNLOCK TABLES;LOCK TABLES animal READ, espece READ;
-- requête à executer depuis une autre session, par exemple avec l'utilisateur `root`SELECT * FROM animal;INSERT INTO animal (nom, date_arrivee, date_naissance, numero, espece_id, zone_id) VALUES ('Toto', CURRENT_DATE, CURRENT_DATE - INTERVAL 1 DAY, 1, 17, 1); -- devrait être bloqué tant que les tables sont verrouillées
-- 2. Vérouillez la table `animal` en écriture
LOCK TABLES animal WRITE, espece READ;
-- requête à executer depuis une autre session, par exemple avec l'utilisateur `root`SELECT * FROM animal, espece;INSERT INTO animal (nom, date_arrivee, date_naissance, numero, espece_id, zone_id) VALUES ('Toto', CURRENT_DATE, CURRENT_DATE - INTERVAL 1 DAY, 1, 17, 1); -- devrait être bloqué tant que les tables sont verrouillées
UNLOCK TABLES;