Table des matières
Version : 2022.01
Dernière mise-à-jour : 2022/11/10 07:14
SER803 - Procédures, Fonctions, Déclencheurs, Vues et le Planificateur d'Evénements
Contenu du Module
- SER803 - Procédures, Fonctions, Déclencheurs, Vues et le Planificateur d'Evénements
- Contenu du Module
- Routines Stockées
- Procédures stockées
- Fonctions Stockées
- Déclencheurs
- Vues
- Planificateur d'Evénements
Routines Stockées
Procédures stockées
Les procédures stockées et les fonctions sont créées avec les commandes CREATE PROCEDURE et CREATE FUNCTION. Une procédure est appelée avec la commande CALL et peut appeler une autre routine stockée. Une routine est une procédure stockée ou une fonction.
Une routine hérite de la base de données par défaut de l'utilisateur appelant, et donc, il est recommandé de commencer les routines avec la commande USE dbname, ou de spécifier explicitement les tables et les bases de données qui sont utilisées : i.e. base.table.
Pour illustrer les procédures stockées, vous allez travailler sur une base de données conçue pour suivre des rencontres et résultats d'un ligue d'équipes de football. Commencez par créer la base ligue1 et les deux tables equipe et rencontre:
[root@centos8 ~]# mysql -uroot -p Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 8 Server version: 10.3.28-MariaDB MariaDB Server Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> CREATE DATABASE ligue1; Query OK, 1 row affected (0.000 sec) MariaDB [(none)]>
Utilisez les requêtes suivantes pour créer les tables equipe et rencontre :
CREATE TABLE ligue1.equipe ( id_equipe int primary key auto_increment, nom varchar(50) not null, stade varchar(50) not null, ville varchar(30) not null, points int not null default 0, buts int not null default 0 ) ENGINE=MyISAM;
CREATE TABLE ligue1.rencontre ( id_domicile int, id_visiteurs int, date_match DATETIME, score_domicile tinyint, score_visiteurs tinyint, arbitre varchar(80), primary key (id_domicile, id_visiteurs, date_match) ) ENGINE=MyISAM;
Vous obtiendrez :
MariaDB [(none)]> CREATE TABLE ligue1.equipe ( -> id_equipe int primary key auto_increment, -> nom varchar(50) not null, -> stade varchar(50) not null, -> ville varchar(30) not null, -> points int not null default 0, -> buts int not null default 0 -> ) ENGINE=MyISAM; Query OK, 0 rows affected (0.052 sec) MariaDB [(none)]> CREATE TABLE ligue1.rencontre ( -> id_domicile int, -> id_visiteurs int, -> date_match DATETIME, -> score_domicile tinyint, -> score_visiteurs tinyint, -> arbitre varchar(80), -> primary key (id_domicile, id_visiteurs, date_match) -> ) ENGINE=MyISAM; Query OK, 0 rows affected (0.038 sec) MariaDB [(none)]>
Sélectionnez la base ligue1:
MariaDB [(none)]> USE ligue1; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed MariaDB [ligue1]>
Ensuite créez la première procédure dans la base ligue1:
DELIMITER // CREATE PROCEDURE ligue1.INIT_EQUIPE (nom_eq varchar(50), stade_eq varchar(50), ville_eq varchar(30)) BEGIN INSERT INTO equipe (nom, stade, ville) VALUES (nom_eq, stade_eq, ville_eq); END// DELIMITER ;
Cette procédure a pour but l'insertion d'une nouvelle équipe, le stade et la ville. Vous obtiendrez un résultat similaire à celui-ci:
MariaDB [ligue1]> DELIMITER // MariaDB [ligue1]> CREATE PROCEDURE ligue1.INIT_EQUIPE (nom_eq varchar(50), stade_eq varchar(50), ville_eq varchar(30)) -> BEGIN -> INSERT INTO equipe (nom, stade, ville) VALUES (nom_eq, stade_eq, ville_eq); -> END// Query OK, 0 rows affected (0.016 sec) MariaDB [ligue1]> DELIMITER ; MariaDB [ligue1]>
Appelez la procédure pour saisir trois équipes:
MariaDB [ligue1]> CALL ligue1.INIT_EQUIPE('FC Mandriva', 'Parc des Princes', 'Paris'); Query OK, 1 row affected (0.000 sec) MariaDB [ligue1]> CALL ligue1.INIT_EQUIPE('Debian AC', 'Yankee Stadium', 'New York'); Query OK, 1 row affected (0.000 sec) MariaDB [ligue1]> CALL ligue1.INIT_EQUIPE('Vista FC', 'Qwest Field', 'Redmond'); Query OK, 1 row affected (0.000 sec) MariaDB [ligue1]>
Visualisez les entrées de la table equipe:
MariaDB [ligue1]> SELECT * FROM ligue1.equipe; +-----------+-------------+------------------+----------+--------+------+ | id_equipe | nom | stade | ville | points | buts | +-----------+-------------+------------------+----------+--------+------+ | 1 | FC Mandriva | Parc des Princes | Paris | 0 | 0 | | 2 | Debian AC | Yankee Stadium | New York | 0 | 0 | | 3 | Vista FC | Qwest Field | Redmond | 0 | 0 | +-----------+-------------+------------------+----------+--------+------+ 3 rows in set (0.000 sec) MariaDB [ligue1]>
Créez une deuxième procédure pour initialiser les rencontres:
DELIMITER // CREATE PROCEDURE ligue1.SAISIR_RENCONTRE (id_dom INTEGER, id_vis INTEGER, date_m DATETIME, arbitre_m VARCHAR(80)) BEGIN INSERT INTO rencontre (id_domicile, id_visiteurs, date_match, arbitre) VALUES (id_dom, id_vis, date_m, arbitre_m); END// DELIMITER ;
Cette procédure crée un rencontre entre deux équipes à une date précise et avec un arbitre précis. Vous obtiendrez un résultat similaire à celui-ci:
MariaDB [ligue1]> DELIMITER // MariaDB [ligue1]> CREATE PROCEDURE ligue1.SAISIR_RENCONTRE (id_dom INTEGER, id_vis INTEGER, date_m DATETIME, arbitre_m VARCHAR(80)) -> BEGIN -> INSERT INTO rencontre (id_domicile, id_visiteurs, date_match, arbitre) -> VALUES (id_dom, id_vis, date_m, arbitre_m); -> END// Query OK, 0 rows affected (0.043 sec) MariaDB [ligue1]> DELIMITER ; MariaDB [ligue1]>
Appelez la procédure pour créer trois rencontres:
MariaDB [ligue1]> CALL ligue1.SAISIR_RENCONTRE(1, 2, '2016-12-25', 'Paul Unix'); Query OK, 1 row affected (0.000 sec) MariaDB [ligue1]> CALL ligue1.SAISIR_RENCONTRE(2, 3, '2016-12-26', 'Joseph Bash'); Query OK, 1 row affected (0.000 sec) MariaDB [ligue1]> CALL ligue1.SAISIR_RENCONTRE(3, 4, '2016-12-27', 'Jean Fenêtre'); Query OK, 1 row affected (0.000 sec) MariaDB [ligue1]>
Visualisez les entrées de la table rencontre:
MariaDB [ligue1]> SELECT * FROM ligue1.rencontre; +-------------+--------------+---------------------+----------------+-----------------+---------------+ | id_domicile | id_visiteurs | date_match | score_domicile | score_visiteurs | arbitre | +-------------+--------------+---------------------+----------------+-----------------+---------------+ | 1 | 2 | 2016-12-25 00:00:00 | NULL | NULL | Paul Unix | | 2 | 3 | 2016-12-26 00:00:00 | NULL | NULL | Joseph Bash | | 3 | 4 | 2016-12-27 00:00:00 | NULL | NULL | Jean Fenêtre | +-------------+--------------+---------------------+----------------+-----------------+---------------+ 3 rows in set (0.000 sec) MariaDB [ligue1]>
Les matchs ayant eu lieu, il faut maintenant mettre à jour cette table. Créez une procédure pour la mise à jour des résultats:
DELIMITER // CREATE PROCEDURE `ligue1`.`SAISIR_RESULTAT`(id_dom INTEGER, id_vis INTEGER, score_dom TINYINT(4), score_vis TINYINT(4)) BEGIN UPDATE ligue1.rencontre SET score_domicile = score_dom, score_visiteurs = score_vis WHERE id_domicile=id_dom AND id_visiteurs=id_vis; IF score_dom = score_vis THEN UPDATE equipe SET points = points+1 WHERE id_equipe=id_dom OR id_equipe=id_vis; ELSEIF score_dom > score_vis THEN UPDATE equipe SET points = points+3 WHERE id_equipe = id_dom; ELSE UPDATE equipe SET points = points+3 WHERE id_equipe = id_vis; END IF; END// DELIMITER ;
Vous obtiendrez un résultat similaire à celui-ci:
MariaDB [ligue1]> DELIMITER // MariaDB [ligue1]> CREATE PROCEDURE `ligue1`.`SAISIR_RESULTAT`(id_dom INTEGER, id_vis INTEGER, score_dom TINYINT(4), score_vis TINYINT(4)) -> BEGIN -> UPDATE ligue1.rencontre -> SET score_domicile = score_dom, score_visiteurs = score_vis -> WHERE id_domicile=id_dom AND id_visiteurs=id_vis; -> IF score_dom = score_vis THEN -> UPDATE equipe SET points = points+1 -> WHERE id_equipe=id_dom OR id_equipe=id_vis; -> ELSEIF score_dom > score_vis THEN -> UPDATE equipe SET points = points+3 WHERE id_equipe = id_dom; -> ELSE UPDATE equipe SET points = points+3 WHERE id_equipe = id_vis; -> END IF; -> END// Query OK, 0 rows affected (0.034 sec) MariaDB [ligue1]> DELIMITER ; MariaDB [ligue1]>
Appelez la procédure pour les trois matchs:
MariaDB [ligue1]> CALL ligue1.SAISIR_RESULTAT(1, 2, 2, 1); Query OK, 2 rows affected (0.001 sec) MariaDB [ligue1]> CALL ligue1.SAISIR_RESULTAT(2, 3, 1, 3); Query OK, 2 rows affected (0.000 sec) MariaDB [ligue1]> CALL ligue1.SAISIR_RESULTAT(3, 4, 4, 2); Query OK, 2 rows affected (0.000 sec) MariaDB [ligue1]>
Visualisez les entrées de la table rencontre:
MariaDB [ligue1]> SELECT * FROM ligue1.rencontre; +-------------+--------------+---------------------+----------------+-----------------+---------------+ | id_domicile | id_visiteurs | date_match | score_domicile | score_visiteurs | arbitre | +-------------+--------------+---------------------+----------------+-----------------+---------------+ | 1 | 2 | 2016-12-25 00:00:00 | 2 | 1 | Paul Unix | | 2 | 3 | 2016-12-26 00:00:00 | 1 | 3 | Joseph Bash | | 3 | 4 | 2016-12-27 00:00:00 | 4 | 2 | Jean Fenêtre | +-------------+--------------+---------------------+----------------+-----------------+---------------+ 3 rows in set (0.000 sec) MariaDB [ligue1]>
Visualisez la table ligue1.equipe et vérifiez que les buts et les points ont été mis à jour :
MariaDB [ligue1]> SELECT * FROM equipe ; +-----------+-------------+------------------+----------+--------+------+ | id_equipe | nom | stade | ville | points | buts | +-----------+-------------+------------------+----------+--------+------+ | 1 | FC Mandriva | Parc des Princes | Paris | 3 | 0 | | 2 | Debian AC | Yankee Stadium | New York | 0 | 0 | | 3 | Vista FC | Qwest Field | Redmond | 6 | 0 | +-----------+-------------+------------------+----------+--------+------+ 3 rows in set (0.000 sec) MariaDB [ligue1]>
La nouvelle saison arrivée, il serait utile d'avoir une procédure qui vous crée les rencontres automatiquement. Créez donc une procédure pour initier les rencontres:
DELIMITER // CREATE PROCEDURE `ligue1`.`INIT_RENCONTRES`() BEGIN DECLARE fini INT default 0; DECLARE domicile, visiteur INT; DECLARE cur_domicile CURSOR FOR SELECT id_equipe FROM equipe; DECLARE cur_visiteur CURSOR FOR SELECT id_equipe FROM equipe; DECLARE CONTINUE HANDLER FOR NOT FOUND SET fini = 1; OPEN cur_domicile; WHILE fini <> 1 DO FETCH cur_domicile INTO domicile; IF fini=0 THEN OPEN cur_visiteur; WHILE fini <> 1 DO FETCH cur_visiteur INTO visiteur; IF domicile <> visiteur AND fini <> 1 THEN INSERT IGNORE INTO rencontre (id_domicile, id_visiteurs) VALUES (domicile, visiteur); END IF; END WHILE; CLOSE cur_visiteur; SET fini=0; END IF; END WHILE; CLOSE cur_domicile; END// DELIMITER ;
Vous obtiendrez un résultat similaire à celui-ci:
MariaDB [ligue1]> DELIMITER // MariaDB [ligue1]> CREATE PROCEDURE `ligue1`.`INIT_RENCONTRES`() -> BEGIN -> DECLARE fini INT default 0; -> DECLARE domicile, visiteur INT; -> DECLARE cur_domicile CURSOR FOR SELECT id_equipe FROM equipe; -> DECLARE cur_visiteur CURSOR FOR SELECT id_equipe FROM equipe; -> DECLARE CONTINUE HANDLER FOR NOT FOUND SET fini = 1; -> OPEN cur_domicile; -> WHILE fini <> 1 DO -> FETCH cur_domicile INTO domicile; -> IF fini=0 THEN -> OPEN cur_visiteur; -> WHILE fini <> 1 DO -> FETCH cur_visiteur INTO visiteur; -> IF domicile <> visiteur AND fini <> 1 THEN -> INSERT IGNORE INTO rencontre (id_domicile, id_visiteurs) VALUES (domicile, visiteur); -> END IF; -> END WHILE; -> CLOSE cur_visiteur; -> SET fini=0; -> END IF; -> END WHILE; -> CLOSE cur_domicile; -> END// Query OK, 0 rows affected (0.149 sec) MariaDB [ligue1]> DELIMITER ;
Un curseur est un objet permettant de parcourir d'une manière séquentielle le jeu de résultats retourné par une requête SQL. Dans notre cas, nous avons besoin de créer deux curseurs cur_domicile et cur_visiteur portant sur la même requête SELECT id_equipe FROM equipe. Le parcours du deuxième curseur est placé à l'intérieur du premier pour passer en revue toutes les combinaisons de couples (equipe1, equipe2). De cette façon, pour chaque équipe domicile on parcourt toutes les équipes visiteuses qui vont jouer contre elle (c'est à dire toutes sauf elle-même) et on insère un nouveau match à chaque fois.
Le curseur est ouvert via l'ordre OPEN et fermé avec CLOSE. La syntaxe d'itération sur un curseur repose sur une simple boucle WHILE dans laquelle on fait avancer le curseur avec FETCH, et sur un HANDLER.
Un HANDLER sert à déterminer ce qui se passe lorsque le SQLSTATE NOT FOUND est atteint, autrement dit quand le curseur est au bout du jeu de résultats. En général on sort de la boucle WHILE.
Supprimez maintenant les enregistrements de la saison précédente se trouvant dans la table ligue1.rencontres :
MariaDB [ligue1]> DELETE FROM ligue1.rencontre WHERE id_domicile IS NOT NULL; Query OK, 3 rows affected (0.000 sec) MariaDB [ligue1]>
Appelez la procédure:
MariaDB [ligue1]> CALL ligue1.INIT_RENCONTRES(); Query OK, 0 rows affected, 1 warning (0.00 sec) MariaDB [ligue1]>
Visualisez les entrées de la table rencontre:
MariaDB [ligue1]> SELECT * FROM ligue1.rencontre; +-------------+--------------+---------------------+----------------+-----------------+---------+ | id_domicile | id_visiteurs | date_match | score_domicile | score_visiteurs | arbitre | +-------------+--------------+---------------------+----------------+-----------------+---------+ | 2 | 3 | 0000-00-00 00:00:00 | NULL | NULL | NULL | | 2 | 1 | 0000-00-00 00:00:00 | NULL | NULL | NULL | | 1 | 3 | 0000-00-00 00:00:00 | NULL | NULL | NULL | | 1 | 2 | 0000-00-00 00:00:00 | NULL | NULL | NULL | | 3 | 1 | 0000-00-00 00:00:00 | NULL | NULL | NULL | | 3 | 2 | 0000-00-00 00:00:00 | NULL | NULL | NULL | +-------------+--------------+---------------------+----------------+-----------------+---------+ 6 rows in set (0.000 sec) MariaDB [ligue1]>
Réinitialisez la table ligue1.equipe :
MariaDB [ligue1]> UPDATE ligue1.equipe SET points=0, buts=0; Query OK, 2 rows affected (0.000 sec) Rows matched: 3 Changed: 2 Warnings: 0 MariaDB [ligue1]>
Visualisez les entrées de la table equipe :
MariaDB [ligue1]> SELECT * FROM ligue1.equipe; +-----------+-------------+------------------+----------+--------+------+ | id_equipe | nom | stade | ville | points | buts | +-----------+-------------+------------------+----------+--------+------+ | 1 | FC Mandriva | Parc des Princes | Paris | 0 | 0 | | 2 | Debian AC | Yankee Stadium | New York | 0 | 0 | | 3 | Vista FC | Qwest Field | Redmond | 0 | 0 | +-----------+-------------+------------------+----------+--------+------+ 3 rows in set (0.000 sec) MariaDB [ligue1]>
Le code d'une procédure est stocké dans la table interne INFORMATION_SCHEMA.ROUTINES. Pour visualiser les procédures créées, il convient d'utiliser la commande suivante :
MariaDB [ligue1]> SELECT * FROM information_schema.routines WHERE ROUTINE_TYPE='PROCEDURE'\G *************************** 1. row *************************** SPECIFIC_NAME: INIT_EQUIPE ROUTINE_CATALOG: def ROUTINE_SCHEMA: ligue1 ROUTINE_NAME: INIT_EQUIPE ROUTINE_TYPE: PROCEDURE DATA_TYPE: CHARACTER_MAXIMUM_LENGTH: NULL CHARACTER_OCTET_LENGTH: NULL NUMERIC_PRECISION: NULL NUMERIC_SCALE: NULL DATETIME_PRECISION: NULL CHARACTER_SET_NAME: NULL COLLATION_NAME: NULL DTD_IDENTIFIER: NULL ROUTINE_BODY: SQL ROUTINE_DEFINITION: BEGIN INSERT INTO equipe (nom, stade, ville) VALUES (nom_eq, stade_eq, ville_eq); END EXTERNAL_NAME: NULL EXTERNAL_LANGUAGE: NULL PARAMETER_STYLE: SQL IS_DETERMINISTIC: NO SQL_DATA_ACCESS: CONTAINS SQL SQL_PATH: NULL SECURITY_TYPE: DEFINER CREATED: 2022-11-08 05:01:26 LAST_ALTERED: 2022-11-08 05:01:26 SQL_MODE: STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION ROUTINE_COMMENT: DEFINER: root@localhost CHARACTER_SET_CLIENT: utf8 COLLATION_CONNECTION: utf8_general_ci DATABASE_COLLATION: latin1_swedish_ci *************************** 2. row *************************** SPECIFIC_NAME: INIT_RENCONTRES ROUTINE_CATALOG: def ROUTINE_SCHEMA: ligue1 ROUTINE_NAME: INIT_RENCONTRES ROUTINE_TYPE: PROCEDURE DATA_TYPE: CHARACTER_MAXIMUM_LENGTH: NULL CHARACTER_OCTET_LENGTH: NULL NUMERIC_PRECISION: NULL NUMERIC_SCALE: NULL DATETIME_PRECISION: NULL CHARACTER_SET_NAME: NULL COLLATION_NAME: NULL DTD_IDENTIFIER: NULL ROUTINE_BODY: SQL ROUTINE_DEFINITION: BEGIN DECLARE fini INT default 0; DECLARE domicile, visiteur INT; DECLARE cur_domicile CURSOR FOR SELECT id_equipe FROM equipe; DECLARE cur_visiteur CURSOR FOR SELECT id_equipe FROM equipe; DECLARE CONTINUE HANDLER FOR NOT FOUND SET fini = 1; OPEN cur_domicile; WHILE fini <> 1 DO FETCH cur_domicile INTO domicile; IF fini=0 THEN OPEN cur_visiteur; WHILE fini <> 1 DO FETCH cur_visiteur INTO visiteur; IF domicile <> visiteur AND fini <> 1 THEN INSERT IGNORE INTO rencontre (id_domicile, id_visiteurs) VALUES (domicile, visiteur); END IF; END WHILE; CLOSE cur_visiteur; SET fini=0; END IF; END WHILE; CLOSE cur_domicile; END EXTERNAL_NAME: NULL EXTERNAL_LANGUAGE: NULL PARAMETER_STYLE: SQL IS_DETERMINISTIC: NO SQL_DATA_ACCESS: CONTAINS SQL SQL_PATH: NULL SECURITY_TYPE: DEFINER CREATED: 2022-11-08 11:52:13 LAST_ALTERED: 2022-11-08 11:52:13 SQL_MODE: STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION ROUTINE_COMMENT: DEFINER: root@localhost CHARACTER_SET_CLIENT: utf8 COLLATION_CONNECTION: utf8_general_ci DATABASE_COLLATION: latin1_swedish_ci *************************** 3. row *************************** SPECIFIC_NAME: SAISIR_RENCONTRE ROUTINE_CATALOG: def ROUTINE_SCHEMA: ligue1 ROUTINE_NAME: SAISIR_RENCONTRE ROUTINE_TYPE: PROCEDURE DATA_TYPE: CHARACTER_MAXIMUM_LENGTH: NULL CHARACTER_OCTET_LENGTH: NULL NUMERIC_PRECISION: NULL NUMERIC_SCALE: NULL DATETIME_PRECISION: NULL CHARACTER_SET_NAME: NULL COLLATION_NAME: NULL DTD_IDENTIFIER: NULL ROUTINE_BODY: SQL ROUTINE_DEFINITION: BEGIN INSERT INTO rencontre (id_domicile, id_visiteurs, date_match, arbitre) VALUES (id_dom, id_vis, date_m, arbitre_m); END EXTERNAL_NAME: NULL EXTERNAL_LANGUAGE: NULL PARAMETER_STYLE: SQL IS_DETERMINISTIC: NO SQL_DATA_ACCESS: CONTAINS SQL SQL_PATH: NULL SECURITY_TYPE: DEFINER CREATED: 2022-11-08 05:03:39 LAST_ALTERED: 2022-11-08 05:03:39 SQL_MODE: STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION ROUTINE_COMMENT: DEFINER: root@localhost CHARACTER_SET_CLIENT: utf8 COLLATION_CONNECTION: utf8_general_ci DATABASE_COLLATION: latin1_swedish_ci *************************** 4. row *************************** SPECIFIC_NAME: SAISIR_RESULTAT ROUTINE_CATALOG: def ROUTINE_SCHEMA: ligue1 ROUTINE_NAME: SAISIR_RESULTAT ROUTINE_TYPE: PROCEDURE DATA_TYPE: CHARACTER_MAXIMUM_LENGTH: NULL CHARACTER_OCTET_LENGTH: NULL NUMERIC_PRECISION: NULL NUMERIC_SCALE: NULL DATETIME_PRECISION: NULL CHARACTER_SET_NAME: NULL COLLATION_NAME: NULL DTD_IDENTIFIER: NULL ROUTINE_BODY: SQL ROUTINE_DEFINITION: BEGIN UPDATE ligue1.rencontre SET score_domicile = score_dom, score_visiteurs = score_vis WHERE id_domicile=id_dom AND id_visiteurs=id_vis; IF score_dom = score_vis THEN UPDATE equipe SET points = points+1 WHERE id_equipe=id_dom OR id_equipe=id_vis; ELSEIF score_dom > score_vis THEN UPDATE equipe SET points = points+3 WHERE id_equipe = id_dom; ELSE UPDATE equipe SET points = points+3 WHERE id_equipe = id_vis; END IF; END EXTERNAL_NAME: NULL EXTERNAL_LANGUAGE: NULL PARAMETER_STYLE: SQL IS_DETERMINISTIC: NO SQL_DATA_ACCESS: CONTAINS SQL SQL_PATH: NULL SECURITY_TYPE: DEFINER CREATED: 2022-11-08 05:06:32 LAST_ALTERED: 2022-11-08 05:06:32 SQL_MODE: STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION ROUTINE_COMMENT: DEFINER: root@localhost CHARACTER_SET_CLIENT: utf8 COLLATION_CONNECTION: utf8_general_ci DATABASE_COLLATION: latin1_swedish_ci *************************** 5. row *************************** SPECIFIC_NAME: AddGeometryColumn ROUTINE_CATALOG: def ROUTINE_SCHEMA: mysql ROUTINE_NAME: AddGeometryColumn ROUTINE_TYPE: PROCEDURE DATA_TYPE: CHARACTER_MAXIMUM_LENGTH: NULL CHARACTER_OCTET_LENGTH: NULL NUMERIC_PRECISION: NULL NUMERIC_SCALE: NULL DATETIME_PRECISION: NULL CHARACTER_SET_NAME: NULL COLLATION_NAME: NULL DTD_IDENTIFIER: NULL ROUTINE_BODY: SQL ROUTINE_DEFINITION: begin set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' ADD ', geometry_column,' GEOMETRY REF_SYSTEM_ID=', t_srid); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end EXTERNAL_NAME: NULL EXTERNAL_LANGUAGE: NULL PARAMETER_STYLE: SQL IS_DETERMINISTIC: NO SQL_DATA_ACCESS: CONTAINS SQL SQL_PATH: NULL SECURITY_TYPE: INVOKER CREATED: 2022-11-07 06:02:06 LAST_ALTERED: 2022-11-07 06:02:06 SQL_MODE: ROUTINE_COMMENT: DEFINER: root@localhost CHARACTER_SET_CLIENT: utf8 COLLATION_CONNECTION: utf8_general_ci DATABASE_COLLATION: latin1_swedish_ci *************************** 6. row *************************** SPECIFIC_NAME: DropGeometryColumn ROUTINE_CATALOG: def ROUTINE_SCHEMA: mysql ROUTINE_NAME: DropGeometryColumn ROUTINE_TYPE: PROCEDURE DATA_TYPE: CHARACTER_MAXIMUM_LENGTH: NULL CHARACTER_OCTET_LENGTH: NULL NUMERIC_PRECISION: NULL NUMERIC_SCALE: NULL DATETIME_PRECISION: NULL CHARACTER_SET_NAME: NULL COLLATION_NAME: NULL DTD_IDENTIFIER: NULL ROUTINE_BODY: SQL ROUTINE_DEFINITION: begin set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' DROP ', geometry_column); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end EXTERNAL_NAME: NULL EXTERNAL_LANGUAGE: NULL PARAMETER_STYLE: SQL IS_DETERMINISTIC: NO SQL_DATA_ACCESS: CONTAINS SQL SQL_PATH: NULL SECURITY_TYPE: INVOKER CREATED: 2022-11-07 06:02:06 LAST_ALTERED: 2022-11-07 06:02:06 SQL_MODE: ROUTINE_COMMENT: DEFINER: root@localhost CHARACTER_SET_CLIENT: utf8 COLLATION_CONNECTION: utf8_general_ci DATABASE_COLLATION: latin1_swedish_ci 6 rows in set (0.001 sec) MariaDB [ligue1]>
Fonctions Stockées
Vous allez maintenant créer une Fonction Stockée que vous utiliserez ultérieurement. La différence entre une procédure stockée et une fonction stockée est que cette dernière n'a pas besoin d'être appelée en utilisant la commande CALL. La fonction est appelée à partir d'une commande SQL. Cette fonction va vous identifier les équipes relégables en fin de saison.
Créez donc la fonction intégrée :
DELIMITER // CREATE FUNCTION EST_RELEGABLE(idequipe INTEGER) RETURNS TINYINT BEGIN DECLARE relegable TINYINT default 0; DECLARE id_courante INTEGER; DECLARE fini TINYINT DEFAULT 0; DECLARE cur1 CURSOR FOR SELECT id_equipe FROM equipe ORDER BY points ASC LIMIT 3; DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET fini = 1; OPEN cur1; BOUCLE: REPEAT FETCH cur1 INTO id_courante; IF idequipe=id_courante THEN SET relegable=1; LEAVE BOUCLE; END IF; UNTIL fini END REPEAT BOUCLE; CLOSE cur1; RETURN relegable; END// DELIMITER ;
Vous obtiendrez un résultat similaire à celui-ci:
MariaDB [ligue1]> DELIMITER // MariaDB [ligue1]> CREATE FUNCTION EST_RELEGABLE(idequipe INTEGER) RETURNS TINYINT -> BEGIN -> DECLARE relegable TINYINT default 0; -> DECLARE id_courante INTEGER; -> DECLARE fini TINYINT DEFAULT 0; -> DECLARE cur1 CURSOR FOR SELECT id_equipe FROM equipe ORDER BY points ASC LIMIT 3; -> DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET fini = 1; -> OPEN cur1; -> BOUCLE: REPEAT -> FETCH cur1 INTO id_courante; -> IF idequipe=id_courante THEN -> SET relegable=1; -> LEAVE BOUCLE; -> END IF; -> UNTIL fini END REPEAT BOUCLE; -> CLOSE cur1; -> RETURN relegable; -> END// Query OK, 0 rows affected (0.038 sec) MariaDB [ligue1]> DELIMITER ; MariaDB [ligue1]>
A la fin de la saison, il conviendrait de saisir la commande suivante pour identifier les équipes relégables (NE SAISISSEZ PAS LES DEUX REQUETES SUIVANTES) :
> SELECT * FROM equipe WHERE EST_RELEGABLE(id_equipe)=1; [Entrée]
Ensuite il conviendrait de les supprimer :
> DELETE FROM equipe WHERE EST_RELEGABLE(id_equipe)=1; [Entrée]
Le code d'une fonction est stocké dans la table interne INFORMATION_SCHEMA.ROUTINES. Pour visualiser les fonctions stockées, utilisez la commande suivante :
MariaDB [ligue1]> SELECT * FROM information_schema.routines WHERE ROUTINE_TYPE='FUNCTION'\G *************************** 1. row *************************** SPECIFIC_NAME: EST_RELEGABLE ROUTINE_CATALOG: def ROUTINE_SCHEMA: ligue1 ROUTINE_NAME: EST_RELEGABLE ROUTINE_TYPE: FUNCTION DATA_TYPE: tinyint CHARACTER_MAXIMUM_LENGTH: NULL CHARACTER_OCTET_LENGTH: NULL NUMERIC_PRECISION: 3 NUMERIC_SCALE: 0 DATETIME_PRECISION: NULL CHARACTER_SET_NAME: NULL COLLATION_NAME: NULL DTD_IDENTIFIER: tinyint(4) ROUTINE_BODY: SQL ROUTINE_DEFINITION: BEGIN DECLARE relegable TINYINT default 0; DECLARE id_courante INTEGER; DECLARE fini TINYINT DEFAULT 0; DECLARE cur1 CURSOR FOR SELECT id_equipe FROM equipe ORDER BY points ASC LIMIT 3; DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET fini = 1; OPEN cur1; BOUCLE: REPEAT FETCH cur1 INTO id_courante; IF idequipe=id_courante THEN SET relegable=1; LEAVE BOUCLE; END IF; UNTIL fini END REPEAT BOUCLE; CLOSE cur1; RETURN relegable; END EXTERNAL_NAME: NULL EXTERNAL_LANGUAGE: NULL PARAMETER_STYLE: SQL IS_DETERMINISTIC: NO SQL_DATA_ACCESS: CONTAINS SQL SQL_PATH: NULL SECURITY_TYPE: DEFINER CREATED: 2022-11-08 11:56:30 LAST_ALTERED: 2022-11-08 11:56:30 SQL_MODE: STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION ROUTINE_COMMENT: DEFINER: root@localhost CHARACTER_SET_CLIENT: utf8 COLLATION_CONNECTION: utf8_general_ci DATABASE_COLLATION: latin1_swedish_ci 1 row in set (0.001 sec) MariaDB [ligue1]>
Notez que vous ne pouvez pas utiliser les commandes suivantes dans des routines stockées : LOCK TABLES, UNLOCK TABLES, ALTER VIEW, LOAD DATA/TABLE, PREPARE, EXECUTE, DEALLOCATE PREPARE.
Déclencheurs
Le support des déclencheurs (triggers) est inclus dans les versions de MySQL à partir de la version 5.0.2. Un déclencheur est un objet de base de données nommé, qui est associé à une table et qui s'active lorsqu'une ACTION de type INSERT, DELETE ou UPDATE sont effectuées sur une table. Un déclencheur peut être appelé avec une POSITION. La valeur de la POSITION est BEFORE ou AFTER l'ACTION.
Créez un trigger pour convertir la ville en majuscules lors de son insertion:
DELIMITER // CREATE TRIGGER TGR_BI_EQUIPE BEFORE INSERT ON equipe FOR EACH ROW BEGIN SET new.ville = UPPER(new.ville); END// DELIMITER ;
Vous obtiendrez un résultat similaire à celui-ci:
MariaDB [ligue1]> DELIMITER // MariaDB [ligue1]> CREATE TRIGGER TGR_BI_EQUIPE BEFORE INSERT ON equipe FOR EACH ROW -> BEGIN -> SET new.ville = UPPER(new.ville); -> END// Query OK, 0 rows affected (0.055 sec) MariaDB [ligue1]> DELIMITER ; MariaDB [ligue1]>
Insérez une nouvel enregistrement:
MariaDB [ligue1]> INSERT INTO equipe (nom, stade, ville) VALUES ('Racing Club Strasbourg', 'La Meinau', 'strasbourg'); Query OK, 1 row affected (0.000 sec) MariaDB [ligue1]>
MariaDB [ligue1]> SELECT nom, stade, ville FROM equipe; +------------------------+------------------+------------+ | nom | stade | ville | +------------------------+------------------+------------+ | FC Mandriva | Parc des Princes | Paris | | Debian AC | Yankee Stadium | New York | | Vista FC | Qwest Field | Redmond | | Racing Club Strasbourg | La Meinau | STRASBOURG | +------------------------+------------------+------------+ 4 rows in set (0.000 sec) MariaDB [ligue1]>
Créez un trigger pour faire le total des buts:
DELIMITER // CREATE TRIGGER TGR_BU_RENCONTRE BEFORE UPDATE ON rencontre FOR EACH ROW BEGIN IF old.score_domicile IS NULL and new.score_domicile IS NOT NULL THEN UPDATE equipe SET buts = buts + new.score_domicile WHERE id_equipe=new.id_domicile; END IF; IF old.score_visiteurs IS NULL and new.score_visiteurs IS NOT NULL THEN UPDATE equipe SET buts = buts + new.score_visiteurs WHERE id_equipe=new.id_visiteurs; END IF; END// DELIMITER ;
Vous obtiendrez un résultat similaire à celui-ci :
MariaDB [ligue1]> DELIMITER // MariaDB [ligue1]> CREATE TRIGGER TGR_BU_RENCONTRE BEFORE UPDATE ON rencontre FOR EACH ROW -> BEGIN -> IF old.score_domicile IS NULL and new.score_domicile IS NOT NULL THEN -> UPDATE equipe SET buts = buts + new.score_domicile WHERE id_equipe=new.id_domicile; -> END IF; -> IF old.score_visiteurs IS NULL and new.score_visiteurs IS NOT NULL THEN -> UPDATE equipe SET buts = buts + new.score_visiteurs WHERE id_equipe=new.id_visiteurs; -> END IF; -> END// Query OK, 0 rows affected (0.053 sec) MariaDB [ligue1]> DELIMITER ; MariaDB [ligue1]>
Appelez la procédure pour inscrire un résultat:
MariaDB [ligue1]> CALL SAISIR_RESULTAT(1, 2, 2, 1); Query OK, 4 rows affected (0.001 sec) MariaDB [ligue1]>
Appelez la procédure une deuxième fois pour inscrire un autre résultat:
MariaDB [ligue1]> CALL SAISIR_RESULTAT(2, 1, 2, 1); Query OK, 4 rows affected (0.000 sec) MariaDB [ligue1]>
Examinez les résultats obtenus :
MariaDB [ligue1]> SELECT * FROM ligue1.equipe; +-----------+------------------------+------------------+------------+--------+------+ | id_equipe | nom | stade | ville | points | buts | +-----------+------------------------+------------------+------------+--------+------+ | 1 | FC Mandriva | Parc des Princes | Paris | 3 | 3 | | 2 | Debian AC | Yankee Stadium | New York | 3 | 3 | | 3 | Vista FC | Qwest Field | Redmond | 0 | 0 | | 4 | Racing Club Strasbourg | La Meinau | STRASBOURG | 0 | 0 | +-----------+------------------------+------------------+------------+--------+------+ 4 rows in set (0.000 sec) MariaDB [ligue1]>
L'utilisation des déclencheurs est soumise à des limites :
- Limitation à un seul trigger par table, par ACTION et par POSITION.
- Uniquement triggers FOR EACH ROW (déclencheurs niveau ligne).
- Pas de déclencheurs sur des événements système autres que des requêtes SQL,
- Les déclencheurs ne peuvent pas être mis sur les tables de la base mysql,
- Les déclencheurs ne sont pas déclenchés par les ACTIONS de clés étrangères.
Vues
Les vues, y compris les vues modifiables, sont disponibles dans les versions binaires depuis la version 5.0.1.
- Création ou modification de vues avec les commandes CREATE VIEW ou ALTER VIEW
- Destruction de vues avec DROP VIEW
- Affichage des méta-données de vues avec SHOW CREATE VIEW
Ajoutez d'abord des champs à notre table equipe pour stocker le nom des entraîneurs ainsi que leurs numéros de téléphone :
ALTER TABLE equipe ADD entraineur varchar(100) default 'inconnu', ADD tel_entraineur varchar(20) default 'inconnu';
Vous obtiendrez un résultat similaire à celui-ci :
MariaDB [ligue1]> ALTER TABLE equipe -> ADD entraineur varchar(100) default 'inconnu', -> ADD tel_entraineur varchar(20) default 'inconnu'; Query OK, 4 rows affected (0.025 sec) Records: 4 Duplicates: 0 Warnings: 0 MariaDB [ligue1]>
Mettez à jour la table:
MariaDB [ligue1]> UPDATE equipe SET entraineur='Ricardo GOMES', tel_entraineur='06-56-56-56-56' WHERE id_equipe=1; Query OK, 1 row affected (0.000 sec) Rows matched: 1 Changed: 1 Warnings: 0 MariaDB [ligue1]> UPDATE equipe SET entraineur='Gérard Houllier', tel_entraineur='06-57-57-57-57' WHERE id_equipe=2; Query OK, 1 row affected (0.000 sec) Rows matched: 1 Changed: 1 Warnings: 0 MariaDB [ligue1]>
Consultez le résultat :
MariaDB [ligue1]> SELECT * FROM ligue1.equipe; +-----------+------------------------+------------------+------------+--------+------+------------------+----------------+ | id_equipe | nom | stade | ville | points | buts | entraineur | tel_entraineur | +-----------+------------------------+------------------+------------+--------+------+------------------+----------------+ | 1 | FC Mandriva | Parc des Princes | Paris | 3 | 3 | Ricardo GOMES | 06-56-56-56-56 | | 2 | Debian AC | Yankee Stadium | New York | 3 | 3 | Gérard Houllier | 06-57-57-57-57 | | 3 | Vista FC | Qwest Field | Redmond | 0 | 0 | inconnu | inconnu | | 4 | Racing Club Strasbourg | La Meinau | STRASBOURG | 0 | 0 | inconnu | inconnu | +-----------+------------------------+------------------+------------+--------+------+------------------+----------------+ 4 rows in set (0.000 sec) MariaDB [ligue1]>
Créez une vue qui ne montre pas le numéro de téléphone:
MariaDB [ligue1]> CREATE VIEW V_EQUIPE AS SELECT id_equipe, nom, stade, ville, points, buts, entraineur FROM equipe; Query OK, 0 rows affected (0.062 sec) MariaDB [ligue1]>
Le code d'un view est stocké dans la table interne INFORMATION_SCHEMA.VIEWS :
MariaDB [ligue1]> SELECT * FROM information_schema.views\G *************************** 1. row *************************** TABLE_CATALOG: def TABLE_SCHEMA: ligue1 TABLE_NAME: V_EQUIPE VIEW_DEFINITION: select `ligue1`.`equipe`.`id_equipe` AS `id_equipe`,`ligue1`.`equipe`.`nom` AS `nom`,`ligue1`.`equipe`.`stade` AS `stade`,`ligue1`.`equipe`.`ville` AS `ville`,`ligue1`.`equipe`.`points` AS `points`,`ligue1`.`equipe`.`buts` AS `buts`,`ligue1`.`equipe`.`entraineur` AS `entraineur` from `ligue1`.`equipe` CHECK_OPTION: NONE IS_UPDATABLE: YES DEFINER: root@localhost SECURITY_TYPE: DEFINER CHARACTER_SET_CLIENT: utf8 COLLATION_CONNECTION: utf8_general_ci ALGORITHM: UNDEFINED 1 row in set (0.004 sec) MariaDB [ligue1]>
Donnez les droits sur cette vue à user1:
MariaDB [ligue1]> GRANT SELECT, INSERT, DELETE, UPDATE ON V_EQUIPE TO user1@localhost IDENTIFIED BY 'user1'; Query OK, 0 rows affected (0.000 sec) MariaDB [ligue1]>
Déconnectez-vous et reconnectez-vous en tant qu'user1:
MariaDB [ligue1]> exit Bye [root@centos8 ~]# mysql -uuser1 -p Enter password: user1 Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 10 Server version: 10.3.28-MariaDB MariaDB Server Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]>
Notez que user1 ne voit que les bases de données information_schema et ligue1 :
MariaDB [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | ligue1 | +--------------------+ 2 rows in set (0.000 sec) MariaDB [(none)]>
Changez de base de données:
MariaDB [(none)]> use ligue1; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed MariaDB [ligue1]>
Ensuite, visualisez la vue V_EQUIPE:
MariaDB [ligue1]> SELECT * FROM V_EQUIPE; +-----------+------------------------+------------------+------------+--------+------+------------------+ | id_equipe | nom | stade | ville | points | buts | entraineur | +-----------+------------------------+------------------+------------+--------+------+------------------+ | 1 | FC Mandriva | Parc des Princes | Paris | 3 | 3 | Ricardo GOMES | | 2 | Debian AC | Yankee Stadium | New York | 3 | 3 | Gérard Houllier | | 3 | Vista FC | Qwest Field | Redmond | 0 | 0 | inconnu | | 4 | Racing Club Strasbourg | La Meinau | STRASBOURG | 0 | 0 | inconnu | +-----------+------------------------+------------------+------------+--------+------+------------------+ 4 rows in set (0.000 sec) MariaDB [ligue1]>
Notez cependant qu'user1 n'a pas accès à la table equipe :
MariaDB [ligue1]> SELECT * FROM equipe; ERROR 1142 (42000): SELECT command denied to user 'user1'@'localhost' for table 'equipe' MariaDB [ligue1]>
Déconnectez-vous et reconnectez-vous en tant que root :
MariaDB [ligue1]> exit Bye [root@centos8 ~]# mysql -uroot -p Enter password: fenestros Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 11 Server version: 10.3.28-MariaDB MariaDB Server Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]>
Planificateur d'Evénements
Pour visualiser l'état du planificateur d'évènements, utilisez la requête suivante :
MariaDB [(none)]> SHOW VARIABLES LIKE 'event_scheduler'; +-----------------+-------+ | Variable_name | Value | +-----------------+-------+ | event_scheduler | OFF | +-----------------+-------+ 1 row in set (0.001 sec) MariaDB [(none)]>
Pour activer le planificateur d'évènements, modifiez la valeur de la variable event_scheduler :
MariaDB [(none)]> SET GLOBAL event_scheduler = 1; Query OK, 0 rows affected (0.000 sec) MariaDB [(none)]> SHOW VARIABLES LIKE 'event_scheduler'; +-----------------+-------+ | Variable_name | Value | +-----------------+-------+ | event_scheduler | ON | +-----------------+-------+ 1 row in set (0.001 sec) MariaDB [(none)]>
L'état du planificateur d'évènements, Waiting on empty queue peut être visualisé en saisissant la requête suivante :
MariaDB [(none)]> SHOW PROCESSLIST; +----+-----------------+-----------+------+---------+------+--------------------------+------------------+----------+ | Id | User | Host | db | Command | Time | State | Info | Progress | +----+-----------------+-----------+------+---------+------+--------------------------+------------------+----------+ | 2 | system user | | NULL | Daemon | NULL | InnoDB purge worker | NULL | 0.000 | | 1 | system user | | NULL | Daemon | NULL | InnoDB purge coordinator | NULL | 0.000 | | 3 | system user | | NULL | Daemon | NULL | InnoDB purge worker | NULL | 0.000 | | 4 | system user | | NULL | Daemon | NULL | InnoDB purge worker | NULL | 0.000 | | 5 | system user | | NULL | Daemon | NULL | InnoDB shutdown handler | NULL | 0.000 | | 12 | event_scheduler | localhost | NULL | Daemon | 193 | Waiting on empty queue | NULL | 0.000 | | 13 | root | localhost | NULL | Query | 0 | Init | SHOW PROCESSLIST | 0.000 | +----+-----------------+-----------+------+---------+------+--------------------------+------------------+----------+ 7 rows in set (0.000 sec) MariaDB [(none)]>
Copyright © 2022 Hugh Norris.