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

OPDATERING TABEL MED SUM

Triggers er sandsynligvis ønsker du ønsker. Det vil dog være grimt at få dette til at fungere korrekt og effektivt. Det er nok bedre ikke at gemme saldoen i hver række, hvis du så ofte skal indsætte rækker på tidligere datoer; brug i stedet forespørgsler eller visninger at finde balancen. For at finde saldoen på en bestemt dato skal du slå den sammen med rækkerne for tidligere datoer og summere nettoindbetalingen, grupperet efter det aktuelle transaktions-id:

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
;

Jeg begrænser også older.pc_id at være mindre end current.pc_id for at fastlægge en uklarhed vedrørende skemaet og saldoberegningen. Siden pc_date er ikke unik, kan du have flere transaktioner for en given dato. Hvis det er tilfældet, hvad skal saldoen så være for hver transaktion? Her antager vi, at en transaktion med et større ID kommer efter en transaktion med et mindre ID, men som har samme dato. Mere formelt bruger vi bestillingen

Bemærk, at vi i visningen bruger en ≥ rækkefølge baseret på>:

Efter at have forsøgt at få triggere til at fungere korrekt, vil jeg anbefale ikke engang at prøve. På grund af interne tabel- eller rækkelåse ved indsættelse/opdatering, skal du flytte saldokolonnen til en ny tabel, selvom dette ikke er for besværligt (omdøb pettycash til pettytransactions , opret en ny pettybalance (balance, pc_id) tabel, og opret en visning med navnet pettycash end slutter sig til pettytransactions og pettybalancepc_id ). Hovedproblemet er, at trigger-kroppe udføres én gang for hver række, der er oprettet eller opdateret, hvilket vil få dem til at være utroligt ineffektive. Et alternativ ville være at oprette en lagret procedure at opdatere kolonner, som du kan kalde efter indsættelse eller opdatering. En procedure er mere effektiv, når man får saldi end en visning, men mere skør, da det er op til programmører at opdatere saldi i stedet for at lade databasen håndtere det. At bruge en visning er det renere design.

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 ;

Udenfor emnet

Et problem med det aktuelle skema er brugen af ​​Float s at gemme pengeværdier. På grund af hvordan flydende kommatal repræsenteres, er tal, der er nøjagtige i grundtallet 10 (dvs. ikke har en gentagende decimalrepræsentation) ikke altid nøjagtige som flydere. For eksempel vil 0,01 (i basis 10) være tættere på 0,009999999776482582... eller 0,010000000000000000002081668... når den er gemt. Det er lidt ligesom, hvordan 1/3 i base 3 er "0,1", men 0,333333.... i base 10. I stedet for Float , skal du bruge Decimal type:

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

Hvis du bruger en visning, skal du slippe pettycash.pc_bal . Hvis du bruger en lagret procedure til at opdatere pettycash.pc_bal , bør den også ændres.




  1. Postgres 9.4 jsonb-array som tabel

  2. Pivot med flere kolonner i T-SQL

  3. MySQL Storage Engine Optimization:Konfiguration af InnoDB-optimering til høj ydeevne

  4. MySQL-pivotforespørgsel med sum af kolonneværdi