Как обновить столбец на основе предыдущего значения? - PullRequest
0 голосов
/ 27 апреля 2019

Я прочитал здесь много ответов, но не смог приспособиться к своим потребностям.

У меня есть таблица ниже, где я хотел бы обновить столбец BALANCE:

balance = old.balance + new.amount

+----+----------------+---------+------------+-------------+---------------------+------------------+--------+----------+---------+
| ID | TRANSACTION_ID | BANK_ID | ACCOUNT_ID | CUSTOMER_ID | CREATED             | DESCRIPTION      | AMOUNT | CURRENCY | BALANCE |
+----+----------------+---------+------------+-------------+---------------------+------------------+--------+----------+---------+
|  1 | T1             |       2 |          2 |           1 | 2018-04-22 00:00:00 | TRANSACTION TEST | 100.00 | GBP      |    NULL |
|  2 | T2             |       2 |          2 |           1 | 2018-04-22 00:00:00 | TRANSACTION TEST | 125.00 | GBP      |    NULL |
|  3 | T3             |       2 |          2 |           1 | 2018-04-22 00:00:00 | TRANSACTION TEST | -73.00 | GBP      |    NULL |
+----+----------------+---------+------------+-------------+---------------------+------------------+--------+----------+---------+

Это результат, который я хотел бы показать ниже: Я получил это выполнение:

SET @balance:=0;
UPDATE TRANSACTIONS SET BALANCE = (@balance := @balance + AMOUNT) WHERE ID > 0;

Нет способа запустить оператор выше после вставки нового столбца?

+----+----------------+---------+------------+-------------+---------------------+------------------+--------+----------+---------+
| ID | TRANSACTION_ID | BANK_ID | ACCOUNT_ID | CUSTOMER_ID | CREATED             | DESCRIPTION      | AMOUNT | CURRENCY | BALANCE |
+----+----------------+---------+------------+-------------+---------------------+------------------+--------+----------+---------+
|  1 | T1             |       2 |          2 |           1 | 2018-04-22 00:00:00 | TRANSACTION TEST | 100.00 | GBP      |  100.00 |
|  2 | T2             |       2 |          2 |           1 | 2018-04-22 00:00:00 | TRANSACTION TEST | 125.00 | GBP      |  225.00 |
|  3 | T3             |       2 |          2 |           1 | 2018-04-22 00:00:00 | TRANSACTION TEST | -73.00 | GBP      |  152.00 |
+----+----------------+---------+------------+-------------+---------------------+------------------+--------+----------+---------+

Я пытался использовать триггер:

DELIMITER $$ 
CREATE TRIGGER updateBalance AFTER INSERT ON TRANSACTIONS 
FOR EACH ROW 
BEGIN
    SET NEW.BALANCE = BALANCE + NEW.AMOUNT;
END $$ 
DELIMITER ;

И я получил ошибку:

Error Code: 1362. Updating of NEW row is not allowed in after trigger

Я новичок в SQL и MySQL и считаю, что это обычная задача для опытных пользователей.

Ответы [ 2 ]

0 голосов
/ 27 апреля 2019

Вы можете сделать это с помощью триггера BEFORE INSERT, суммируя все суммы транзакций для данного CUSTOMER_ID и добавляя новое значение AMOUNT, чтобы получить баланс:

DELIMITER $$
CREATE TRIGGER updateBalance BEFORE INSERT ON transactions
FOR EACH ROW
BEGIN
   SET NEW.BALANCE = NEW.AMOUNT +
                     COALESCE((SELECT SUM(AMOUNT) 
                               FROM transactions 
                               WHERE CUSTOMER_ID = NEW.CUSTOMER_ID), 0);
END $$
DELIMITER ;

Демонстрация по dbfiddle

Обратите внимание, что вы можете дополнительно уточнить сумму с

AND BANK_ID = NEW.BANK_ID

и / или

AND ACCOUNT_ID = NEW.ACCOUNT_ID

, если необходимо точно определить, какие записичитать предыдущие транзакции из.

0 голосов
/ 27 апреля 2019

Значения, которые можно рассчитать из других (материализованных) значений, не должны материализоваться, так как это может привести к несоответствиям.

Удалить столбец все вместе.

ALTER TABLE transactions
            DROP balance;

И вместо этого создайте представление:

CREATE VIEW transactions_with_balance
AS
SELECT t1.*,
       (SELECT sum(t2.amount)
               FROM transactions t2
               WHERE t2.bank_id = t1.bank_id
                     AND t2.account_id = t1.account_id
                     AND t2.id <= t1.id) balance
       FROM transactions t1;

дб <> скрипка

Если вы используете MySQL версии 8 или выше, вы также можете заменить подзапрос оконной версией sum()

CREATE VIEW transactions_with_balance
AS
SELECT t1.*,
       sum(amount) OVER (PARTITION BY t1.bank_id,
                                      t1.account_id
                         ORDER BY t1.id) balance
       FROM transactions t1;

дб <> скрипка

Столбец customer_id также кажется неуместным в таблице, так как я предполагаю, что есть таблица счетов, в которой клиент, которому принадлежит счет, хранится во внешнем ключе таблицы клиентов. Таким образом, вы можете получить клиента через accoount_id.

...