データが本当に変更された場合にのみ、「更新後」トリガーを使用する可能性はありますか。 「新旧」を知っています。しかし、それらを使用する場合、列を比較することしかできません。たとえば、「NEW.count <> OLD.count」。
しかし、私は次のようなものが欲しい:「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 |
+------+------+
ポイントは、更新があったが、何も変わっていないであるということです。しかし、とにかくトリガーが実行されました。私見ではない方法があるはずです。
私は使用できたことを知っています
IF NOW.b <> OLD.b
この例では。
しかし、列が変わる大きなテーブルを想像してください。すべての列を比較する必要があり、データベースが変更された場合はトリガーを調整する必要があります。そして、ハードコーディングされた行のすべての列を比較するのは「気分が悪い」:)
追加
行でわかるように
一致した行:1変更:0警告:0
MySQLは、行が変更されなかったことを知っています。しかし、この知識をトリガーと共有することはありません。 「AFTER REAL UPDATE」などのトリガーまたはこのようなものはクールです。
回避策として、チェックにタイムスタンプ(古いものと新しいもの)を使用できます。行に変更がない場合、タイムスタンプは更新されませんnot。 (おそらくそれが混乱の原因ですか?それは「更新時」とも呼ばれますが、変更が発生しないと実行されないためです)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の動作により動作します。タイムスタンプは、更新で変更が発生した場合にのみ更新されます。
ドキュメントはこちらです:
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 |
+-------+-----------+------+-----+-------------------+-----------------------------+
しかし、列が変わる大きなテーブルを想像してください。すべての列を比較する必要があり、データベースが変更された場合はトリガーを調整する必要があります。そして、ハードコーディングされたすべての行を比較するのは「気分が悪い」:)
ええ、しかしそれが先へ進む方法です。
補足として、更新する前に先制的にチェックすることも良い習慣です:
UPDATE foo SET b = 3 WHERE a=3 and b <> 3;
あなたの例では、これはそれを更新します(したがってoverwrite)two行ではなく3行。
コメントできないため、列がNULL値をサポートしている場合、OLD.x <> NEW.xでは十分ではないことに注意してください。
SELECT IF(1<>NULL,1,0)
と同じように0を返します
NULL<>NULL 1<>NULL 0<>NULL 'AAA'<>NULL
そのため、FROMおよびTO NULLの変更を追跡しません
このシナリオの正しい方法は
((OLD.x IS NULL AND NEW.x IS NOT NULL) OR (OLD.x IS NOT NULL AND NEW.x IS NULL) OR (OLD.x<>NEW.x))
これを行うには、 NULL-safe equals operator <=>
を使用して各フィールドを比較し、次に NOT
を使用して結果を否定します を使用します。
完全なトリガーは次のようになります。
DROP TRIGGER IF EXISTS `my_trigger_name`;
DELIMITER $$
CREATE TRIGGER `my_trigger_name` AFTER UPDATE ON `my_table_name` FOR EACH ROW
BEGIN
/*Add any fields you want to compare here*/
IF !(OLD.a <=> NEW.a AND OLD.b <=> NEW.b) THEN
INSERT INTO `my_other_table` (
`a`,
`b`
) VALUES (
NEW.`a`,
NEW.`b`
);
END IF;
END;$$
DELIMITER ;
( 私の別の答え に基づきます。)
ここで、新しい挿入に影響する行がある場合、データベース内の別のテーブルで更新されます。
DELIMITER $$
CREATE TRIGGER "give trigger name" AFTER INSERT ON "table name"
FOR EACH ROW
BEGIN
INSERT INTO "give table name you want to add the new insertion on previously given table" (id,name,age) VALUES (10,"sumith",24);
END;
$$
DELIMITER ;
次のクエリを使用して、変更のある行を確認します。
(select * from inserted) except (select * from deleted)
このクエリの結果は、古いレコードとは異なるすべての新しいレコードで構成される必要があります。
MYSQL TRIGGER BEFORE UPDATE IF OLD.a<>NEW.b
USE `pdvsa_ent_aycg`;
DELIMITER $$
CREATE TRIGGER `cisterna_BUPD` BEFORE UPDATE ON `cisterna` FOR EACH ROW
BEGIN
IF OLD.id_cisterna_estado<>NEW.id_cisterna_estado OR OLD.observacion_cisterna_estado<>NEW.observacion_cisterna_estado OR OLD.fecha_cisterna_estado<>NEW.fecha_cisterna_estado
THEN
INSERT INTO cisterna_estado_modificaciones(nro_cisterna_estado, id_cisterna_estado, observacion_cisterna_estado, fecha_cisterna_estado) values (NULL, OLD.id_cisterna_estado, OLD.observacion_cisterna_estado, OLD.fecha_cisterna_estado);
END IF;
END