2012-12-18 88 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)