Chapitre 1610 minAvancé
Aide-mémoire : syntaxe et erreurs fréquentes
Par Josselyn C., prof de BTS SIO. Mis à jour le .
À la fin de ce chapitre, tu sauras
- retrouver vite la syntaxe de chaque programme stocké ;
- comprendre les messages d'erreur fréquents ;
- vérifier ta copie avec une liste de contrôle.
Cet aide-mémoire rassemble la syntaxe MySQL 8.4 des procédures stockées, fonctions, curseurs, gestionnaires d'erreurs, triggers et événements, les codes d'erreur que tu rencontreras le plus souvent, et une liste de contrôle à relire avant de rendre une copie ou de déployer une routine. Chaque bloc renvoie au chapitre qui l'explique.
Procédure
DELIMITER //
CREATE PROCEDURE nom_procedure(IN p_entree INT, OUT p_sortie INT, INOUT p_les_deux INT)
[SQL SECURITY { DEFINER | INVOKER }] [COMMENT '…']
BEGIN
DECLARE v_variable INT DEFAULT 0; -- variables et conditions d'abord
-- curseurs ensuite, gestionnaires enfin
SELECT COUNT(*) INTO p_sortie FROM … WHERE … = p_entree;
END //
DELIMITER ;
CALL nom_procedure(1, @sortie, @les_deux);
SELECT @sortie;
DROP PROCEDURE IF EXISTS nom_procedure;
Fonction
DELIMITER //
CREATE FUNCTION nom_fonction(p_valeur INT) RETURNS INT
DETERMINISTIC NO SQL -- ou NOT DETERMINISTIC READS SQL DATA
BEGIN
RETURN p_valeur * 2;
END //
DELIMITER ;
SELECT nom_fonction(colonne) FROM ma_table;
Une fonction : une seule valeur, ni transaction, ni jeu de résultats, ni SQL dynamique (chapitre 4).
Conditions et boucles
IF condition THEN … ELSEIF condition THEN … ELSE … END IF;
CASE variable WHEN valeur THEN … ELSE … END CASE;
WHILE condition DO … END WHILE;
REPEAT … UNTIL condition END REPEAT; -- au moins un tour
etiquette: LOOP
IF fin THEN LEAVE etiquette; END IF; -- break
IF sauter THEN ITERATE etiquette; END IF; -- continue
END LOOP etiquette;
Curseur
DECLARE v_id INT;
DECLARE v_fini BOOLEAN DEFAULT FALSE;
DECLARE c CURSOR FOR SELECT id_poste FROM poste;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_fini = TRUE;
OPEN c;
lecture: LOOP
FETCH c INTO v_id;
IF v_fini THEN LEAVE lecture; END IF;
-- traitement
END LOOP lecture;
CLOSE c;
Ordre des DECLARE : variables, curseurs, gestionnaires (chapitre 5).
Gestion des erreurs
DECLARE nom_condition CONDITION FOR 1062;
DECLARE CONTINUE HANDLER FOR 1062 SET v_doublon = TRUE; -- reprend après l'instruction
DECLARE EXIT HANDLER FOR SQLEXCEPTION -- quitte le bloc
BEGIN
GET DIAGNOSTICS CONDITION 1 v_num = MYSQL_ERRNO, v_msg = MESSAGE_TEXT;
ROLLBACK;
RESIGNAL; -- relance l'erreur d'origine
END;
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Message de 128 caractères au plus';
Priorité : numéro MySQL, puis SQLSTATE, puis SQLEXCEPTION, SQLWARNING, NOT FOUND (chapitre 6).
Procédure transactionnelle
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
START TRANSACTION;
SELECT … FOR UPDATE; -- verrouiller ce qu'on va décider
-- contrôles avec SIGNAL
-- modifications
COMMIT;
END
Une procédure qui ouvre une transaction ne s'appelle pas au milieu d'une autre (chapitre 7).
Trigger
DELIMITER //
CREATE TRIGGER trg_table_role
{ BEFORE | AFTER } { INSERT | UPDATE | DELETE } ON nom_table
FOR EACH ROW
[ { FOLLOWS | PRECEDES } autre_trigger ]
BEGIN
-- INSERT : NEW ; UPDATE : OLD et NEW ; DELETE : OLD
-- BEFORE : SET NEW.colonne = … ou SIGNAL ; AFTER : écrire dans une autre table
END //
DELIMITER ;
SHOW TRIGGERS FROM parc;
DROP TRIGGER IF EXISTS trg_table_role;
Événement
CREATE EVENT ev_nom
ON SCHEDULE EVERY 1 DAY STARTS '2026-11-09 03:00:00' -- ou AT '2026-12-01 01:00:00'
DO DELETE FROM audit_ticket WHERE modifie_le < NOW() - INTERVAL 1 YEAR;
SHOW VARIABLES LIKE 'event_scheduler'; -- ON (MySQL), OFF par défaut (MariaDB)
ALTER EVENT ev_nom DISABLE;
DROP EVENT IF EXISTS ev_nom;
Sécurité et SQL dynamique
CREATE DEFINER = 'routines_parc'@'localhost' PROCEDURE … SQL SECURITY DEFINER …
GRANT EXECUTE ON PROCEDURE parc.cloturer_ticket TO 'helpdesk'@'192.168.21.20';
SET @valeur = p_valeur; -- USING : variables de session
SET @sql = CONCAT('SELECT … WHERE colonne = ? ORDER BY ', v_colonne_liste_blanche);
PREPARE stmt FROM @sql;
EXECUTE stmt USING @valeur;
DEALLOCATE PREPARE stmt;
Les erreurs fréquentes
| Code | Message (début) | Cause habituelle |
|---|---|---|
| 1064 | You have an error in your SQL syntax | DELIMITER oublié, DECLARE mal placé, mot réservé |
| 1172 | Result consisted of more than one row | SELECT … INTO qui renvoie plusieurs lignes |
| 1305 | PROCEDURE … does not exist | Mauvaise base courante, ou routine perdue à la restauration |
| 1321 | FUNCTION … ended without RETURN | Un chemin de la fonction sans RETURN |
| 1329 | No data - zero rows fetched | FETCH sans gestionnaire NOT FOUND, SELECT … INTO sans ligne (avertissement) |
| 1337, 1338 | … declaration after cursor or handler declaration | Ordre des DECLARE |
| 1339 | Case not found for CASE statement | Instruction CASE sans ELSE |
| 1362 | Updating of NEW row is not allowed in after trigger | SET NEW.… dans un trigger AFTER |
| 1363 | There is no OLD row in on INSERT trigger | OLD dans un INSERT, NEW dans un DELETE |
| 1370 | execute command denied to user … | Droit EXECUTE manquant, à l'appelant ou au propriétaire |
| 1415 | Not allowed to return a result set from a function | SELECT sans INTO dans une fonction |
| 1418 | This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA | Caractéristique manquante, journal binaire actif |
| 1422 | Explicit or implicit commit is not allowed in stored function or trigger | COMMIT ou LDD dans une fonction ou un trigger |
| 1442 | Can't update table '…' in stored function/trigger | Le trigger modifie sa propre table |
| 1449 | The user specified as a definer ('…') does not exist | Objet orphelin |
| 1568 | Transaction characteristics can't be changed while a transaction is in progress | SET TRANSACTION dans une transaction ouverte |
| 1644 | Ton message | SIGNAL SQLSTATE '45000' : une erreur métier |
| 1648 | Data too long for condition item 'MESSAGE_TEXT' | Message de plus de 128 caractères |
La liste de contrôle
Avant de rendre une copie ou de déployer une routine, vérifie :
DELIMITER //avant,END //à la fin,DELIMITER ;après (dans le clientmysql).- Les paramètres ont le bon mode (
IN,OUT,INOUT) et un préfixe qui les distingue des colonnes (p_). - Les
DECLAREsont au début du bloc, dans l'ordre : variables, curseurs, gestionnaires. - Chaque
IFa sonEND IF;, chaque boucle sonEND …, chaqueCASEsonELSE. - Un trigger a
FOR EACH ROW, utiliseNEWetOLDselon l'événement, ne modifieNEWqu'enBEFOREet ne touche pas à sa propre table. - Les comparaisons avec une valeur qui peut être
NULLutilisentIS NULLou<=>. - Une procédure qui modifie plusieurs tables a sa transaction, un gestionnaire
ROLLBACK+RESIGNAL, et unCOMMIT. - Une fonction déclare
DETERMINISTIC,NO SQLouREADS SQL DATA, et renvoie une valeur sur chaque chemin. - Les messages de
SIGNALsont compréhensibles par un utilisateur et font moins de 128 caractères. - Aucun paramètre n'est collé dans une requête dynamique ; le propriétaire et les droits
EXECUTEsont les bons ; le script de test et le script d'annulation existent.