如何根据先前的值更新列?

时间:2019-04-26 21:55:51

标签: mysql sql database-trigger

我在这里阅读了很多答案,但是我无法适应我的需求。

我在下面的表格中想要更新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 :(得分:0)

不应从其他(物化)值中计算出的值物化,因为这会导致不一致。

一起删除该列。

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;

db<>fiddle

如果您使用的是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;

db<>fiddle

customer_id在表中似乎也放错了位置,因为我想有一个客户表,该客户所属的客户存储在客户表的外键中。这样您就可以通过accoount_id吸引客户。

答案 1 :(得分:0)

您可以使用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 ;

Demo on dbfiddle

请注意,您可能想用

进一步限定总和
AND BANK_ID = NEW.BANK_ID

和/或

AND ACCOUNT_ID = NEW.ACCOUNT_ID

根据需要准确区分要从中读取先前交易记录的记录。