【问题标题】:Trying to write a trigger in mySQL 5.6 to write out to another table after UPDATE尝试在 mySQL 5.6 中编写触发器以在 UPDATE 后写入另一个表
【发布时间】:2017-11-02 21:36:52
【问题描述】:

我正在 mySQL 5.6 中编写触发器,在更新表 A 中的某些字段后,我会将表 A 的更改写入注释表,但是我在第 2 行遇到错误,我很确定它是有点傻:

SET @createNote = 0;
SET @message = 'UPDATED';

IF (NEW.customerEmail != OLD.customerEmail) THEN
    SET @message = CONCAT(@message, '\r\n', OLD.customerEmail, ' -> ', NEW.customerEmail);
    SET @createNote = 1;
END IF;

IF (@createNote) THEN
    INSERT INTO claim_notes SET claimId = NEW.id, message = @message, createdBy = NEW.lastModifiedBy, type = 'system', createdByEmail = NEW.lastModifiedByEmail;
END IF;

我正在使用 Sequel Pro 的触发 UI,所以我的示例中没有正常的分隔符。


错误信息:

MySQL 说:你的 SQL 语法有错误;检查手册 对应于您的 MySQL 服务器版本以获得正确的语法 在 'SET \@message = 'UPDATED' 附近使用;如果(新客户电子邮件!= OLD.customerEmail) THEN SET' 在第 2 行

【问题讨论】:

  • 确切的错误信息是什么?
  • @aendeerei MySQL 说:你的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以在 'SET \@message = 'UPDATED'; 附近使用正确的语法; IF (NEW.customerEmail != OLD.customerEmail) THEN SET' 在第 2 行

标签: mysql triggers


【解决方案1】:

在“更新”周围使用撇号而不是引号

【讨论】:

  • 这不会改变任何事情。
【解决方案2】:

因为触发器是多个语句,所以我需要用BEGIN END 包装它。我没有意识到 Sequel Pro 没有自动包装通过 UI 创建的触发器。

BEGIN

    SET @createNote = 0;
    SET @message = 'UPDATED';

    IF (NEW.customerEmail != OLD.customerEmail) THEN
        SET @message = CONCAT(@message, '\r\n', OLD.customerEmail, ' -> ', NEW.customerEmail);
        SET @createNote = 1;
    END IF;

    IF (@createNote) THEN
        INSERT INTO claim_notes SET claimId = NEW.id, message = @message, createdBy = NEW.lastModifiedBy, type = 'system', createdByEmail = NEW.lastModifiedByEmail;
    END IF;

END;

我将根据@BillKarwin 的回答修改我的变量声明。

【讨论】:

  • 太好了,很高兴您发现了错误。是的,触发器主体必须是单个语句或单个 BEGIN/END 块。 CREATE TRIGGER 上的文档是 MySQL 手册中最被忽视的部分之一。一个例子都没有!
  • 确实! :-) 做得好!请不要忘记接受您自己的答案,以便其他用户从解决方案中受益。祝你好运。
【解决方案3】:

在我将智能引号更改为单引号后,您的语句才能正常工作。

CREATE TRIGGER TestTrigger AFTER UPDATE ON MyTable FOR EACH ROW
BEGIN
  SET @createNote = 0;
  SET @message = "UPDATED";
  IF (NEW.customerEmail != OLD.customerEmail) THEN
    SET @message := CONCAT(@message, '\r\n', OLD.customerEmail, ' -> ', NEW.customerEmail);
    SET @createNote := 1;
  END IF;
  IF (@createNote) THEN
    INSERT INTO claim_notes SET claimId = NEW.id, message = @message, createdBy = NEW.lastModifiedBy, type = 'system', createdByEmail = NEW.lastModifiedByEmail;
  END IF;
END

请注意,这些是智能引号:‘’ 它们在我所知道的任何编码语言中都没有用。

这些是直接的单引号:'' 它们用于 SQL 中的字符串文字和日期文字。

其他一些建议:

  • 对所有字符串使用直单引号。
  • 使用局部变量而不是会话变量。
  • 您不需要:= 进行赋值,除非您在表达式中执行此操作。只需将 = 用于常规的 SET 语句即可。

所以我会这样写这个触发器:

CREATE TRIGGER TestTrigger AFTER UPDATE ON MyTable FOR EACH ROW
BEGIN
  DECLARE _createNote INT DEFAULT 0;
  DECLARE _message VARCHAR(255) DEFAULT 'UPDATED';
  IF (NEW.customerEmail != OLD.customerEmail) THEN
    SET _message = CONCAT(message, '\r\n', OLD.customerEmail, ' -> ', NEW.customerEmail);
    SET _createNote = 1;
  END IF;
  IF (_createNote) THEN
    INSERT INTO claim_notes SET claimId = NEW.id, message = _message, createdBy = NEW.lastModifiedBy, type = 'system', createdByEmail = NEW.lastModifiedByEmail;
  END IF;
END

【讨论】:

  • 很抱歉,如果我的编辑在您查看之前没有出现,智能引号是我的一些复制粘贴操作的副产品。我还从代码中删除了:=。您的回答确实告诉我我做错了什么;我之前编写的触发器被包裹在一个包含的IF 中,所以它们本质上是单个语句。我需要用BEGIN END; 包装代码
猜你喜欢
  • 2011-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多