sql >> Database >  >> RDS >> Mysql

UPDATE TABEL MET SUM

Triggers zijn waarschijnlijk wilt u wilt. Het zal echter lelijk zijn om dit goed en efficiënt te laten werken. Het is waarschijnlijk beter om het saldo niet in elke rij op te slaan als u zo vaak rijen op eerdere data gaat invoegen; gebruik in plaats daarvan zoekopdrachten of weergaven om de balans te vinden. Om het saldo op een bepaalde datum te vinden, voegt u het samen met de rijen voor eerdere datums en telt u de netto-storting op, gegroepeerd op de huidige transactie-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
;

Ik beperk ook older.pc_id kleiner zijn dan current.pc_id om een ​​dubbelzinnigheid met betrekking tot het schema en de balansberekening op te lossen. Sinds de pc_date niet uniek is, kunt u meerdere transacties hebben voor een bepaalde datum. Als dat het geval is, wat moet dan het saldo zijn voor elke transactie? Hierbij gaan we ervan uit dat een transactie met een grotere ID komt na een transactie met een kleinere ID maar die dezelfde datum heeft. Meer formeel gebruiken we de volgorde

Merk op dat we in de weergave een ≥-volgorde gebruiken op basis van>:

Nadat ik geprobeerd heb om triggers goed te laten werken, raad ik aan om het niet eens te proberen. Vanwege interne tabel- of rijvergrendelingen bij het invoegen/bijwerken, moet u de saldokolom naar een nieuwe tabel verplaatsen, hoewel dit niet al te omslachtig is (hernoem pettycash naar pettytransactions , maak een nieuwe pettybalance (balance, pc_id) tabel, en maak een weergave met de naam pettycash dan sluit zich aan bij pettytransactions en pettybalance op pc_id ). Het grootste probleem is dat trigger-instanties één keer worden uitgevoerd voor elke gemaakte of bijgewerkte rij, waardoor ze ongelooflijk inefficiënt zijn. Een alternatief zou zijn om een ​​opgeslagen procedure te maken om kolommen bij te werken, die u kunt oproepen na het invoegen of bijwerken. Een procedure is performanter bij het verkrijgen van saldi dan een weergave, maar brozer omdat het aan programmeurs is om saldi bij te werken, in plaats van de database het te laten afhandelen. Het gebruik van een weergave is het schonere ontwerp.

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

Een probleem met het huidige schema is het gebruik van Float s om geldwaarden op te slaan. Vanwege de manier waarop getallen met drijvende komma worden weergegeven, zijn getallen die exact zijn in grondtal 10 (d.w.z. geen herhalende decimale representatie hebben) niet altijd exact als drijvers. Bijvoorbeeld, 0,01 (in grondtal 10) zal dichter bij 0,009999999776482582... of 0,0100000000000002081668... liggen wanneer deze wordt opgeslagen. Het is een beetje zoals hoe 1/3 in basis 3 "0.1" is, maar 0.333333.... in basis 10. In plaats van Float , moet u de Decimal typ:

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

Als u een weergave gebruikt, laat u pettycash.pc_bal . vallen . Als u een opgeslagen procedure gebruikt om pettycash.pc_bal bij te werken, , moet ook worden gewijzigd.




  1. Hoe MySQL 8.0 op CentOS 8 / RHEL 8 te installeren

  2. node-mysql meerdere instructies in één query

  3. Laravel (5.3) Welsprekend - Relatieprobleem

  4. Waarom is hier ONMIDDELLIJK UITVOEREN nodig?