Commit 9683d050 authored by Fabrice Missonnier's avatar Fabrice Missonnier
Browse files

Modification fiche récap MySQL avancé

parent 4215ae38
Loading
Loading
Loading
Loading
+126 −92
Original line number Diff line number Diff line
# Bloc 2 - SGBDR Fiche 6 - SQL : Triggers et procédures stockées

## Procédures stockées
# Bloc 2 - SGBDR Fiche 6 - MySQL avancé :Transaction Triggers et procédures stockées (MySQL)

Les procédures stockées représentent des programmes constitués d'une séquence d'instruction SQL. Elles sont stockées dans la base de données, et conçues pour effectuer une tâche particulière. Elles peuvent contenir une commande ou un ensemble de commandes SQL. Les procédures sont compilées et stockées sur le serveur. Grâce à elles, l'utilisateur n'a plus besoin de soumettre toute une commande, mais il fait référence à la procédure stockée correspondante.
C'est entendu. Passons à la vitesse supérieure avec une approche plus technique, en intégrant la syntaxe rigoureuse de MySQL pour la gestion des transactions et la logique procédurale.

Elles apportent entre autres :
-    une meilleure sécurité (pas d'accès direct aux tables et pas d'erreur de commande),
-    une diminution des redondances de code,
-    une augmentation de la performance (baisse du trafic SQL sur le serveur).
Voici les deux sections enrichies avec des exemples concrets.

Les procédures stockées sont conservées sous forme **d'exécutable** en attente d'être appelées. Elles deviennent des objets de la base de données, tout comme les tables. L'application la plus simple est de rattacher des requêtes complexes à une base de données, afin que les utilisateurs n'aient pas à les taper plus d'une fois.
---

**Syntaxe générale** 
### 1. Transactions et Propriétés ACID : Le "Tout ou Rien"

```sql
CREATE Procedure [nom_procedure]   
{ @parametre1 type, @parametre 2 type } 
AS [requete]                                
```
Une **transaction** est une unité logique de traitement. Pour garantir l'intégrité, MySQL (via le moteur **InnoDB**) s'appuie sur le modèle **ACID** :

*Exemple : procédure qui permet de sélectionner une date de commande (SQL SERVER) :*  
* **A (Atomicité) :** La transaction est une unité indivisible.
* **C (Cohérence) :** On passe d'un état valide à un autre (respect des clés étrangères, types, etc.).
* **I (Isolation) :** Les opérations d'une transaction sont invisibles pour les autres tant qu'elles ne sont pas validées.
* **D (Durabilité) :** Une fois confirmées, les données sont gravées physiquement sur le disque.

**Exemple technique (Transfert bancaire) :**

```sql
CREATE PROCEDURE OrdersByDate
@StartDate datetime, @EndDate datetime
AS
	SELECT * 
	FROM COMMANDES
	WHERE date_cde BETWEEN @StartDate AND @EndDate
```
START TRANSACTION; -- Début de l'unité de travail

Ici les paramètres sont en entrée, l'utilisateur doit fournir leurs variables. Les paramètres peuvent également être en sortie (on renvoie une valeur, on utilise alors le mot clé OUTPUT), ou même d'entrée et sortie. On indique les paramètres en précisant leur nom avec le symbole @. Le mot clé AS précise le début du corps de la procédure stockée.
-- Étape 1 : Débit
UPDATE comptes SET solde = solde - 100 WHERE id_client = 1;

Exécution de la procédure : 
-- Étape 2 : Crédit
UPDATE comptes SET solde = solde + 100 WHERE id_client = 2;

```sql
DECLARE @StartDate datetime
DECLARE @EndDate datetime
-- Vérification logique (ex: solde négatif non autorisé)
IF (solde_insatisfaisant) THEN
    ROLLBACK; -- Annulation totale : le client 1 récupère ses 100€
	ELSE
	    COMMIT;   -- Validation finale : les changements sont définitifs
		END IF;
```

SET @StartDate='1/1/1997'
SET @EndDate='1/20/1997'

EXECUTE OrdersByDate @StartDate, @EndDate
```
### 2. Programmation Procédurale MySQL : Syntaxe Évoluée

Le langage procédural de MySQL permet d'encapsuler de la logique métier complexe. Contrairement au SQL standard, il nécessite l'utilisation de blocs `BEGIN ... END` et de mots-clés de contrôle de flux.

#### Éléments clés de la syntaxe :

## Triggers 
* **Déclaration :** Les variables locales doivent être déclarées au tout début du bloc avec `DECLARE`.
* **Gestion d'erreurs (Handlers) :** Crucial pour automatiser le `ROLLBACK` en cas d'erreur SQL.
* **Structures de contrôle :** `IF`, `CASE`, `WHILE`, `LOOP`.

Un trigger (ou déclencheur) est un code SQL associé à une seule table se déclenchant pour un ou plusieurs événements se produisant sur cette table. Ce code est exécuté par le SGBD chaque fois qu'un des événements se réalise.
**Exemple : Procédure avec gestionnaire d'erreur et transaction**
```SQL
DELIMITER //

Un trigger peut être déclenché par les événements suivants :
- l'insertion de tuples,
- la suppression de tuples,
- la modification de tuples dans une table. 
CREATE PROCEDURE p_virement_securise(IN p_expediteur INT, IN p_destinataire INT, IN p_montant DECIMAL(10,2))
BEGIN
    -- 1. Déclarer un gestionnaire en cas d'erreur SQL
	DECLARE EXIT HANDLER FOR SQLEXCEPTION
	BEGIN
		-- En cas d'erreur (ex: clé étrangère inexistante), on annule tout
		ROLLBACK;
		RESIGNAL; -- Renvoie l'erreur au client
	END;

L'événement déclencheur est donc l'une des commandes `INSERT`, `DELETE`, `UPDATE` ou l'une de leurs combinaisons possibles par l'opérateur booléen `OR`.
	-- 2. Début de la logique métier
	START TRANSACTION;

Le traitement qui est décrit pour un trigger est rédigé en Transact SQL (SQL Server) ou en PL/SQL (Oracle). Il peut agir sur les informations stockées dans la table pour laquelle il a été défini ou pour tout autre objet de la base de données.
	-- Vérification du solde
	IF (SELECT solde FROM comptes WHERE id = p_expediteur) < p_montant THEN
		SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Solde insuffisant';
	END IF;

La syntaxe simplifiée de la commande qui permet de créer un trigger est la suivante :
	-- Exécution des mouvements
	UPDATE comptes SET solde = solde - p_montant WHERE id = p_expediteur;
	UPDATE comptes SET solde = solde + p_montant WHERE id = p_destinataire;

```sql
CREATE TRIGGER [ schema_name . ]trigger_name 
ON { table | view } 
	{ FOR | AFTER | INSTEAD OF } 
	{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] } 
	AS { sql_statement [ ; ] }
	-- Si tout va bien, on valide
	COMMIT;
END //

DELIMITER ;
```

Un trigger traitant des enregistrements en cours de modification, il est possible d'accéder à la valeur de l'enregistrement avant modification (`DELETED` sous SQL Server, `:OLD` sous Oracle) et après modification (`INSERTED` sous SQL Server, `:NEW` sous Oracle). Ces valeurs apparaissent en fonction du type de mise à jour.
### Résumé des différences techniques MySQL :

La modification d'un trigger peut également se faire par la commande de modification suivante : 
| Fonctionnalité | Syntaxe MySQL | Note technique |
| --- | --- | --- |
| **Variables** | `DECLARE v_nom INT DEFAULT 0;` | Uniquement à l'intérieur d'un `BEGIN...END`. |																	
| **Assignation** | `SET v_nom = 10;` ou `SELECT col INTO v_nom...` | Utilise `INTO` pour stocker le résultat d'un SELECT. |
| **Annulation** | `SIGNAL SQLSTATE '45000'` | Provoque une erreur personnalisée pour stopper l'exécution. |
| **Délimiteur** | `DELIMITER //` | Nécessaire pour que le client SQL ne confonde pas le `;` interne avec la fin de la procédure. |

```sql
ALTER TRIGGER [schema.]trigger { ENABLE / DISABLE / COMPILE } ;
```
## Procédures stockées

Pour supprimer un trigger, l'utilisateur doit formuler la commande suivante : 
Les procédures stockées représentent des programmes constitués d'une séquence d'instructions SQL. Elles sont stockées dans la base de données et conçues pour effectuer une tâche particulière. Elles peuvent contenir une commande ou un ensemble de commandes SQL (Logique `IF`, boucles, etc.).

```sql
DROP TRIGGER [schema.]trigger ;
```
Dans MySQL, les procédures sont pré-calculées sur le serveur, ce qui évite d'envoyer de lourdes requêtes sur le réseau : l'utilisateur appelle simplement le nom de la procédure.

*Exemples (SQL Server)*
### Avantages

```sql
CREATE TRIGGER CheckStock ON Products FOR UPDATE
AS
	IF (SELECT InStock FROM INSERTED) < 0
	BEGIN
		PRINT 'Cannot oversell Products'
		PRINT 'Transaction has been cancelled'
		ROLLBACK
	END
```
* **Performance :** Réduction du trafic réseau entre le client et le serveur.
* **Sécurité :** On peut donner l'accès à une procédure sans donner l'accès direct aux tables.
* **Maintenance :** La logique métier est centralisée à un seul endroit.
* **Cohérence :** Garantit que la même opération est exécutée de la même manière par toutes les applications.

### Syntaxe de création

Pour créer une procédure dans MySQL, il faut changer temporairement le délimiteur de fin d'instruction (généralement `;`) pour que le serveur ne stoppe pas l'exécution à la première ligne interne.

```sql
CREATE TRIGGER DelhiDel ON Customers FOR DELETE
AS
     IF (SELECT state FROM DELETED) = 'Delhi'
DELIMITER //

CREATE PROCEDURE nom_procedure (IN param1 INT, OUT param2 INT)
BEGIN
		PRINT 'Can not remove customers from Delhi'
		PRINT 'Transaction has been canceled'
	ROLLBACK
    -- Corps de la procédure
	    SELECT COUNT(*) INTO param2 FROM ma_table WHERE id = param1;
END //

DELIMITER ;

END
```

*Exemples (Oracle)* 
### Appel d'une procédure

```sql
CREATE TRIGGER CheckStock BEFORE UPDATE ON Products
BEGIN
	IF (SELECT InStock FROM :NEW) < 0
	BEGIN
		PRINT 'Cannot oversell Products'
		PRINT 'Transaction has been cancelled'	
		ROLLBACK
	END
END
CALL nom_procedure(10, @resultat);
SELECT @resultat;

```


## Triggers (Déclencheurs)

Un **trigger** est un objet de la base de données associé à une table, qui s'exécute (se "déclenche") automatiquement lorsqu'un événement spécifique survient sur cette table.

### Événements déclencheurs

* **INSERT** : Ajout de lignes.
* **UPDATE** : Modification de lignes.
* **DELETE** : Suppression de lignes.

### Moments du déclenchement

* **BEFORE** : Avant que la modification ne soit appliquée (idéal pour la validation ou la modification de données entrantes).
* **AFTER** : Après que la modification a été effectuée (idéal pour mettre à jour d'autres tables ou remplir des tables de log/audit).

### Mots-clés spécifiques

* **OLD** : Accède aux valeurs de la ligne **avant** l'opération (disponible en `UPDATE` et `DELETE`).
* **NEW** : Accède aux nouvelles valeurs **après/pendant** l'opération (disponible en `INSERT` et `UPDATE`).

### Exemple de Trigger (Blocage de suppression)

Voici l'adaptation de ton exemple : empêcher la suppression de clients habitant à 'Delhi'. Dans MySQL, pour annuler une transaction dans un trigger, on utilise souvent `SIGNAL SQLSTATE` pour lever une erreur.

```sql
CREATE TRIGGER FOR DELETE DelhiDel ON Customers 
BEGIN
	IF (SELECT state FROM :OLD)= 'Delhi'
DELIMITER //

CREATE TRIGGER before_delete_customers
BEFORE DELETE ON customers
FOR EACH ROW
BEGIN
		PRINT 'Can not remove customers from Delhi'
		PRINT 'Transaction has been canceled'
		ROLLBACK
	END
END
	IF OLD.city = 'Delhi' THEN
			SIGNAL SQLSTATE '45000' 
					SET MESSAGE_TEXT = 'Can not remove customers from Delhi. Transaction canceled.';
						END IF;
						END //

DELIMITER ;

```
 No newline at end of file