我是新的MySQL和学习触发器。我有2个表,我想要:当已经插入表(detail_transaction)时,另一个表(item)“stock”字段改变。
- “项目”表
| 标识符|姓名|标价|股票|
| - -|- -|- -|- -|
| 一个|物料_A|十五|九百|
| 2个|物料_B|九个|五百个|
- 'detail_transaction'表
| 标识符|id_项目|计数器|总价|
| - -|- -|- -|- -|
| 一个|一个|五个|七十五|
如果在“detail_transaction”表中插入新行,我希望“item”表中具有相同“id”的“stock”字段减少并调整为“detail_transaction”的“count”。例如:我在“detail_transaction”表中插入新行:
| 标识符|id_项目|计数器|总价|
| - -|- -|- -|- -|
| 2个|一个|十| 一百五十个|
我希望将“item”表更新为:
| 标识符|姓名|标价|股票|
| - -|- -|- -|- -|
| 一个|物料_A|十五|八百九十|
| 2个|物料_B|九个|五百个|
我创建了一个触发器来尝试实现我的目的,但是当我尝试在'detail_transaction'中插入新行时,我得到了以下错误:* 无法更新存储函数/触发器中'item'表,因为它已被调用此存储函数/触发器语句使用 *
我的触发器:
DELIMITER $$
CREATE TRIGGER update_stock
AFTER INSERT
ON detail_transaction
FOR EACH ROW
BEGIN
UPDATE item
JOIN detail_transaction ON detail_transaction.id_item = item.id
SET stock = stock - NEW.count
WHERE item.id = NEW.id_item;
END$$
DELIMITER ;
然后,我在detail_transaction表中插入了一行:
INSERT INTO detail_transaction (id, id_item, count, total_price)
VALUES (2, 1, 10, (SELECT price FROM item WHERE item.ID = 1) * 10);
但是我得到了这个错误。我该怎么做才能解决这个问题呢?是不是因为我尝试INSERT时的SELECT部分?谢谢你的回答。
3条答案
按热度按时间mum43rcc1#
首先(且固执己见):触发器很难调试、测试和维护。2包含触发器的系统 * 真的 * 很难调试,因为它们引入了副作用-“我在这个表上做了X,然后Y发生在另一个表上”。3作为一个开发人员,你必须把所有的触发器都记在脑子里,以了解单个语句可能会做什么。
以您的示例为例,您可能在
Item
中的“stock”字段上有一个触发器,用于创建一个采购订单记录,以便在库存福尔斯阈值时补充库存。purchase order
表可能有一个插入触发器,用于在accounts payable
中创建一个记录。该触发器链实现了有效的业务逻辑,其中但是当插入detail_transaction
的操作突然被拒绝,因为产品供应商超出了他们的付款限额时,会导致非常复杂的调试过程。触发器面临的一个挑战是,数据库引擎不希望发生无限循环,也不希望您正在选择的字段的值由于触发器的激发而发生更改。
此外,您不需要该联接-您可以从NEW中获取值。
方法是使用变量:
请参阅fiddle。
理智的人对如何使用触发器意见不一--但我会建议使用触发器来计算派生值--“给定物品的总库存”或“交易的总价”--通常是个坏主意。你实际上是在复制数据--物品的总库存水平既是交易的总和,* 又是 * 行中的属性。总价既是“价格 * 数量”,* 和 * 一行中的属性。如果有人对total_price或total_stock执行update语句(有意或作为bug的一部分)会发生什么?哪个值是正确的?
6bc51xsx2#
您不应混用insert..values和insert..select我会将插入重写为
尽管我的选择是插入前触发器
带有插入件
您的after insert发布失败,因为您使用了多表更新来调用触发触发器的表,这是不允许的,此问题的解决方案见上一个答案。
qaxu7uf23#
| 标识符|姓名|标价|股票|
| - -|- -|- -|- -|
| 一个|物料_A|十五|九百|
| 2个|物料_B|九个|五百个|
| 标识符|id_项目|计数器|总价|
| - -|- -|- -|- -|
| 一个|一个|五个|七十五|
第一个
| 标识符|id_项目|计数器|总价|
| - -|- -|- -|- -|
| 一个|一个|五个|七十五|
| 2个|一个|10个|一百五十个|
| 标识符|姓名|标价|股票|
| - -|- -|- -|- -|
| 一个|物料_A|十五|八百九十|
| 2个|物料_B|九个|五百个|
fiddle
每个触发器只包含一个语句,所以不需要BEGIN-END和к DELIMITER命令。