sql >> Databáze >  >> RDS >> Mysql

AKTUALIZUJTE TABULKU SOUČETEM

Spouštěče pravděpodobně chcete, co chcete. Nicméně, aby to fungovalo správně a efektivně, bude ošklivé. Pokud budete tak často vkládat řádky v dřívějších datech, bude pravděpodobně lepší neukládat zůstatek v každém řádku; místo toho použijte dotazy nebo zobrazení najít rovnováhu. Chcete-li zjistit zůstatek k určitému datu, spojte jej s řádky pro dřívější data a sečtěte čistý vklad seskupený podle aktuálního ID transakce:

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
;

Také omezuji older.pc_id být menší než current.pc_id aby se odstranila nejednoznačnost týkající se schématu a výpočtu zůstatku. Od pc_date není jedinečný, můžete mít více transakcí pro dané datum. Pokud tomu tak je, jaký by měl být zůstatek u každé transakce? Zde předpokládáme, že transakce s větším ID přichází po transakci s menším ID, která má ale stejné datum. Formálněji používáme řazení

Všimněte si, že v zobrazení používáme pořadí ≥ založené na>:

Po pokusu o správné fungování spouštěčů doporučuji ani nezkoušet. Kvůli vnitřním zámkům tabulky nebo řádků při vkládání/aktualizaci musíte sloupec zůstatku přesunout do nové tabulky, i když to není příliš náročné (přejmenujte pettycash na pettytransactions , vytvořte nový pettybalance (balance, pc_id) a vytvořte pohled s názvem pettycash než se připojí k pettytransactions a pettybalance na pc_id ). Hlavním problémem je, že těla spouštěčů se spouštějí jednou pro každý vytvořený nebo aktualizovaný řádek, což způsobí, že budou neuvěřitelně neefektivní. Alternativou by bylo vytvoření uložené procedury k aktualizaci sloupců, které můžete po vložení nebo aktualizaci vyvolat. Procedura je výkonnější při získávání zůstatků než pohled, ale je křehčí, protože je na programátorech, aby aktualizovali zůstatky, než aby je nechali zpracovávat databázi. Použití pohledu je čistší 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 ;

Mimo téma

Problémem současného schématu je použití Float s k ukládání peněžních hodnot. Kvůli tomu, jak jsou čísla s plovoucí desetinnou čárkou reprezentována, čísla, která jsou přesná v základu 10 (tj. nemají opakující se desítkové zastoupení), nejsou vždy přesná jako čísla s plovoucí desetinnou čárkou. Například 0,01 (v základu 10) bude blíže k 0,009999999776482582... nebo 0,0100000000000000002081668... při uložení. Je to spíše jako 1/3 v základu 3 je "0,1", ale 0,333333.... v základu 10. Místo Float , měli byste použít Decimal typ:

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

Pokud používáte pohled, přetáhněte pettycash.pc_bal . Pokud používáte uloženou proceduru k aktualizaci pettycash.pc_bal , měl by být také změněn.




  1. Vraťte hodnoty sloupců před aktualizací pouze pomocí SQL

  2. C# s parametry INSERT MySQL

  3. Jak upravím tabulku, abych povolil CASCADE DELETE?

  4. Kdy mám na SQL Serveru používat středníky?