NULL Handling in MySQL After Update Trigger that Fires Only on Data Change

女生的网名这么多〃 提交于 2019-12-22 10:36:33

问题


Due to reputation constraints, this is a follow-up question to this answer to a prior question. I'd like to know if there's a more efficient way to test each field for changes while handling NULL values.

CREATE TABLE foo (
  a INT NULL DEFAULT NULL, 
  b INT NULL DEFAULT NULL,
  c INT NULL DEFAULT NULL
);

CREATE TABLE bar (
  a INT NULL DEFAULT NULL,
  b INT NULL DEFAULT NULL,
  c INT NULL DEFAULT NULL
);

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

I want a trigger whose actions occur after update only if a value is changed by the update. So this UPDATE won't result in an INSERT:

UPDATE foo SET a = 1 WHERE b = 2;

But this UPDATE will result in an INSERT:

UPDATE foo SET a = 2 WHERE b = 2;

I have written this trigger to handle that, however I'm hoping the IF statement can be simplified.

DELIMITER ///
CREATE TRIGGER t_after_update_foo
AFTER UPDATE ON foo
FOR EACH ROW 
  BEGIN
    IF
      ((OLD.a <> NEW.a OR OLD.a IS NULL OR NEW.a IS NULL) AND (NEW.a IS NOT NULL OR OLD.a IS NOT NULL))
      OR
      ((OLD.b <> NEW.b OR OLD.b IS NULL OR NEW.b IS NULL) AND (NEW.b IS NOT NULL OR OLD.b IS NOT NULL))
      OR
      ((OLD.c <> NEW.c OR OLD.c IS NULL OR NEW.c IS NULL) AND (NEW.c IS NOT NULL OR OLD.c IS NOT NULL))
    THEN
      INSERT INTO bar (a, b, c) VALUES (NEW.a, NEW.b, NEW.c);
    END IF;
  END;
///
DELIMITER ;

Can the IF statement be simplified? Or is there an easier overall solution?


回答1:


You could use coalesce(), which returns the first of its arguments that is not null.

if coalesce(old.a,'') <> coalesce(new.a,'') or
   coalesce(old.b,'') <> coalesce(new.b,'') or
   coalesce(old.c,'') <> coalesce(new.c,'')
   then
     insert ...;
   end if;

It can be tricky to choose the second argument. The above example works for the common case when a, b and c are strings and when an empty string value is equivalent to a null value.




回答2:


You can do this by comparing using the NULL-safe equals operator <=> and then negating the result using NOT.

So,

((OLD.a <> NEW.a OR OLD.a IS NULL OR NEW.a IS NULL) AND (NEW.a IS NOT NULL OR OLD.a IS NOT NULL))

would become

!(OLD.a <=> NEW.a)

To check if any of multiple columns have changed, you could do

!(OLD.a <=> NEW.a AND OLD.b <=> NEW.b)

A slightly shorter alternative if you have many colums to compare, courtesy of @dlauzon:

!((OLD.a, OLD.b, OLD.c, ...) <=> (NEW.a, NEW.b, NEW.c, ...))


来源:https://stackoverflow.com/questions/13939964/null-handling-in-mysql-after-update-trigger-that-fires-only-on-data-change

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!