Mysql
 sql >> Base de données >  >> RDS >> Mysql

MISE À JOUR TABLE AVEC SOMME

Déclencheurs sont probablement que vous voulez. Cependant, faire en sorte que cela fonctionne correctement et efficacement sera moche. Il est probablement préférable de ne pas stocker le solde dans chaque ligne si vous insérez fréquemment des lignes à des dates antérieures ; à la place, utilisez des requêtes ou vues pour trouver l'équilibre. Pour trouver le solde à une date particulière, joignez-le aux lignes des dates antérieures et additionnez le dépôt net, en regroupant par l'ID de transaction actuel :

CREATE VIEW pettybalance
  AS SELECT SUM(older.pc_in - older.pc_out) AS balance, 
            current.pc_id AS pc_id,  -- foreign key
            current.pc_date AS `date`
       FROM pettycash AS current
         JOIN pettycash AS older
           ON current.pc_date > older.pc_date 
              OR (current.pc_date = older.pc_date AND current.pc_id >= older.pc_id)
       GROUP BY current.pc_id
;

Je limite également older.pc_id être inférieur à current.pc_id afin de lever une ambiguïté relative au schéma et au calcul du solde. Depuis le pc_date n'est pas unique, vous pourriez avoir plusieurs transactions pour une date donnée. Si tel est le cas, quel doit être le solde de chaque transaction ? Ici, nous supposons qu'une transaction avec un ID plus grand vient après une transaction avec un ID plus petit mais qui a la même date. Plus formellement, nous utilisons la commande

Notez que dans la vue, nous utilisons un ordre ≥ basé sur> :

Après avoir essayé de faire fonctionner correctement les déclencheurs, je vais recommander de ne même pas essayer. En raison de verrous internes de table ou de ligne lors de l'insertion/de la mise à jour, vous devez déplacer la colonne de solde vers une nouvelle table, bien que ce ne soit pas trop onéreux (renommer pettycash aux pettytransactions , créez un nouveau pettybalance (balance, pc_id) table et créez une vue nommée pettycash que rejoint pettytransactions et pettybalance sur pc_id ). Le principal problème est que les corps de déclencheur s'exécutent une fois pour chaque ligne créée ou mise à jour, ce qui les rendra incroyablement inefficaces. Une alternative serait de créer une procédure stockée pour mettre à jour les colonnes, que vous pouvez appeler après l'insertion ou la mise à jour. Une procédure est plus performante lors de l'obtention des soldes qu'une vue, mais plus fragile car c'est aux programmeurs de mettre à jour les soldes, plutôt que de laisser la base de données le gérer. L'utilisation d'une vue est la conception la plus propre.

DROP PROCEDURE IF EXISTS update_balance;
delimiter ;;
CREATE PROCEDURE update_balance (since DATETIME)
BEGIN
    DECLARE sincebal DECIMAL(10,2);
    SET sincebal = (
          SELECT pc_bal 
            FROM pettycash AS pc 
            WHERE pc.pc_date < since
            ORDER BY pc.pc_date DESC, pc.pc_id DESC LIMIT 1
        );
    IF ISNULL(sincebal) THEN
      SET sincebal=0.0;
    END IF;
    UPDATE pettycash AS pc
      SET pc_bal=(
        SELECT sincebal+SUM(net) 
          FROM (
            SELECT pc_id, pc_in - pc_out AS net, pc_date
              FROM pettycash
              WHERE since <= pc_date 
          ) AS older
          WHERE pc.pc_date > older.pc_date
             OR (pc.pc_date = older.pc_date 
                 AND pc.pc_id >= older.pc_id)
      ) WHERE pc.pc_date >= since;
END;;
delimiter ;

Hors sujet

Un problème avec le schéma actuel est l'utilisation de Float s pour stocker des valeurs monétaires. En raison de la façon dont les nombres à virgule flottante sont représentés, les nombres qui sont exacts en base 10 (c'est-à-dire qui n'ont pas de représentation décimale répétitive) ne sont pas toujours exacts en tant que flottants. Par exemple, 0,01 (en base 10) sera plus proche de 0,009999999776482582... ou 0,010000000000000002081668... lorsqu'il est stocké. C'est un peu comme si 1/3 en base 3 est "0,1" mais 0,333333... en base 10. Au lieu de Float , vous devez utiliser le Decimal saisissez :

ALTER TABLE pettycash MODIFY pc_in DECIMAL(10,2);
ALTER TABLE pettycash MODIFY pc_out DECIMAL(10,2);

Si vous utilisez une vue, supprimez pettycash.pc_bal . Si vous utilisez une procédure stockée pour mettre à jour pettycash.pc_bal , elle aussi doit être modifiée.