简体   繁体   English

创建MYSQL触发器语句时错误代码:1064

[英]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 $$

Update 更新资料

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;

Update 2 更新2

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 :) 任何建议将不胜感激:)

Accepted Answer: 接受的答案:

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.) 该语法看起来有效,但我无法验证其语义,例如skuqty是否为有效的列引用,等等。)

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM