Mise à jour séquentielle des soldes dans MySQL avec des variables utilisateur

Création de la table

CREATE TABLE operations_financieres (
    moment_operation TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    montant_depense INT NOT NULL,
    solde_courant INT NOT NULL
);

Structure de la table

mysql> DESC operations_financieres;
+-------------------+-----------+------+-----+-------------------+-------+
| Field             | Type      | Null | Key | Default           | Extra |
+-------------------+-----------+------+-----+-------------------+-------+
| moment_operation  | timestamp | NO   |     | CURRENT_TIMESTAMP |       |
| montant_depense   | int(11)   | NO   |     | NULL              |       |
| solde_courant     | int(11)   | NO   |     | NULL              |       |
+-------------------+-----------+------+-----+-------------------+-------+
3 rows in set (0.00 sec)

Insertion des données d'exemple

INSERT INTO operations_financieres 
(moment_operation, montant_depense, solde_courant) 
VALUES 
(CURRENT_TIMESTAMP, 1, 100), 
(CURRENT_TIMESTAMP + INTERVAL 1 DAY, 3, 0), 
(CURRENT_TIMESTAMP + INTERVAL 2 DAY, 5, 0),
(CURRENT_TIMESTAMP + INTERVAL 3 DAY, 12, 0), 
(CURRENT_TIMESTAMP + INTERVAL 4 DAY, 7, 0);

Aperçu des données

mysql> SELECT * FROM operations_financieres;
+---------------------+----------------+--------------+
| moment_operation    | montant_depense| solde_courant|
+---------------------+----------------+--------------+
| 2017-10-12 15:40:31 |              1 |          100 |
| 2017-10-13 15:40:31 |              3 |            0 |
| 2017-10-14 15:40:31 |              5 |            0 |
| 2017-10-15 15:41:48 |             12 |            0 |
| 2017-10-16 15:41:48 |              7 |            0 |
+---------------------+----------------+--------------+
5 rows in set (0.00 sec)

La colonne solde_courant doit être recalculée. La règle métier est la suivante : chaque ligne doit avoir un solde égal au solde de la ligne précédente diminué du montant dépensé de la ligne courante. La première ligne contient déjà la valeur correcte (100).

Mise à jour ordonnée avec variable utilisateur

Pour réaliser une mise à jour où chaque ligne dépend du résultat de la ligne précédente, nous exploitons une variable utilisateur MySQL. Cette variable accumule le solde au fur et à mesure que l'UPDATE parcourt les lignes dans l'ordre chronologique. La'stuce consiste à initialiser la variable dans la clause ORDER BY juste avant le tri.

UPDATE operations_financieres 
SET solde_courant = (@solde_precedent := @solde_precedent - montant_depense) 
ORDER BY (@solde_precedent := 101), moment_operation;

L'expression @solde_precedent := 101 est évaluée en premier et intiialise la variable à 101 (le solde initial 100 + 1, car la première soustraction de 1 donnera 100). L'ordre d'évaluation garantit que la variable est prête avant le traitement de la première ligne.

Résultat après mise à jour

mysql> SELECT * FROM operations_financieres;
+---------------------+----------------+--------------+
| moment_operation    | montant_depense| solde_courant|
+---------------------+----------------+--------------+
| 2017-10-12 15:40:31 |              1 |          100 |
| 2017-10-13 15:40:31 |              3 |           97 |
| 2017-10-14 15:40:31 |              5 |           92 |
| 2017-10-15 15:41:48 |             12 |           80 |
| 2017-10-16 15:41:48 |              7 |           73 |
+---------------------+----------------+--------------+
5 rows in set (0.00 sec)

Étiquettes: MySQL variables utilisateur UPDATE ORDER BY SQL requêtes séquentielles

Publié le 24 juin à 16h10