2012-12-18 59 views
3

由于信誉限制,这是对this answer to a prior question的后续问题。我想知道在处理NULL值时是否有更有效的方法来测试每个字段的更改。更新触发器后MySQL中的NULL处理触发器仅在数据更改时触发

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); 

我想要一个触发器,其操作在更新后发生,只有当更新值发生更改时。因此,此更新将不会导致INSERT:

UPDATE foo SET a = 1 WHERE b = 2; 

但此更新将导致INSERT:

UPDATE foo SET a = 2 WHERE b = 2; 

我写了这个触发器来处理,但是我希望中频声明可以简化。

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 ; 

IF语句可以简化吗?还是有更简单的整体解决方案?

回答

5

您可以使用coalesce(),它返回的第一个参数是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; 

选择第二个参数可能会很棘手。上面的例子适用于a,b和c是字符串时以及空字符串值等于null值时的常见情况。

2

您可以通过使用NULL-safe equals operator <=>然后negating the result using NOT进行比较来完成此操作。

所以,

((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)) 

将成为

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

要检查是否有多个列的都变了,你可以做

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