简体   繁体   English

MySQL 更新触发器后受影响的行数条件

[英]MySQL after update trigger with number of affected rows condition

In MySQL, I want to create a trigger with AFTER UPDATE triggering event for my user table.在 MySQL 中,我想为我的user表创建一个带有AFTER UPDATE触发事件的触发器。

In next, I have a table named user_log which is use to store the modifications that occurred on the parent table user after any update commands.接下来,我有一个名为user_log的表,用于存储在执行任何更新命令后对父表user进行的修改。

So, data in user_log table need be as follows:所以, user_log表中的数据需要如下:

select * from user_log;
+--------+---------+----------------------------+---------------+----------------+---------------------+------+
| log_id | user_id | action                     | old_data      | new_data       | changed_date        | read |
+--------+---------+----------------------------+---------------+----------------+---------------------+------+
|      1 |      10 | Changed yyy's name         | yyy           | xxx            | 2022-06-20 14:06:56 | no   |
|      2 |      10 | Changed xxx's address      | No.111,       | No.112,        | 2022-06-20 19:07:38 | no   |
|      3 |      10 | Changed xxx's city         | Old City Name | New City Name  | 2022-06-20 19:07:38 | no   |
|      4 |      10 | Changed xxx's phone number | 011-5000000   | 011-4000000    | 2022-06-20 19:07:38 | no   |
+--------+---------+----------------------------+---------------+----------------+---------------------+------+

As you can see from the data in the table above, it will update several columns at once.从上表中的数据可以看出,它会同时更新几列。 So I created my triger as follows, and its working for me.所以我按如下方式创建了触发器,它对我有用。

DELIMITER $$
DROP TRIGGER IF EXISTS `user_log` ;
$$
CREATE TRIGGER `user_log`
  AFTER UPDATE ON `user` 
  FOR EACH ROW
BEGIN

  IF OLD.name <> NEW.name THEN
    INSERT INTO user_log (user_id,action,old_data,new_data)
    VALUES(
      NEW.user_id
    , CASE
        WHEN (NEW.name <> OLD.name)
          THEN CONCAT('Changed ', OLD.name, "'s ", 'name')
          ELSE ''
        END 
    , CASE WHEN (NEW.name <> OLD.name) THEN OLD.name ELSE '' END 
    , CASE WHEN (NEW.name <> OLD.name) THEN NEW.name ELSE '' END  
    );
  END IF;

  IF OLD.address <> NEW.address THEN
    INSERT INTO user_log (user_id,action,old_data,new_data)
    VALUES(
      NEW.user_id
    , CASE
        WHEN (NEW.address <> OLD.address)
          THEN CONCAT('Changed ', OLD.name, "'s ", 'address')    
          ELSE ''
        END 
    , CASE WHEN (NEW.address <> OLD.address) THEN OLD.address ELSE '' END 
    , CASE WHEN (NEW.address <> OLD.address) THEN NEW.address ELSE '' END  
    );
  END IF;

  IF OLD.city <> NEW.city THEN
    INSERT INTO user_log (user_id,action,old_data,new_data)
    VALUES(
      NEW.user_id
    , CASE
        WHEN (NEW.city <> OLD.city)
          THEN CONCAT('Changed ', OLD.name, "'s ", 'city')   
          ELSE ''
        END 
    , CASE WHEN (NEW.city <> OLD.city) THEN OLD.city ELSE '' END 
    , CASE WHEN (NEW.city <> OLD.city) THEN NEW.city ELSE '' END  
    );
  END IF;

  IF OLD.phone <> NEW.phone THEN
    INSERT INTO user_log (user_id,action,old_data,new_data)
    VALUES(
      NEW.user_id
    , CASE
        WHEN (NEW.phone <> OLD.phone)
          THEN CONCAT('Changed ', OLD.name, "'s ", 'phone number')    
          ELSE ''
        END 
    , CASE WHEN (NEW.phone <> OLD.phone) THEN OLD.phone ELSE '' END 
    , CASE WHEN (NEW.phone <> OLD.phone) THEN NEW.phone ELSE '' END  
    );
  END IF;

END$$
DELIMITER ;

My problem is, I have a lot more columns in the user table.我的问题是,我在用户表中有更多的列。 Like I said, all columns or several of them are updated at once.就像我说的,所有专栏或其中的几个专栏都会立即更新。

In that case I have to add a large amount of INSERT query to my trigger.在这种情况下,我必须向我的触发器添加大量 INSERT 查询。 So here I would like to know if there is another suitable way to do this.所以在这里我想知道是否有另一种合适的方法来做到这一点。

I also tried it in this way.我也是这样试的。 But its working only for one column.但它只适用于一列。

DROP TRIGGER IF EXISTS `user_log`; 
CREATE TRIGGER IF NOT EXISTS `user_log`
  AFTER UPDATE ON user
  FOR EACH ROW
  INSERT INTO user_log (user_id,action,old_data,new_data)
  VALUES (
  NEW.user_id
  , CASE
      WHEN (NEW.name <> OLD.name)
        THEN CONCAT('Changed ', OLD.name, "'s ", 'name')
      WHEN (NEW.address <> OLD.address)
        THEN CONCAT('Changed ', OLD.name, "'s ", 'address')    
      WHEN (NEW.city <> OLD.city)
        THEN CONCAT('Changed ', OLD.name, "'s ", 'city')   
      WHEN (NEW.phone <> OLD.phone)
        THEN CONCAT('Changed ', OLD.name, "'s ", 'phone number')    
      ELSE ''
    END
  , CASE
      WHEN (NEW.name <> OLD.name)
        THEN OLD.name
      WHEN (NEW.address <> OLD.address)
        THEN OLD.address
      WHEN (NEW.city <> OLD.city)
        THEN OLD.city
      WHEN (NEW.phone <> OLD.phone)
        THEN OLD.phone 
      ELSE ''
    END 

  , CASE
      WHEN (NEW.name <> OLD.name)
        THEN NEW.name
      WHEN (NEW.address <> OLD.address)
        THEN NEW.address
      WHEN (NEW.city <> OLD.city)
        THEN NEW.city
      WHEN (NEW.phone <> OLD.phone)
        THEN NEW.phone 
      ELSE ''
    END     
  );
  

Thank you.谢谢你。

Pattern:图案:

CREATE TRIGGER ...
...
BEGIN
INSERT INTO user_log (user_id,action,old_data,new_data)
SELECT NEW.user_id,
       CONCAT('Changed ', OLD.name, "'s ", columnname),
       oldvalue,
       newvalue
FROM ( SELECT 'name' columnname, OLD.name oldvalue, NEW.name newvalue
       UNION ALL
       SELECT 'address', OLD.address, NEW.address
       UNION ALL
       SELECT 'city', OLD.city, NEW.city
       UNION ALL
       SELECT 'phone', OLD.phone, NEW.phone
     ) data
WHERE NOT oldvalue <=> newvalue;       
END;

Also you may use ROW() constructor instead of SELECT.. UNION ALL.您也可以使用 ROW() 构造函数代替 SELECT.. UNION ALL。

https://dbfiddle.uk/?rdbms=mysql_5.6&fiddle=c63b122abedf9481d72129bee0d2d87d https://dbfiddle.uk/?rdbms=mysql_5.6&fiddle=c63b122abedf9481d72129bee0d2d87d

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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