1

我目前有一张account桌子和一张account_audit桌子(所有代码都可以在这里找到)。

我有两个触发器,它们根据插入到帐户表中的数据将记录插入到 account_audit 表中。

1 个触发器是一个 ON INSERT 触发器,它只插入这些值 - 工作正常。

因此,在我的审计表上插入 2 条记录后 - 我在两个表中都有两条记录,如下所示。

SELECT * FROM account;

acct_id acct_name   acct_balance    tax_rate    acct_opened
      1 Bill            100.00          0.10     2019-11-01
      2 Ben            1000.00          0.10     2019-11-01

SELECT * FROM account_audit;

acct_id txn_id  acct_name   acct_balance    tax_rate    valid_from  valid_to
      1      1       Bill         100.00        0.10    2021-11-07  2038-01-19
      2      2        Ben        1000.00        0.10    2021-11-07  2038-01-19

一切都很好——2038 年是 MariaDB 的无穷大——至少在临时表中是这样!

但是,我的 UPDATE 触发器如下:

CREATE TRIGGER testtrigger_upd 
AFTER UPDATE ON account
  FOR EACH ROW BEGIN
    UPDATE account_audit SET valid_to = NOW() 
    WHERE ((valid_to = '2038-01-19') AND (OLD.acct_name = NEW.acct_name));
    INSERT INTO 
      account_audit (acct_id, acct_name, acct_balance, tax_rate) 
      VALUES 
      (
        OLD.acct_id, 
        OLD.acct_name, 
        NEW.acct_balance, 
        OLD.tax_rate
        
        -- valid_from - NOW()!
        -- valid_to DEFAULTs to '2038-01-19' which is what we want for updates to balance 
      );
END;

因此,当我更新帐户的余额时,我希望 account_audit 跟踪反映这一点,然后将最近的(插入之前)余额记录转到valid_to(今天),并将今天的新记录valid_from转到valid_to2038 年(MariaDB 无限?)。

问题是当我运行这个语句时

UPDATE account 
SET acct_balance = acct_balance + 50 WHERE acct_name = 'Bill';  -- name is UNIQUE

account_audit 表中的记录变为:

acct_id txn_id  acct_name   acct_balance    tax_rate    valid_from  valid_to
      1      1       Bill         100.00    0.10        2021-11-07  2021-11-07
      1      3       Bill         150.00    0.10        2021-11-07  2038-01-19
      2      2        Ben        1000.00    0.10        2021-11-07  2021-11-07

您可以看到 Bill 的记录已被插入,但问题是 Ben 的记录也已更新为今天插入的日期 - 我只希望这发生在 Bill 身上!

我有WHERE ((valid_to = '2038-01-19') AND (OLD.acct_name = NEW.acct_name));我的触发器,我已经尝试了很多其他方法 -WHERE OLD.acct_id = NEW.acct_id我尝试将 UPDATE 更改为使用 acct_id 而不是名称 - 没有任何效果。我尝试交换OLD。和新的。订购 - 在更新之前或之后尝试 - 我真的疯了!

如何重写触发器以更新其帐户的人而不是所有帐户的 account_audit 表 - 也就是说,仅更新 Bill 的帐户而不是 Ben 的帐户?

我知道临时表功能——我不想使用它,因为这是为了研究,我必须使用触发器!

小提琴在这里

4

2 回答 2

1

那是因为您的 where 子句适用于所有行

所以更改更新查询以检查表

CREATE TRIGGER testtrigger_upd 
AFTER UPDATE ON account
  FOR EACH ROW BEGIN
    UPDATE account_audit SET valid_to = NOW() 
    WHERE ((valid_to = '2038-01-19') AND (acct_name = NEW.acct_name));
    INSERT INTO 
      account_audit (acct_id, acct_name, acct_balance, tax_rate) 
      VALUES 
      (
        OLD.acct_id, 
        OLD.acct_name, 
        NEW.acct_balance, 
        OLD.tax_rate
        
        -- valid_from - NOW()!
        -- valid_to DEFAULTs to '2038-01-19' which is what we want for updates to balance 
      );
END;
UPDATE account 
SET acct_balance = acct_balance + 50 WHERE acct_name = 'Bill';
SELECT * FROM account_audit
帐户 ID | txn_id | 账户名 | 账户余额 | 税率 | 有效来自 | 有效  
------: | -----: | :-------- | ------------: | --------: | :--------- | :---------
      1 | 1 | 比尔 | 100.00 | 0 | 2021-11-07 | 2021-11-07
      2 | 2 | 本 | 1000.00 | 0 | 2021-11-07 | 2038-01-19
      1 |   | 比尔 | 150.00 | 0 |        | 空值      

db<>在这里摆弄

于 2021-11-07T16:13:34.873 回答
0

在我看来,where 子句

WHERE ((valid_to = '2038-01-19') AND (OLD.acct_name = NEW.acct_name));

对 Ben 和 Bill 都有效。所以它会为他们两个更新。

一个解决方案可能是将其稍微更改为:

WHERE ((valid_to = '2038-01-19') AND (acct_name = OLD.acct_name));

于 2021-11-07T16:17:42.813 回答