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)