1. ホーム
  2. mysql

行が変更された場合のみ、更新後にMySQLトリガーが起動する

2023-12-07 07:23:36

質問

データが本当に変更された場合のみ、"after update" トリガーを使用することは可能でしょうか。 私は "NEW と OLD" を知っています。しかし、それらを使用するとき、私は列を比較することしかできません。 例えば、"NEW.count <> OLD.count"のようなものです。

しかし、私は次のようなものが欲しいです:run trigger if "NEW <> OLD"。

例です。

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では、そうならない方法があるはずです。

を使うことができたのは知っています。

IF NOW.b <> OLD.b

この例では

しかし、カラムが変化する大きなテーブルを想像してみてください。 すべてのカラムを比較しなければならず、もしデータベースが変更されたら、トリガーを調整しなければなりません。 そして、ハードコードされた行のすべてのカラムを比較することは、良いことではありません。)

追加

行を見ればわかるように

一致した行 1 変更された: 0 警告 0

MySQL は行が変更されていないことを知っています。しかし、この知識をトリガーと共有することはありません。 "AFTER REAL UPDATE"またはこのようなトリガーがあれば、クールだと思います。

どのように解決するのですか?

回避策として、タイムスタンプ(新旧)を使ってチェックする方法もありますが、こちらは ではなく は更新されません。(もしかしたら、それが混乱の元になっているのでしょうか。なぜなら、そのトリガは 'on update' とも呼ばれますが、変更が発生しないときには実行されないからです) 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

そうすれば、スキームを更新するたびにトリガーを変更する必要はありません(質問にあった問題です)。

EDIT: 完全な例を追加しました。

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の動作のために動作しています。 タイムスタンプは、更新の際に変更が発生した場合にのみ更新されます。

ドキュメントはこちらです。

https://dev.mysql.com/doc/refman/5.7/en/timestamp-initialization.html

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 |
+-------+-----------+------+-----+-------------------+-----------------------------+