Mysql
 sql >> Database >  >> RDS >> Mysql

AGGIORNAMENTO TABELLA CON SOMMA

Trigger probabilmente vuoi tu vuoi. Tuttavia, farlo funzionare correttamente ed efficientemente sarà brutto. Probabilmente è meglio non memorizzare il saldo in ogni riga se si inseriscono righe in date precedenti molto frequentemente; invece, usa query o viste per trovare l'equilibrio. Per trovare il saldo in una data particolare, uniscilo alle righe delle date precedenti e somma il deposito netto, raggruppandolo per ID transazione corrente:

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
;

Limito anche older.pc_id essere inferiore a current.pc_id al fine di correggere un'ambiguità relativa allo schema e al calcolo del saldo. Dal pc_date non è univoco, potresti avere più transazioni per una determinata data. In tal caso, quale dovrebbe essere il saldo per ciascuna transazione? Qui assumiamo che una transazione con un ID più grande avvenga dopo una transazione con un ID più piccolo ma che ha la stessa data. Più formalmente, utilizziamo l'ordinamento

Nota che nella vista, utilizziamo un ordine ≥ basato su>:

Dopo aver provato a far funzionare correttamente i trigger, ti consiglierò di non provare nemmeno. A causa di blocchi di righe o tabelle interne durante l'inserimento/l'aggiornamento, è necessario spostare la colonna del saldo in una nuova tabella, anche se questo non è troppo oneroso (rinominare pettycash a pettytransactions , crea un nuovo pettybalance (balance, pc_id) tabella e crea una vista denominata pettycash che si unisce a pettytransactions e pettybalance su pc_id ). Il problema principale è che i corpi trigger vengono eseguiti una volta per ogni riga creata o aggiornata, il che li renderà incredibilmente inefficienti. Un'alternativa sarebbe creare una procedura memorizzata per aggiornare le colonne, che puoi chiamare dopo l'inserimento o l'aggiornamento. Una procedura è più performante quando si ottengono saldi rispetto a una vista, ma più fragile poiché spetta ai programmatori aggiornare i saldi, piuttosto che lasciare che sia il database a gestirlo. L'uso di una vista è il design più pulito.

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 ;

Fuori tema

Un problema con lo schema corrente è l'uso di Float s per memorizzare valori monetari. A causa del modo in cui vengono rappresentati i numeri in virgola mobile, i numeri esatti in base 10 (cioè non hanno una rappresentazione decimale ripetuta) non sono sempre esatti come float. Ad esempio, 0,01 (in base 10) sarà più vicino a 0,0099999999776482582... o 0,01000000000000000002081668... quando memorizzato. È un po' come 1/3 in base 3 è "0.1" ma 0.333333.... in base 10. Invece di Float , dovresti usare Decimal digita:

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

Se utilizzi una vista, rilascia pettycash.pc_bal . Se si utilizza una procedura memorizzata per aggiornare pettycash.pc_bal , anch'esso dovrebbe essere modificato.