创建MYSQL触发器语句时出错代码:1064
我正在尝试创建一个触发器,将创建MYSQL触发器语句时出错代码:1064,mysql,sql,triggers,Mysql,Sql,Triggers,我正在尝试创建一个触发器,将input\u qty的值与shelf\u qty的值相加,然后将input\u 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 :=
input\u qty
的值与shelf\u qty
的值相加,然后将input\u 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;
通过修改Gordon的答案,我成功地使它“起作用”,但触发器创建了一个无限循环,并且不会更新任何内容
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 ;
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}...]
UPDATE product t
SET t.qty = t.qty
+ CASE t.sku
WHEN 'fee' THEN 1
WHEN 'fi' THEN 2
ELSE 0
END
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 ( ? , ? , ? )
但问题是,我的服务器上组装的sql查询如下所示:
UPDATE product t
SET t.shelf_qty = t.shelf_qty + 1
WHERE t.id = 1 ;
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}...]
UPDATE product t
SET t.qty = t.qty
+ CASE t.sku
WHEN 'fee' THEN 1
WHEN 'fi' THEN 2
ELSE 0
END
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 ( ? , ? , ? )
更新2
查询的数据从如下表单中收集:
UPDATE product t
SET t.shelf_qty = t.shelf_qty + 1
WHERE t.id = 1 ;
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}...]
UPDATE product t
SET t.qty = t.qty
+ CASE t.sku
WHEN 'fee' THEN 1
WHEN 'fi' THEN 2
ELSE 0
END
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 ( ? , ? , ? )
这听起来真的很奇怪——你有一个列总是0?。但是,如果希望将当前行中的值设置为0
,则在更新之前使用触发器:
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;
这听起来真的很奇怪——你有一个列总是0?。但是,如果希望将当前行中的值设置为0
,则在更新之前使用触发器:
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;
触发器无法对触发器语句中引用的表执行DML操作。MySQL参考手册中记录了此限制
换句话说:updateonproduct
触发器的主体不能针对product
表发出UPDATE
语句
这是触发器定义的错误之一
除此之外,还有一些语法问题。每行的后面应该跟有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语法,希望事情能以某种方式解决
我们想要实现什么
UPDATE product SET input_qty = 5 , shelf_quantity = 11 WHERE id = 1;
如果我们想通过提供的某个值“增加”货架数量
,那么标准模式应该是这样的(没有任何触发):
我们引用货架数量
列的当前值,并向其中添加1,然后将该新值分配回货架数量
列
更新1
表达式可以在大小写
表达式中的然后
关键字后面使用。允许在表达式中进行加法运算
为“组合sql查询”(assembled sql query)显示的语法是有效的;我们希望在结束
之前有一个ELSE数量,因为在没有WHERE
子句(更新表中的每一行)的情况下执行更新
有点奇怪(不是非法的,只是不寻常)
语法看起来有效,但我无法验证语义,例如sku
和qty
是否是有效的列引用,等等。)
就我个人而言,我会这样做更新操作(添加到问题中):
UPDATE product t
SET t.shelf_qty = t.shelf_qty + 1
WHERE t.id = 1 ;
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}...]
UPDATE product t
SET t.qty = t.qty
+ CASE t.sku
WHEN 'fee' THEN 1
WHEN 'fi' THEN 2
ELSE 0
END
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
什么。我的假设是,我们将保持这些行上的qty
值不变。我只是不理解这个用例中触发器的好处
更新2
“据我所知,之后的操作是不允许的”[在CASE表达式中]
这取决于操作的含义。CASE表达式的语法为:
CASE WHEN expr1 THEN expr2 WHEN expr3 THEN expr4 ... ELSE expr5 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 product t
SET t.shelf_qty = t.shelf_qty + 1
WHERE t.id = 1 ;
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}...]
UPDATE product t
SET t.qty = t.qty
+ CASE t.sku
WHEN 'fee' THEN 1
WHEN 'fi' THEN 2
ELSE 0
END
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 ( ? , ? , ? )
或者使用位置占位符,如下所示:
UPDATE product t
SET t.shelf_qty = t.shelf_qty + 1
WHERE t.id = 1 ;
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}...]
UPDATE product t
SET t.qty = t.qty
+ CASE t.sku
WHEN 'fee' THEN 1
WHEN 'fi' THEN 2
ELSE 0
END
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}
组合动态扩展
跟进
这一切都是使用触发器解除提示的。这不是处理需求的最佳方式。但是,为了回答被问到的问题
如果我们必须使用触发器,给定:
product
id sku input_qty shelf_qty
-- --- --------- ---------
3 fo 0 41
4 fum 0 11
及
然后定义此触发器:
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
但我觉得用扳机做这件事没有意义。我没有看到好处。它似乎不必要地、令人困惑地修改了更新的正常行为触发器无法对触发器语句中引用的表执行DML操作。MySQL参考手册中记录了此限制
换句话说:updateonproduct
触发器的主体不能针对product
表发出UPDATE
语句
这是触发器定义的错误之一
除此之外,还有一些语法问题。每行的后面应该跟有BEGIN
关键字(例外情况是触发器是一条语句)
IF
语句应以END IF
结束(不仅仅是END
)
但我们必须重新思考整个方法,而不仅仅是修改语法
我们走吧