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

时间:2019-02-13 16:11:19

标签: mysql sql triggers

我正在尝试创建一个触发器,将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;

更新2

查询数据是从这样的表单中收集的:

<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')

2 个答案:

答案 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子句(以更新表中的每一行)。

该语法看起来有效,但是我无法验证其语义,例如skuqty是否为有效的列引用,等等。

我个人会这样执行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的正常行为。