我正在尝试创建一个触发器,将input_qty
的值添加到shelf_qty
的值,然后将input_qty
= 0设置。
这是我的尝试:
DELIMITER $$
CREATE TRIGGER inventory_update
AFTER UPDATE ON `products`
FOR EACH ROW
IF OLD.`input_qty` > 0 THEN
BEGIN
DECLARE new_shelf_qty INT(11);
SET new_shelf_qty := OLD.`input_qty` + OLD.`shelf_qty`;
UPDATE `products` SET `input_qty` = 0, `shelf_qty` = new_shelf_qty;
END $$
DELIMITER;
通过修改戈登的答案,我设法使它“起作用”,但是触发器创建了一个无限循环,并且不更新任何内容。
DELIMITER $$
CREATE TRIGGER inventory_update
BEFORE UPDATE ON `products`
FOR EACH ROW
BEGIN
DECLARE new_shelf_qty INT(11);
IF OLD.`input_qty` > 0 THEN
SET new_shelf_qty = OLD.input_qty + OLD.shelf_qty;
SET new.input_qty = 0;
END IF;
END $$
我会用这样的东西:
UPDATE product t
SET t.shelf_qty = t.shelf_qty + 1
WHERE t.id = 1 ;
但是问题是我的服务器上组装的sql查询看起来像这样:
UPDATE `products`
SET `qty` = CASE
WHEN `sku` = 'foo' THEN `qty` + qty1
WHEN `sku` = 'bar' THEN `qty` + qty2
...
END;
查询数据是从这样的表单中收集的:
<input id="sku1" type="number">
<input id="sku2" type="number">
<input id="sku3" type="number">
...
<input type="submit" value="Save">
print(POST body) //[{sku1:qty1}, {sku2:qty2}, {sku3:qty3}...]
表单仅在进行更改时提交项目/数量对象列表。 “数量”字段是要增加库存的数量,而不是实际数量。
据我所知,THEN
之后的操作是不允许的,而我想到的通过1个查询实现此操作的唯一方法是使用我尝试的触发器(这显然行不通)。任何建议将不胜感激:)
这对我有用:
UPDATE products t
SET t.qty = t.qty
+ CASE t.sku
WHEN 'foo' THEN 1
WHEN 'bar' THEN 2
ELSE 0
END
WHERE t.sku IN ('foo','bar')
答案 0 :(得分:1)
这听起来真的很奇怪-您有一列始终为0?但是,如果要将当前行的值设置为0
,请使用BEFORE UPDATE
触发器:
DELIMITER $$
CREATE TRIGGER inventory_update
BEFORE UPDATE ON `products`
FOR EACH ROW
BEGIN
IF OLD.`input_qty` > 0 THEN
DECLARE new_shelf_qty INT(11);
SET new_shelf_qty = OLD.input_qty + OLD.shelf_qty;
SET new.input_qty = 0;
END IF;
END $$
DELIMITER;
答案 1 :(得分:1)
TRIGGER无法对触发语句中引用的表执行DML操作。 《 MySQL参考手册》中记录了该限制。
换句话说,UPDATE ON product
触发器的主体无法针对UPDATE
表发出product
语句。
这是触发器定义的错误之一。
除此之外,还有一些语法问题。 FOR EACH ROW
之后应加上BEGIN
关键字(该例外是作为单个语句的触发器。)
IF
语句应以END IF
(而不仅仅是END
)结束
但是我们必须在这里重新考虑整个方法,而不仅仅是修复语法。
也许通过示例,让我们了解我们正在努力实现的目标。
假设我们有表product
id mfr input_qty shelf_qty
-- --- --------- ---------
1 fee 3 39
2 fi 0 7
发出以下语句后,表的预期状态是什么?
UPDATE product SET mfr = 'fo' WHERE id = 1 ;
UPDATE product SET input_qty = 4 WHERE id = 2 ;
也就是说,如果不触发任何触发器,我们就可以预测这些语句的结果。但是触发器应该如何影响行为,修改这些语句的结果?我们需要触发器来完成什么?
UPDATE product SET input_qty = 5 , shelf_quantity = 11 WHERE id = 1;
如果没有规范,我们将无法编写代码来执行某些操作;我们需要进行一些测试,以验证所编写的代码是否正在执行预期的工作。否则,我们只是使用SQL语法,希望事情能以某种方式解决。
我们要完成什么?
如果我们想“增加” shelf_qty
某个提供的值,那么规范模式将是这样的(没有任何触发器):
UPDATE product t
SET t.shelf_qty = t.shelf_qty + 1
WHERE t.id = 1 ;
我们引用shelf_qty
列的当前值,并为其添加1,然后将该新值分配回shelf_qty
列。
更新1
可以在THEN
表达式中的CASE
关键字之后使用表达式。允许在表达式中进行加法运算。
为“汇编的SQL查询”显示的语法(有效;我们希望END
前面有一个ELSE数量,因为执行一个命令有点奇怪(不是非法的,只是不寻常的) UPDATE
,不带WHERE
子句(以更新表中的每一行)。
该语法看起来有效,但是我无法验证其语义,例如sku
和qty
是否为有效的列引用,等等。
我个人会这样执行UPDATE操作(添加到问题中):
UPDATE product t
SET t.qty = t.qty
+ CASE t.sku
WHEN 'fee' THEN 1
WHEN 'fi' THEN 2
ELSE 0
END
但是,当qty
未列出时,我不确定要分配给sku
的什么。我的假设是我们将这些行上的qty
值保持不变。我只是不了解此用例的触发器的好处,
更新2
“据我所知,不允许在THEN之后进行操作” [在CASE表达式中]
这取决于操作的含义。 CASE表达式的语法为:
CASE WHEN expr1 THEN expr2 WHEN expr3 THEN expr4 ... ELSE expr5 END
或:
CASE expr1 WHEN expr2 THEN expr3 WHEN expr4 THEN expr5 ... ELSE expr6 END
exprN
是表达式。表达式中可以使用加法运算。
我们可以这样编写更新:
UPDATE products t
SET t.qty = CASE
WHEN t.sku = 'foo' THEN t.qty + 1
WHEN t.sku = 'bar' THEN t.qty + 2
ELSE t.qty
END
WHERE t.sku IN ('foo','bar')
但是我们将通过这样表达来使将来的读者更容易辨别我们的意图
UPDATE products t
SET t.qty = t.qty
+ CASE t.sku
WHEN 'foo' THEN 1
WHEN 'bar' THEN 2
ELSE 0
END
WHERE t.sku IN ('foo','bar')
概括起来很简单。应用程序使用命名占位符生成的SQL文本如下所示:
UPDATE products t
SET t.qty = t.qty
+ CASE t.sku
WHEN :sku1 THEN :qty1
WHEN :sku2 THEN :qty2
WHEN :sku3 THEN :qty3
ELSE 0
END
WHERE t.sku IN ( :wsku1 , :wsku2 , :wsku3 )
或使用位置占位符,如下所示:
UPDATE products t
SET t.qty = t.qty
+ CASE t.sku
WHEN ? THEN ?
WHEN ? THEN ?
WHEN ? THEN ?
ELSE 0
END
WHERE t.sku IN ( ? , ? , ? )
我们可以看到如何针对可变数量的{sku:qty}
组合动态扩展该语句
跟进
这一切都不建议使用TRIGGER。这不是处理需求的最佳方法。但是,要回答所提出的问题...
如果必须使用触发器,则给出:
product
id sku input_qty shelf_qty
-- --- --------- ---------
3 fo 0 41
4 fum 0 11
和
UPDATE product t
SET t.input_qty = CASE t.sku
WHEN 'fo' THEN 1
WHEN 'fum' THEN 2
ELSE 0
END
WHERE t.sku IN ('fo','fum')
然后定义此触发器:
DELIMITER $$
CREATE TRIGGER product_bu
BEFORE UPDATE ON product
FOR EACH ROW
BEGIN
IF NEW.input_qty > 0 THEN
-- add provided value of input_qty to shelf_qty
SET NEW.shelf_qty = HEW.shelf_qty + NEW.input_qty;
-- set input_qty to zero
SET NEW.input_qty = 0;
END IF;
END$$
预期结果将是:
product
id sku input_qty shelf_qty
-- --- --------- ---------
3 fo 0 42
4 fum 0 13
但是对我来说,使用触发器来执行此操作没有任何意义。我没有看到好处。似乎不必要地且令人困惑地修改了UPDATE
的正常行为。