只有在行已更改时,更新后才触发MySQL触发器

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (73)

是否有可能只在数据被真正更改的情况下使用“后更新”触发器。我知道“新旧”。但是当使用它们时,我只能比较列。例如,“NEW.Count<>OLD.count”。

但是我想要这样的东西:如果“新的<>旧的”运行触发器

例如:

create table foo (a INT, b INT);
create table bar (a INT, b INT);

INSERT INTO foo VALUES(1,1);
INSERT INTO foo VALUES(2,2);
INSERT INTO foo VALUES(3,3);

CREATE TRIGGER ins_sum
    AFTER UPDATE ON foo
    FOR EACH ROW
    INSERT INTO bar VALUES(NEW.a, NEW.b);

UPDATE foo SET b = 3 WHERE a=3;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0


select * from bar;
+------+------+
| a    | b    |
+------+------+
|    3 |    3 |
+------+------+

重点是,有一个更新,但是没有什么改变...。但触发器还是启动了。IMHO应该有一种不应该的方式。

我知道我可以用

如果NOW.b<>OLD.b

对于这个例子。

但是想象一下,一个大的表中的列在不断变化。您必须比较每一列,如果数据库发生更改,则必须调整触发器。比较行硬编码的每一列并不“感觉”好:)

加法

就像你在网上看到的

匹配的行:1已更改:0警告:0

MySQL知道行没有改变。但它并没有和触发器分享这些知识。像“真正更新后”之类的触发器会很酷。

提问于
用户回答回答于

作为解决办法,可以使用时间戳(旧的和新的)来检查,但在行没有更改时更新。(可能这就是造成混乱的根源?因为它也被称为‘onupdate’,但在没有发生更改时不会执行),所以在1秒内的更改将不会执行触发器的这一部分,但是在某些情况下这可能很好(比如,当应用程序拒绝快速更改时)。

例如,而不是

IF NEW.a <> OLD.a or NEW.b <> OLD.b /* etc, all the way to NEW.z <> OLD.z */ 
THEN  
  INSERT INTO bar (a, b) VALUES(NEW.a, NEW.b) ;
END IF

你可以用

IF NEW.ts <> OLD.ts 
THEN  
  INSERT INTO bar (a, b) VALUES(NEW.a, NEW.b) ;
END IF

然后,不必每次更新方案(问题中提到的问题)时都更改触发器。

create table foo (a INT, b INT, ts TIMESTAMP);
create table bar (a INT, b INT);

INSERT INTO foo (a,b) VALUES(1,1);
INSERT INTO foo (a,b) VALUES(2,2);
INSERT INTO foo (a,b) VALUES(3,3);

DELIMITER ///

CREATE TRIGGER ins_sum AFTER UPDATE ON foo
    FOR EACH ROW
    BEGIN
        IF NEW.ts <> OLD.ts THEN  
            INSERT INTO bar (a, b) VALUES(NEW.a, NEW.b);
        END IF;
    END;
///

DELIMITER ;

select * from foo;
+------+------+---------------------+
| a    | b    | ts                  |
+------+------+---------------------+
|    1 |    1 | 2011-06-14 09:29:46 |
|    2 |    2 | 2011-06-14 09:29:46 |
|    3 |    3 | 2011-06-14 09:29:46 |
+------+------+---------------------+
3 rows in set (0.00 sec)

-- UPDATE without change
UPDATE foo SET b = 3 WHERE a = 3;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0

-- the timestamo didnt change
select * from foo WHERE a = 3;
+------+------+---------------------+
| a    | b    | ts                  |
+------+------+---------------------+
|    3 |    3 | 2011-06-14 09:29:46 |
+------+------+---------------------+
1 rows in set (0.00 sec)

-- the trigger didn't run
select * from bar;
Empty set (0.00 sec)

-- UPDATE with change
UPDATE foo SET b = 4 WHERE a=3;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

-- the timestamp changed
select * from foo;
+------+------+---------------------+
| a    | b    | ts                  |
+------+------+---------------------+
|    1 |    1 | 2011-06-14 09:29:46 |
|    2 |    2 | 2011-06-14 09:29:46 |
|    3 |    4 | 2011-06-14 09:34:59 |
+------+------+---------------------+
3 rows in set (0.00 sec)

-- and the trigger ran
select * from bar;
+------+------+---------------------+
| a    | b    | ts                  |
+------+------+---------------------+
|    3 |    4 | 2011-06-14 09:34:59 |
+------+------+---------------------+
1 row in set (0.00 sec)

因为MySQL处理时间戳的行为,它才能工作。只有在更新中发生更改时,才更新时间戳。

文件如下:

desc foo;
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type      | Null | Key | Default           | Extra                       |
+-------+-----------+------+-----+-------------------+-----------------------------+
| a     | int(11)   | YES  |     | NULL              |                             |
| b     | int(11)   | YES  |     | NULL              |                             |
| ts    | timestamp | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------+
用户回答回答于

但是想象一下,一个大的表中的列在不断变化。必须比较每一列,如果数据库发生更改,则必须调整触发器。比较每一行硬编码都感觉不太好:)

是的,但这就是继续的方法。

另外,在更新之前先发制人地检查也是很好的做法:

UPDATE foo SET b = 3 WHERE a=3 and b <> 3;

在示例中,这将使其更新2三排而不是三排。

扫码关注云+社区