如何在触发器中使用 Case-When 和 Update?(我的代码出错)

How to use Case-When and Update in Trigger?(Error in my code)

我试图在下面创建触发器,但出现错误。 我可以在触发器中使用更新或使用 'case when' 吗? 请帮我解决这里的问题。

代码说明: 我想在插入或更新后更新我现有的行。 不要更改 'FUSDate1' 或 'FUSDate2' 如果我没有向 'FUSDate1' 或 'FUSDate2'

添加任何内容

将 FUSDate 更新为新的或插入的如果我更新或插入数据到 FUSDate

代码:

delimiter //

create trigger SafetyCertificationTRG
after insert on SafetyCertification
for each row
begin
    case when (FUSDate1='' or FUZDate1 is NULL) then (FUZDate1=OLD.FUSDate1)  else (update SafetyCertification set FUZDate1=NEW.FUSDate1) end;
    case when (FUSDate2='' or FUZDate2 is NULL) then (FUZDate2=NEW.FUSDate2) else (update SafetyCertification set FUZDate2=NEW.FUSDate2) end;
end //

delimiter ;

编辑:我将在此处添加一些信息以使问题更清楚。

我有一列作为 FUS,只能得到这 3 个值:('FUS1'、'FUS2' 和 'FUS3') 我还有 3 个其他列:FUSDate1、FUSDate2、FUSDate3。

我想根据FUS的用户用户选择将当前日期保存到FUSDate1或FUSDate2或FUSDate3。 (他们在同一个Table)

我使用了提供的答案并将其更改为此,但我无法执行上述操作。

代码:此代码仅适用于 FUS1 和 FUSDate1

delimiter //

CREATE TRIGGER  SafetyCertification_bu
BEFORE UPDATE ON   SafetyCertification
FOR EACH ROW
BEGIN
   -- detect a change made to a value in col
   IF OLD.FUS <=> NEW.FUS THEN
      -- value of col is not changed, so do nothing
      DO 0;
   ELSE
      -- we detected a new value was assigned to col
      IF OLD.FUS ='%FUS1%' THEN
         -- we can override the new value, keep it the same
         SET NEW.FUSDate1 = CURDATE();
      END IF;
   END IF;
END //

delimiter ;

另一个我希望完成我的工作但仍然有问题的代码,不会像上面的代码那样更新:

delimiter //

CREATE TRIGGER  SafetyCertification_bu
BEFORE INSERT ON   SafetyCertification
FOR EACH ROW
BEGIN
    IF NEW.FUS='%FUS1%' THEN
         SET new.FUSDate1=MD5(CURDATE());
    END IF;

END //

delimiter ;

更新 3:

当我更新或插入任何数据时,答案中提供的第三个代码不会向 FUSdate1、2 和 3 添加任何内容。

代码

DELIMITER $$

CREATE TRIGGER  SafetyCertification_bu
BEFORE UPDATE ON   SafetyCertification
FOR EACH ROW
BEGIN
   -- set one of the `fusdateN` columns to current date
   -- which column to set depends on the value assigned to `fus` 
   IF NEW.fus = 'FUS1' THEN
      SET NEW.fusdate1 = DATE(NOW());
   ELSEIF NEW.fus = 'FUS2' THEN
      SET NEW.fusdate2 = DATE(NOW());
   ELSEIF NEW.fus = 'FUS3' THEN
      SET NEW.fusdate3 = DATE(NOW());
   END IF;
END$$

DELIMITER ;

我遇到了同样的问题,我使用了两个触发器, 第一个触发器将数据发送到另一个 table,因此现在您可以创建另一个触发器将此数据发送到第一个 table。我认为这是低性能,但这是我达到它的唯一方法。我希望其他人有其他解决方案。

一些注意事项:

触发器不能针对触发触发器的 table 发出更新,这是被禁止的。

不合格的引用(例如 FUSDate1FUZDate1)无效。这些引用没有解决任何问题。

OLD.FUSDate1 的引用在 AFTER INSERT 触发器的上下文中无效。在 UPDATE 触发器中,OLD.col 指更新前 col 的值。

表达式 (FUZDate1=OLD.FUSDate1) 不是赋值,它是一个比较 return 0、1 或 NULL。

如果我们想在 UPDATEINSERT 上触发,则需要两个单独的触发器。

如果我们要修改当前行的内容,可以使用BEFORE触发器代替AFTER


我想在插入或更新后更新现有行。

在插入或更新行之前应用更改会容易得多。我们可以通过在 BEFORE INSERTBEFORE UPDATE 触发器的赋值中引用 NEW.col 来为列 col 赋值。例如:

 SET NEW.col = expr;

不要更改 FUSDate1FUSDate2 如果我没有向 FUSDate1FUSDate2 添加任何内容

这看起来很简单。只是不要对 NEW.FUSDate1NEW.FUSDate2.

进行任何分配

将FUSDate更新为新的或插入的如果我更新或插入数据到FUSDate

提议的触发器示例包含对 FUZDate1FUZDate2 的引用,但规范中未提及这些列。规范令人困惑。

UPDATE 语句将为列赋值,不需要触发器来执行此操作。 INSERT 语句可以为列赋值,同样,不需要触发器。


规格不明确。提供示例起始状态(table 中的行)和示例 INSERT 或 UPDATE 语句,以及语句执行后的所需状态将大大有助于阐明要求。

防止将新值分配给特定列的 BEFORE UPDATE 触发器的演示:

DELIMITER $$

CREATE TRIGGER  SafetyCertification_bu
BEFORE UPDATE ON   SafetyCertification
FOR EACH ROW
BEGIN
   -- detect a change made to a value in col
   IF OLD.col <=> NEW.col THEN
      -- value of col is not changed, so do nothing
      DO 0;
   ELSE
      -- we detected a new value was assigned to col
      IF OLD.col IS NOT NULL THEN
         -- we can override the new value, keep it the same
         SET NEW.col = OLD.col;
      END IF;
   END IF;
END$$

DELIMITER ;

对于这个示例触发器的实现,我们不一定需要那么多 IF 条件;包含这些内容是为了演示我们可以执行的一些检查,我们如何引用 col 的现有值以及分配给 col.

的新值

跟进

根据问题中的更新信息,这里有一个满足规范的BEFORE UPDATE触发器示例。

这是针对 UPDATE 操作。要使用 INSERT 语句获得相同的行为,需要重复此触发器定义,用 BEFORE INSERT 代替 BEFORE UPDATE

(我将使用名称 _bu 表示更新前触发器,_bi 表示插入前触发器。)

DELIMITER $$

CREATE TRIGGER  SafetyCertification_bu
BEFORE UPDATE ON   SafetyCertification
FOR EACH ROW
BEGIN
   -- set one of the `fusdateN` columns to current date
   -- which column to set depends on the value assigned to `fus` 
   IF NEW.fus = 'FUS1' THEN
      SET NEW.fusdate1 = DATE(NOW());
   ELSEIF NEW.fus = 'FUS2' THEN
      SET NEW.fusdate2 = DATE(NOW());
   ELSEIF NEW.fus = 'FUS3' THEN
      SET NEW.fusdate3 = DATE(NOW());
   END IF;
END$$

DELIMITER ;

第二次跟进

回答有关在 MySQL 存储程序的上下文中使用 CASE WHEN 语句的问题...

我们可以实现示例触发器(在此答案的正上方)用 CASE 语句的两种形式之一替换 IF-THEM

任一

   CASE 
      WHEN NEW.fus = 'FUS1' THEN
         SET NEW.fusdate1 = DATE(NOW());
      WHEN NEW.fus = 'FUS2' THEN
         SET NEW.fusdate2 = DATE(NOW());
      WHEN NEW.fus = 'FUS3' THEN
         SET NEW.fusdate3 = DATE(NOW());
   END CASE;

-或-

   CASE NEW.fus 
      WHEN 'FUS1' THEN
         SET NEW.fusdate1 = DATE(NOW());
      WHEN 'FUS2' THEN
         SET NEW.fusdate2 = DATE(NOW());
      WHEN 'FUS3' THEN
         SET NEW.fusdate3 = DATE(NOW());
   END CASE;

注意

CASE 语句在 MySQL 个存储程序中可用;在存储程序之外,它 不是 有效的 SQL 语句。

此外,我们不应将此 CASE 语句 与 CASE 表达式 混淆。 CASE 表达式 在 SQL 语句的上下文中有效,例如 SELECTUPDATE 语句。

演示

"I examined the Trigger, But unfortunately does not save anything in fusDates."

@Christiano:这是一个简单的演示

创建table

CREATE TABLE `safety_certification`
( id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
, fus       VARCHAR(5)
, fusdate1  DATE
, fusdate2  DATE
, fusdate3  DATE
) ENGINE=INNODB
;

使用演示行table填充

INSERT INTO `safety_certification` (id, fus, fusdate1, fusdate2, fusdate3) VALUES
( 1, '', NULL, NULL, NULL)
,( 2, '', NULL, NULL, NULL)
,( 3, '', NULL, NULL, NULL)
,( 4, '', NULL, NULL, NULL)
,( 5, '', NULL, NULL, NULL)
;

创建触发器

DELIMITER $$

CREATE TRIGGER  `safety_certification_bu`
BEFORE UPDATE ON   `safety_certification`
FOR EACH ROW
BEGIN
   -- set one of the `fusdateN` columns to current date
   -- which column to set depends on the value assigned to `fus`
   IF NEW.fus = 'FUS1' THEN
      SET NEW.fusdate1 = DATE(NOW());
   ELSEIF NEW.fus = 'FUS2' THEN
      SET NEW.fusdate2 = DATE(NOW());
   ELSEIF NEW.fus = 'FUS3' THEN
      SET NEW.fusdate3 = DATE(NOW());
   END IF;
END$$

DELIMITER ;

更新将在我们刚刚定义的更新触发器之前执行

UPDATE `safety_certification` sc SET sc.fus = 'FUS1' WHERE sc.id = 1 ;
UPDATE `safety_certification` sc SET sc.fus = 'FUS2' WHERE sc.id = 2 ;
UPDATE `safety_certification` sc SET sc.fus = 'FUS3' WHERE sc.id = 3 ;
UPDATE `safety_certification` sc SET sc.fus = 'FUS4' WHERE sc.id = 4 ;

显示table

的内容
SELECT * FROM `safety_certification`;

returns:

    id  fus     fusdate1    fusdate2    fusdate3
------  ------  ----------  ----------  ------------
     1  FUS1    2018-05-04  (NULL)      (NULL)
     2  FUS2    (NULL)      2018-05-04  (NULL)
     3  FUS3    (NULL)      (NULL)      2018-05-04
     4  FUS4    (NULL)      (NULL)      (NULL)
     5          (NULL)      (NULL)      (NULL)

当一些特定的值被分配给 fus 时,触发器似乎正在按照规范填充 fusdate1、fusdate2 和 fusdate3 列