[英]Error Code: 1064 when creating MYSQL Trigger Statement
I'm trying to make a trigger that adds the value of input_qty
to the value of shelf_qty
, then sets input_qty
= 0. 我正在尝试创建一个将
input_qty
的值添加到input_qty
的值的shelf_qty
,然后将input_qty
设置为0。
This is my attempt: 这是我的尝试:
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;
I managed to get this to "work" by modifying Gordon's answer, but the trigger creates an infinite loop and doesn't update anything. 我设法通过修改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 $$
I would use something like this: 我会用这样的东西:
UPDATE product t
SET t.shelf_qty = t.shelf_qty + 1
WHERE t.id = 1 ;
But the problem is that the assembled sql query on my server looks like this: 但是问题是我的服务器上组装的sql查询看起来像这样:
UPDATE `products`
SET `qty` = CASE
WHEN `sku` = 'foo' THEN `qty` + qty1
WHEN `sku` = 'bar' THEN `qty` + qty2
...
END;
The data for the query is collected from a form like this: 查询数据是从如下形式收集的:
<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}...]
the form only submits a list of item/qty objects when a change was made. 进行更改后,表单仅提交项目/数量对象列表。 The qty field is the amount to increment the inventory by, not the actual qty amount.
数量字段是增加库存量的数量,而不是实际数量。
As far as I know, operations after THEN
aren't allowed and the only way I can think of to implement this with 1 query is with the trigger I attempted (which clearly doesn't work). 据我所知,
THEN
之后的操作是不允许的,而我想到的用1个查询实现此操作的唯一方法是使用我尝试的触发器(这显然行不通)。 Any suggestions would really be appreciated :) 任何建议将不胜感激:)
This worked for me: 这为我工作:
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')
That sounds really weird -- you have a column that will always be 0?. 这听起来真的很奇怪-您的列始终为0? But if you want the set the value in the current row to
0
, then use a BEFORE UPDATE
trigger: 但是,如果要将当前行中的值设置为
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;
A TRIGGER cannot perform DML operations on tables that are referenced in the triggering statement. TRIGGER无法对触发语句中引用的表执行DML操作。 This restriction is documented in the MySQL Reference Manual.
MySQL参考手册中记录了此限制。
To put that another way: the body of an UPDATE ON product
trigger cannot issue an UPDATE
statement against the product
table. 换句话说,
UPDATE ON product
触发器的主体无法针对product
表发出UPDATE
语句。
This is one of the the things wrong with the trigger definition. 这是触发器定义的错误之一。
Beyond that, there's some syntax issues. 除此之外,还有一些语法问题。 The
FOR EACH ROW
should be followed by BEGIN
keyword (the exception to that is a trigger that is a single statement.) 在
FOR EACH ROW
后面应加上BEGIN
关键字(该例外是作为单个语句的触发器。)
An IF
statement should be closed with END IF
(not just END
) IF
语句应使用END IF
(不仅是END
)关闭
But we have to re-think the whole approach here, not just fix the syntax. 但是我们必须在这里重新考虑整个方法,而不仅仅是修复语法。
Let's understand what we're trying to achieve, maybe by way of example. 让我们通过示例来了解我们正在尝试实现的目标。
Let's say we have table product
假设我们有餐桌
product
id mfr input_qty shelf_qty
-- --- --------- ---------
1 fee 3 39
2 fi 0 7
What would be the expected state of the table after we issue these statements: 发出以下语句后,表的预期状态是什么:
UPDATE product SET mfr = 'fo' WHERE id = 1 ;
UPDATE product SET input_qty = 4 WHERE id = 2 ;
That is, we can predict the outcome of these statements if no triggers are fired. 也就是说,如果没有触发任何触发器,我们就可以预测这些语句的结果。 But how are triggers supposed to influence the behavior, modify the results of these statements?
但是触发器应该如何影响行为,修改这些语句的结果? What we are needing the trigger(s) to accomplish?
我们需要触发器来完成什么?
UPDATE product SET input_qty = 5 , shelf_quantity = 11 WHERE id = 1;
We can't write code to do something if we don't have a specification; 如果没有规范,我们将无法编写代码来执行某些操作。 we need to have some tests that we can use to verify that the code we write is doing what it's supposed to be doing.
我们需要进行一些测试,以验证所编写的代码是否正在执行预期的工作。 Otherwise, we're just flinging SQL syntax hoping that things will somehow work out.
否则,我们只是抛出SQL语法,希望事情能以某种方式解决。
What are we trying to accomplish? 我们要完成什么?
If we are wanting to "increment" shelf_qty
by some provided value, the normative pattern would be something like this (without any trigger): 如果我们想通过一些提供的值来“增加”
shelf_qty
,那么规范模式将是这样的(没有任何触发器):
UPDATE product t
SET t.shelf_qty = t.shelf_qty + 1
WHERE t.id = 1 ;
We reference the current value of shelf_qty
column, and add 1 to it, and then assign that new value back to the shelf_qty
column. 我们引用了
shelf_qty
列的当前值,并向其添加1,然后将该新值分配回shelf_qty
列。
Update 1 更新1
An expression can be used following the THEN
keyword in a CASE
expression. 可以在
CASE
表达式中的THEN
关键字之后使用表达式。 An addition operation in an expression is allowed. 允许在表达式中进行加法运算。
The syntax shown for the "assembled sql query" (is valid; we'd hope that there's an ELSE qty before the END
, in that it's a bit odd (not illegal, just unusual) to perform an UPDATE
without a WHERE
clause (to update every row in the table). 显示为“汇编的sql查询”的语法(有效;我们希望在
END
之前有一个ELSE qty,因为在没有WHERE
子句的情况下执行UPDATE
有点奇怪(不是非法的,只是不寻常的)更新表中的每一行)。
The syntax looks valid, but I can't verify the semantics, eg whether sku
and qty
are valid column references, et al.) 该语法看起来有效,但我无法验证其语义,例如
sku
和qty
是否为有效的列引用,等等。)
Personally, I'd do the UPDATE operation (added to the question) like this: 就个人而言,我将执行UPDATE操作(添加到问题中),如下所示:
UPDATE product t
SET t.qty = t.qty
+ CASE t.sku
WHEN 'fee' THEN 1
WHEN 'fi' THEN 2
ELSE 0
END
But I'm not exactly sure what we're supposed to be assigning to qty
when sku
isn't listed. 但是我不确定在未列出
sku
时应分配给qty
。 My assumption is that we would leave the qty
values on those rows unchanged. 我的假设是我们将这些行的
qty
值保持不变。 I'm just not understanding the benefit of a trigger for this use case, 我只是不了解此用例的触发器的好处,
Update 2 更新2
"As far as I know, operations after THEN aren't allowed" [in a CASE expression] “据我所知,不允许在THEN之后进行操作” (在CASE表达式中)
That depends what is meant by operations . 这取决于操作的含义。 Syntax for a CASE expression is:
CASE表达式的语法为:
CASE WHEN expr1 THEN expr2 WHEN expr3 THEN expr4 ... ELSE expr5 END
or: 要么:
CASE expr1 WHEN expr2 THEN expr3 WHEN expr4 THEN expr5 ... ELSE expr6 END
Where exprN
are expressions. 其中
exprN
是表达式。 An addition operation can be used in an expression. 可以在表达式中使用加法运算。
We could write the update like this: 我们可以这样编写更新:
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')
But we would make it easier for a future reader to discern our intent by expressing it like this 但是通过这样表达它,我们将使将来的读者更容易辨别我们的意图
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')
Generalizing that is fairly straightforward. 概括起来很简单。 The SQL text generated by the application using named placeholders would be something like this:
应用程序使用命名占位符生成的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 )
or using positional placeholders, like this: 或使用位置占位符,如下所示:
UPDATE products t
SET t.qty = t.qty
+ CASE t.sku
WHEN ? THEN ?
WHEN ? THEN ?
WHEN ? THEN ?
ELSE 0
END
WHERE t.sku IN ( ? , ? , ? )
We can see how the statement would be extended dynamically for a variable number of {sku:qty}
combinations 我们可以看到如何针对可变数量的
{sku:qty}
组合动态扩展该语句
followup 跟进
This all disrecommends using a TRIGGER. 所有这些都不建议使用TRIGGER。 It's not the best way to handle the requirement.
这不是处理需求的最佳方法。 But, to answer the question that was asked...
但是,要回答所提出的问题...
If we have to use a trigger, given: 如果必须使用触发器,则给出:
product
id sku input_qty shelf_qty
-- --- --------- ---------
3 fo 0 41
4 fum 0 11
and 和
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')
then with this trigger defined: 然后定义此触发器:
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$$
The expected result would be: 预期结果将是:
product
id sku input_qty shelf_qty
-- --- --------- ---------
3 fo 0 42
4 fum 0 13
But it doesn't make sense to me to do this with a trigger. 但是,使用触发器来执行此操作对我来说没有任何意义。 I'm not seeing the benefit.
我没有看到好处。 It just seems to unnecessarily and confusingly modify the normal behavior of an
UPDATE
. 似乎不必要地且令人困惑地修改了
UPDATE
的正常行为。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.