sql >> Databasteknik >  >> RDS >> Mysql

UPPDATERA TABELL MED SUMMA

Triggers är förmodligen vill du vill. Men att få detta att fungera korrekt och effektivt kommer att vara fult. Det är förmodligen bättre att inte lagra saldot i varje rad om du ska infoga rader vid tidigare datum så ofta; använd istället frågor eller vyer att hitta balansen. För att hitta saldot på ett visst datum, slå ihop det med raderna för tidigare datum och summera nettoinsättningen, grupperad efter aktuellt 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
;

Jag begränsar också older.pc_id vara mindre än current.pc_id för att fastställa en oklarhet som rör schemat och saldoberäkningen. Sedan pc_date är inte unikt, du kan ha flera transaktioner för ett visst datum. Om så är fallet, vad ska saldot vara för varje transaktion? Här antar vi att en transaktion med ett större ID kommer efter en transaktion med ett mindre ID men som har samma datum. Mer formellt använder vi beställningen

Observera att i vyn använder vi en ≥ ordning baserad på>:

Efter att ha försökt få triggers att fungera korrekt, kommer jag att rekommendera att du inte ens försöker. På grund av interna tabell- eller radlås när du infogar/uppdateringar måste du flytta saldokolumnen till en ny tabell, även om detta inte är alltför betungande (byt namn på pettycash till pettytransactions , skapa en ny pettybalance (balance, pc_id) tabell och skapa en vy som heter pettycash than ansluter till pettytransactions och pettybalancepc_id ). Huvudproblemet är att triggerkroppar körs en gång för varje rad som skapas eller uppdateras, vilket gör att de blir otroligt ineffektiva. Ett alternativ skulle vara att skapa en lagrad procedur för att uppdatera kolumner, som du kan anropa efter att du har infogat eller uppdaterat. En procedur är mer presterande när man skaffar saldon än en vy, men mer skör eftersom det är upp till programmerare att uppdatera saldon, snarare än att låta databasen hantera det. Att använda en vy är den renare designen.

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 ;

Off-topic

Ett problem med det aktuella schemat är användningen av Float s för att lagra monetära värden. På grund av hur flyttalsnummer representeras, är tal som är exakta i bas 10 (dvs. inte har en upprepad decimalrepresentation) inte alltid exakta som flytande. Till exempel kommer 0,01 (i bas 10) att vara närmare 0,009999999776482582... eller 0,010000000000000000002081668... när den lagras. Det är ungefär som hur 1/3 i bas 3 är "0,1" men 0,333333.... i bas 10. Istället för Float , bör du använda Decimal typ:

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

Om du använder en vy, släpp pettycash.pc_bal . Om du använder en lagrad procedur för att uppdatera pettycash.pc_bal , bör den också ändras.




  1. spola tabeller - åtkomst nekad

  2. Fråga för att kontrollera tabellstorleken i Oracle-databasen

  3. Returnerar alla rader med vissa villkor

  4. Hur kontrollerar man om en rad finns i MySQL? (dvs kontrollera om ett e-postmeddelande finns i MySQL)