MariaDB 触发器在同一张表上执行 UPDATE 和 INSERT
Posted
技术标签:
【中文标题】MariaDB 触发器在同一张表上执行 UPDATE 和 INSERT【英文标题】:MariaDB trigger to perform an UPDATE and then an INSERT on the same table 【发布时间】:2021-12-20 17:43:36 【问题描述】:我目前有一个account
表和一个account_audit
表(所有代码都可以在小提琴here 上找到)。
我有两个触发器,它们根据插入到帐户表中的数据将记录插入到 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
(今天)和新记录 @987654331 @ 今天到 valid_to
在 2038 年(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
,我尝试将更新更改为使用acct_id 而不是名称-没有任何效果。我尝试交换OLD。和新的。订购 - 在更新之前或之后尝试 - 我真的疯了!
如何重写触发器以仅更新其帐户的人而不是所有帐户的 account_audit 表 - 也就是说,仅更新 Bill 的帐户而不是 Ben 的帐户? p>
我知道临时表功能 - 我不想使用它,因为这是为了研究,我必须使用触发器!
小提琴是here。
【问题讨论】:
【参考方案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';
帐户 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 | 空 | 空SELECT * FROM account_audit
db小提琴here
【讨论】:
【参考方案2】:在我看来,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));
【讨论】:
WHERE ((valid_to = '2038-01-19') AND (acct_name = OLD.acct_name));
- 那got it!如果您愿意将其写下来,我会很乐意将其标记为正确并投赞成票。简单的错误,但我是 mysql/MariaDB 触发器的初学者...
非常感谢!我现在已经更新了。这是一个很好的问题。当您身处险境时,很难透过树木看到森林。
我将您的答案标记为正确 - 也尝试过投票 - 没有 15 个代表。然而,但它说我的投票被记录了 - 所以希望你能得到更多的分数!以上是关于MariaDB 触发器在同一张表上执行 UPDATE 和 INSERT的主要内容,如果未能解决你的问题,请参考以下文章