行が変更された場合のみ、更新後にMySQLトリガーが起動する
質問
データが本当に変更された場合のみ、"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 |
+-------+-----------+------+-----+-------------------+-----------------------------+
関連
-
[解決済み】MySQLのエラーコードです。MySQL WorkbenchでUPDATE中に1175のエラーが発生しました。
-
Mysql がエラー 1241 を報告 オペランドは 1 つのカラムを含む必要があります。
-
MySQL 接続タイムアウト。エラー SQLSTATE[HY000] [2002] 接続がタイムアウトしました 解決済み
-
Unknown character set.を解決する。MySQLデータベースインポート時の'utf8mb4'エラーの解消
-
[解決済み] ユーザー 'root'@'localhost' (パスワード: YES を使用) のアクセス拒否 - 特権がない?
-
[解決済み] SQL ServerでSELECTからUPDATEする方法とは?
-
[解決済み] MySQLの複数行を1つのフィールドに連結することはできますか?
-
[解決済み] MySQLテーブルへの挿入または存在する場合の更新
-
[解決済み] SQLite - UPSERT *not* INSERT or REPLACE
-
[解決済み] 挿入更新トリガー 挿入か更新かを判断する方法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
MySQLデータベースでvarchar型の数値の大きさを比較する方法
-
MySQLとOracleの一括挿入SQLの汎用的な記述例
-
MySQLのselect、distinct、limitの使い方
-
MySQLインデックスベースストレステストの実装
-
MySQLで正規表現を使う 詳細
-
[解決済み】マルチパート識別子をバインドできませんでした。
-
Mysql がエラー 1241 を報告 オペランドは 1 つのカラムを含む必要があります。
-
PostMan レポート エラー: 接続 ECONNREFUSED 127.0.0.1:port number
-
[解決済み] MySQLでコマンドラインを使用してユーザーアカウントのリストを取得するにはどうすればよいですか?
-
[解決済み] MySQLデータベースのテーブルのサイズを取得する方法は?