Mysql
 sql >> Baza danych >  >> RDS >> Mysql

AKTUALIZUJ TABELĘ O SUMA

Wyzwalacze są prawdopodobnie chcesz chcesz. Jednak sprawienie, aby to działało poprawnie i wydajnie, będzie brzydkie. Prawdopodobnie lepiej nie przechowywać salda w każdym wierszu, jeśli zamierzasz wstawiać wiersze we wcześniejszych terminach tak często; zamiast tego użyj zapytań lub widoków znaleźć równowagę. Aby znaleźć saldo w określonym dniu, połącz je z wierszami dla wcześniejszych dat i zsumuj depozyt netto, grupując według bieżącego identyfikatora transakcji:

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
;

Ograniczam również older.pc_id być mniejsze niż current.pc_id w celu ustalenia niejasności dotyczących schematu i kalkulacji salda. Od pc_date nie jest unikalny, możesz mieć wiele transakcji w danym dniu. Jeśli tak jest, jakie powinno być saldo dla każdej transakcji? Tutaj zakładamy, że transakcja z większym identyfikatorem następuje po transakcji z mniejszym identyfikatorem, ale ma tę samą datę. Bardziej formalnie korzystamy z zamówienia

Zauważ, że w widoku używamy kolejności ≥ opartej na>:

Po próbie sprawienia, aby wyzwalacze działały prawidłowo, radzę nawet nie próbować. Ze względu na wewnętrzne blokady tabeli lub wiersza podczas wstawiania/aktualizowania, musisz przenieść kolumnę salda do nowej tabeli, choć nie jest to zbyt uciążliwe (zmień nazwę pettycash do pettytransactions , utwórz nowy pettybalance (balance, pc_id) tabeli i utwórz widok o nazwie pettycash niż dołącza do pettytransactions i pettybalance na pc_id ). Główny problem polega na tym, że ciała wyzwalające są wykonywane raz dla każdego utworzonego lub zaktualizowanego wiersza, co spowoduje, że będą one niewiarygodnie nieefektywne. Alternatywą byłoby utworzenie procedury składowanej do aktualizacji kolumn, które możesz wywołać po wstawieniu lub aktualizacji. Procedura jest bardziej wydajna podczas pobierania sald niż widok, ale jest bardziej krucha, ponieważ to programiści powinni aktualizować salda, zamiast pozwolić, aby obsłużyła je baza danych. Korzystanie z widoku to czystszy projekt.

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 ;

Nie na temat

Problemem z obecnym schematem jest użycie Float s do przechowywania wartości pieniężnych. Ze względu na sposób przedstawiania liczb zmiennoprzecinkowych, liczby o podstawie 10 (tzn. nie mają powtarzalnej reprezentacji dziesiętnej) nie zawsze są dokładne jako liczby zmiennoprzecinkowe. Na przykład 0,01 (w podstawie 10) będzie bliższe 0,009999999776482582... lub 0,0100000000000000002081668... podczas przechowywania. To raczej tak, jak 1/3 w bazie 3 to "0.1", ale 0.333333.... w bazie 10. Zamiast Float , należy użyć Decimal typ:

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

Jeśli używasz widoku, upuść pettycash.pc_bal . Jeśli używasz procedury składowanej do aktualizacji pettycash.pc_bal , to też powinno zostać zmienione.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Pobieranie wierszy dodanych w ostatniej godzinie

  2. wznowić dla XID podniesionego 0:nieznany

  3. Wybierz wiersz z najnowszą datą na użytkownika

  4. Ustaw strefę czasową w PHP i MySQL

  5. Kreatywne zastosowania silnika czarnej dziury