【问题标题】:With MySQL how can I iterate through fields in an update trigger to compare old and new values for a change log?使用 MySQL,我如何遍历更新触发器中的字段以比较更改日志的新旧值?
【发布时间】:2019-11-26 16:11:55
【问题描述】:

当日志记录打开时,我正在尝试使用 MySQL 中的触发器来更新带有表更改的日志表。

UPDATE 触发器需要遍历表的所有字段,比较数据变化(OLD.fieldname NEW.fieldname),然后将字段名称和数据写入日志表。

我编写的代码必须明确命名每个字段。有些表有很多字段,我不想手动输入所有字段名称。

有没有办法以编程方式遍历表的字段,以便我可以创建一个存储过程来调用?

我的代码:

CREATE DEFINER=`root`@`localhost` TRIGGER `trgUserUpd` AFTER UPDATE ON `user`
FOR EACH ROW BEGIN
DECLARE rChanges TEXT DEFAULT '';

IF BINARY(OLD.userName) <> BINARY(NEW.userName) THEN
  SET rChanges := CONCAT('userName: ', OLD.userName, ' => ', NEW.userName);
END IF;

IF BINARY(OLD.fullName) <> BINARY(NEW.fullName) THEN
  IF rChanges <> '' THEN
    SET rChanges := CONCAT(rChanges, '
');
  END IF;
  SET rChanges := CONCAT(rChanges, 'fullName: ', OLD.fullName, ' => ', NEW.fullName);
END IF;

IF BINARY(OLD.initials) <> BINARY(NEW.initials) THEN
  IF rChanges <> '' THEN
    SET rChanges := CONCAT(rChanges, '
');
  END IF;
  SET rChanges := CONCAT(rChanges, 'initials: ', OLD.initials, ' => ', NEW.initials);
END IF;

IF BINARY(OLD.password) <> BINARY(NEW.password) THEN
  IF rChanges <> '' THEN
    SET rChanges := CONCAT(rChanges, '
');
  END IF;
  SET rChanges := CONCAT(rChanges, 'password changed');
END IF;

IF BINARY(OLD.salt) <> BINARY(NEW.salt) THEN
  IF rChanges <> '' THEN
    SET rChanges := CONCAT(rChanges, '
');
  END IF;
  SET rChanges := CONCAT(rChanges, 'salt: ', OLD.salt, ' => ', NEW.salt);
END IF;

IF BINARY(OLD.administrator) <> BINARY(NEW.administrator) THEN
  IF rChanges <> '' THEN
    SET rChanges := CONCAT(rChanges, '
');
  END IF;
  SET rChanges := CONCAT(rChanges, 'administrator: ', OLD.administrator, ' => ', NEW.administrator);
END IF;

IF BINARY(OLD.active) <> BINARY(NEW.active) THEN
  IF rChanges <> '' THEN
    SET rChanges := CONCAT(rChanges, '
');
  END IF;
  SET rChanges := CONCAT(rChanges, 'active: ', OLD.active, ' => ', NEW.active);
END IF;

CALL ChangeNotify('user', OLD.id, rChanges, 'update');
END;

似乎准备好的语句也不起作用。我刚试过:

BEGIN
DECLARE rChanges TEXT DEFAULT '';
DECLARE eof INT DEFAULT FALSE;
DECLARE field CHAR(50) DEFAULT '';
DECLARE query, stmt CHAR(200) DEFAULT '';
DECLARE oldValue, newValue TEXT DEFAULT '';

DECLARE fields CURSOR FOR
SELECT column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'user'
ORDER BY ordinal_position;

DECLARE CONTINUE HANDLER FOR NOT FOUND SET eof = TRUE;

OPEN fields;

REPEAT
  FETCH fields INTO field;
  IF NOT eof THEN
    SET query = CONCAT('SELECT OLD.', field, ', NEW.', field, ' INTO oldValue, newValue');
    PREPARE stmt FROM query;
    EXECUTE stmt;
    IF BINARY(oldValue) <> BINARY(newValue) THEN
      IF rChanges <> '' THEN
        SET rChanges := CONCAT(rChanges, '
');
      END IF;
      SET rChanges := CONCAT(rChanges, field, ': ', oldValue, ' => ', newValue);
    END IF;
  END IF;
UNTIL eof = TRUE;
END REPEAT;

CLOSE fields;

CALL ChangeNotify('user', OLD.id, rChanges, 'update');
END

这甚至不会保存(除非我有什么问题)。

【问题讨论】:

    标签: mysql stored-procedures triggers


    【解决方案1】:

    使用 DB 和 Table 试试下面的代码,它可能会有所帮助。让我知道它是否对您有帮助。

    调用 ATESTE('tablename','dbname')

     CREATE PROCEDURE `ATESTE`(tablename varchar(100),schemaname varchar(100))
        BEGIN
        DECLARE rChanges MEDIUMTEXT;
        DECLARE field VARCHAR(50);
        DECLARE cmdquery MEDIUMTEXT;
        DECLARE oldValue, newValue VARCHAR(50);
        DECLARE myfields MEDIUMTEXT;
        DECLARE mPos integer;        
    
        set myfields = (SELECT group_concat(column_name)
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE table_name = tablename and table_schema= schemaname
        ORDER BY ordinal_position);
    
          set rChanges = '';
          set mPos = Position("," in myfields);
    
        myloop: While(mPos > 0) Do
    
            set field = trim(substring(myfields,1,mPos-1));    
            set myfields = trim(substring(myfields,mPos+1)); 
            set mPos = Position("," in myfields);    
            set oldValue =  CONCAT('old.',field);
            set NewValue =  CONCAT('new.',field);   
    
    
            IF rChanges <> '' THEN
               SET rChanges = CONCAT(rChanges, '\r\n');
             END IF;
    
            SET rChanges = CONCAT(rChanges, field, ' : ', oldValue, ' => ', newValue);    
    
          End While;  
    
         -- select rChanges;  
    
         CALL ChangeNotify('user', OLD.id, rChanges, 'update');
    
        END
    

    【讨论】:

    • 遗憾的是,它只输出字段名称,而不是它们的值。实际输出: id : old.id => new.id userName : old.userName => new.userName fullName : old.fullName => new.fullName 首字母 : old.initials => new.initials 密码 : old.password => new.password salt : old.salt => new.salt 管理员 : old.administrator => new.administrator
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-05
    • 2010-11-15
    • 1970-01-01
    • 1970-01-01
    • 2013-04-14
    • 2015-08-23
    相关资源
    最近更新 更多