복붙노트

[SQL] MySQL의 트리거 업데이트 후 행이 변경된 경우에만

SQL

MySQL의 트리거 업데이트 후 행이 변경된 경우에만

데이터 만 정말 변경된 경우에 "업데이트 후"트리거를 사용하는 가능성이있다. 나는 "NEW와 OLD"알고. 그들을 사용하지만 난 단지 열을 비교할 수 있어요. 예를 들어 "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 |
+------+------+

요점은 업데이트가 있었다,하지만 아무것도 변경되었습니다. 그러나 트리거 어쨌든 달렸다. 이럴는하지 않는 방법이 있어야한다.

내가 사용했을 수 있다는 것을 알고있다

이 예를 들어.

하지만 변화하는 열이있는 큰 테이블을 상상한다. 당신은 모든 열을 비교해야하고 데이터베이스가 변경되면 당신은 방아쇠를 조정해야합니다. 그리고 그것은 하드 코딩 된 행의 모든 ​​열을 비교하는 좋은 "느낌"하지 않습니다 :)

부가

당신은 라인에서 볼 수 있듯이

MySQL은 라인이 변경되지 않았다는 사실을 알 수있다. 그러나 트리거이 지식을 공유하지 않습니다. 같은 트리거는이 같은 또는 뭔가 "REAL 업데이트 한 후"멋진 것입니다.

해결법

  1. ==============================

    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 |
    +-------+-----------+------+-----+-------------------+-----------------------------+
    
  2. ==============================

    2.그래,하지만 그 진행하는 방법입니다.

    그래,하지만 그 진행하는 방법입니다.

    보조 노트, 그것은 선제로 업데이트하기 전에 확인 좋은 방법도있다 :

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

    귀하의 예제에서 이것은 두 행 대신 세를 업데이트 (및 덮어 쓰기) 할 것입니다.

  3. ==============================

    3.나는, 그래서 그냥 조심 언급 어차피 그 경우 열 지원의 NULL 값 OLD.x <> NEW.x 밤은 충분하기 때문에

    나는, 그래서 그냥 조심 언급 어차피 그 경우 열 지원의 NULL 값 OLD.x <> NEW.x 밤은 충분하기 때문에

    SELECT IF (1 <> NULL, 1,0)

    같은 0을 반환

    NULL<>NULL 1<>NULL 0<>NULL 'AAA'<>NULL
    

    그것은 및 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))
    
  4. ==============================

    4.당신은 NOT 사용하여 결과를 부정 다음 NULL 안전 같음 연산자를 사용하여 각 필드를 비교 <=>하고이 작업을 수행 할 수 있습니다.

    당신은 NOT 사용하여 결과를 부정 다음 NULL 안전 같음 연산자를 사용하여 각 필드를 비교 <=>하고이 작업을 수행 할 수 있습니다.

    완전한 트리거가 될 것입니다 :

    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 ;
    

    (내 다른 답변을 기준으로합니다.)

  5. ==============================

    5.어떤 행이 새로운 삽입에 영향을 여기 저기에서 그런 다음 데이터베이스의 다른 테이블에 업데이트됩니다.

    어떤 행이 새로운 삽입에 영향을 여기 저기에서 그런 다음 데이터베이스의 다른 테이블에 업데이트됩니다.

    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 ;
    
  6. ==============================

    6.변경 사항이 행을 보려면 다음 쿼리를 사용 :

    변경 사항이 행을 보려면 다음 쿼리를 사용 :

    (select * from inserted) except (select * from deleted)
    

    이 쿼리의 결과는 기존의 것과 다른 모든 새 레코드로 구성되어야합니다.

  7. ==============================

    7.

    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
    
  8. from https://stackoverflow.com/questions/6296313/mysql-trigger-after-update-only-if-row-has-changed by cc-by-sa and MIT license