Mysql触发器:跟踪更改

Mysql触发器:跟踪更改,mysql,triggers,history,Mysql,Triggers,History,我不知道这是否可行,但我想跟踪表1的更改 数据库中存在以下两个表: CREATE TABLE IF NOT EXISTS `db`.`table1` ( `idtable1` INT NOT NULL AUTO_INCREMENT, `A` VARCHAR(45) NULL, `B` VARCHAR(45) NULL, `C` VARCHAR(45) NULL, PRIMARY KEY (`idtable1`)) ENGINE = InnoDB CREATE TABLE

我不知道这是否可行,但我想跟踪表1的更改

数据库中存在以下两个表:

CREATE TABLE IF NOT EXISTS `db`.`table1` (
  `idtable1` INT NOT NULL AUTO_INCREMENT,
  `A` VARCHAR(45) NULL,
  `B` VARCHAR(45) NULL,
  `C` VARCHAR(45) NULL,
  PRIMARY KEY (`idtable1`))
ENGINE = InnoDB


CREATE TABLE IF NOT EXISTS `db`.`table2history` (
  `idtable2history` INT NOT NULL AUTO_INCREMENT,
  `columnName` ENUM('A', 'B', 'C') NULL,
  `columnPrimaryKey` INT NULL,
  `columnNewValue` VARCHAR(45) NULL,
  `changetimestamp` DATETIME NULL,
  PRIMARY KEY (`idtable2history`))
ENGINE = InnoDB
如果执行以下指令:

UPDATE table1 SET A="ABC", B="XYZ" WHERE  idtable1=50;
INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "A", "50", "ABC", NOW());

INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "B", "50", "XYZ", NOW());
UPDATE table1 SET A="123", B="456", C="789" WHERE  idtable1=20;
INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "A", "20", "123", NOW());

INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "B", "20", "456", NOW());

INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "C", "20", "789", NOW());
应执行“更新前”触发器:

UPDATE table1 SET A="ABC", B="XYZ" WHERE  idtable1=50;
INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "A", "50", "ABC", NOW());

INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "B", "50", "XYZ", NOW());
UPDATE table1 SET A="123", B="456", C="789" WHERE  idtable1=20;
INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "A", "20", "123", NOW());

INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "B", "20", "456", NOW());

INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "C", "20", "789", NOW());
如果执行以下指令:

UPDATE table1 SET A="ABC", B="XYZ" WHERE  idtable1=50;
INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "A", "50", "ABC", NOW());

INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "B", "50", "XYZ", NOW());
UPDATE table1 SET A="123", B="456", C="789" WHERE  idtable1=20;
INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "A", "20", "123", NOW());

INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "B", "20", "456", NOW());

INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "C", "20", "789", NOW());
应执行“更新前”触发器:

UPDATE table1 SET A="ABC", B="XYZ" WHERE  idtable1=50;
INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "A", "50", "ABC", NOW());

INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "B", "50", "XYZ", NOW());
UPDATE table1 SET A="123", B="456", C="789" WHERE  idtable1=20;
INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "A", "20", "123", NOW());

INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "B", "20", "456", NOW());

INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
VALUES (NULL, "C", "20", "789", NOW());

您知道此问题的智能解决方案吗?

您需要遍历触发器正文中要跟踪的每一列,检查空安全不等式:

IF NOT (NEW.A <=> OLD.A) THEN
  INSERT INTO table2history (idtable2history, columnName, columnPrimaryKey, columnNewValue, changetimestamp)
  VALUES (NULL, "A",NEW.idtable1, NEW.A, NOW());
END IF;

IF NOT (NEW.B <=> OLD.B) THEN
...
如果不是(新的.A旧的.A),那么
插入table2history(idtable2history、columnName、columnPrimaryKey、columnNewValue、changetimestamp)
值(NULL,“A”,NEW.idtable1,NEW.A,NOW());
如果结束;
如果不是(新的B旧的B),那么
...
<> > <代码> >(EXPR1 EXPR2)<代码>测试使用NULL安全相等比较(“S飞船”)操作符<代码> < /代码>,它不同于适当的相等比较,将考虑<代码> NULL/<代码>值相等,并将非空值与“代码>空< /代码>的任一方比较为<代码> false <代码>,而不是<代码> null <代码>,前导的
NOT
反转测试。。。因此,如果行的旧值与新值不同,则运行
INSERT
查询,否则,由于值没有更改,因此不会发生任何事情

OLD
NEW
是行的新旧版本的特殊别名。它们同样有效,并且包含更新之前的
和更新之后的
的相同值,但是实际修改
图像的触发器仅在
之前的
触发器中工作
之前,
新建
表示“行将更新到什么位置,
之后,
新建
表示“行已更新到什么位置”

实际上,您可能希望在更新后将此触发器编写为
,这仅仅是因为您以后可能希望在更新前添加一个不同的
触发器,用于验证建议的更新,因为每个时间只能定义一个触发器(在MySQL 5.7之前),这样就可以让这个触发器不受影响了

触发器必须使用静态查询遍历正在跟踪的每一列,每一列一个,因为触发器不支持使用准备好的语句和动态SQL。通过使用脚本遍历列来编写(生成)触发器主体将节省一些键入时间,但现在您可以手动编写,上面的示例应该完全按照您的意愿执行


您的触发器主体看起来会做很多工作,但服务器会很快完成所有这些工作。

是的,这样做是可能的。到目前为止您尝试了什么?创建一个包含3个以上字段的表副本。时间戳,用于存储插入、删除或更新的类型,以及用户名字段。在插入、更新、删除时创建3个老虎机,将孔行放入新表中,并添加时间戳、类型和用户。所以你可以回到每一次,看看有什么变化。谢谢你的回答@伯纳德·布芬感谢您提供了一个可能的解决方案。但是我想完全按照上面描述的方法来实现它。@Shadow你能给我一个提示吗?我不知道如何处理不同的更新命令。如果要更改一个或多个列。在更新前为每行创建触发器
db
\u update\u table 1
table 1
上更新前开始插入。。。结束。。。如果只更新了A栏或A栏和B栏,我不知道如何处理。为此,我正在寻找一个智能解决方案。我不需要你提供一个完整的解决方案,但是一个提示或说明会很好。