【问题标题】:PostgreSQL not triggering when NEW.field is NULL当 NEW.field 为 NULL 时 PostgreSQL 不触发
【发布时间】:2016-09-21 09:13:16
【问题描述】:

我的客户表上有以下触发器,因此我可以跟踪客户名称是否随时间变化以及名称的先前版本是什么。

CREATE OR REPLACE FUNCTION fn_customer_changes_log_history() RETURNS trigger as 
$BODY$
    BEGIN
       IF (NEW.name <> OLD.name)  
    THEN
        INSERT INTO tbl_customers_history(customer_id, name, action)
        VALUES(OLD.id, OLD.name, 'UPDATE');
    END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;

CREATE TRIGGER tr_customer_changes_log_history
BEFORE UPDATE ON tbl_customers
FOR EACH ROW
EXECUTE PROCEDURE fn_customer_changes_log_history();

但是当我在 NEW.name = NULL 并且 OLD.name = "Customer 1" 时执行更新时,不会触发此触发器?它仅在 NEW.name 此处有实际字符串值时触发。

这是为什么呢? NULL 和“客户 1”不相等所以应该触发?

【问题讨论】:

    标签: postgresql triggers


    【解决方案1】:

    使用

    IF (NEW.name IS DISTINCT FROM OLD.name)
    

    而不是

    IF (NEW.name <> OLD.name)
    

    【讨论】:

    • 将其与 COALESCE 已建议的答案进行比较时会如何?
    • 可能会少一些操作,但我预计不会有可测量的差异。不过我更喜欢我的版本,因为它更容易阅读。
    【解决方案2】:

    尝试将条件更改为

    IF COALESCE((NEW.name <> OLD.name), true)
    

    问题在于,如果NEW.fieldNULL,那么无论OLD.name 的值是多少,NEW.name &lt;&gt; OLD.name 的计算结果都是NULL。在有条件的情况下,NULL 始终被视为 false。

    一个更正确的答案应该是

    IF COALESCE((NEW.name <> OLD.name), true) AND NOT (NEW.name IS NULL AND OLD.name IS NULL)
    

    处理NEW.nameOLD.name 都是NULL 的情况,以便在这种情况下它们不会被视为平等。

    【讨论】:

    • 谢谢。这行得通。但是你知道为什么它不会像我那样触发吗?为什么需要这种 COALESCE 的东西?
    • @koala 我扩展了我的答案。
    【解决方案3】:

    NULL &lt;&gt; 'anything' 的计算结果始终为 FALSE。就像NULL = 'anything'NULL &gt; 5

    您需要coalesce 来修复比较:

    COALESCE(NEW.name, '') <> COALESCE(OLD.name, '')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-11
      • 1970-01-01
      • 1970-01-01
      • 2018-12-10
      • 1970-01-01
      • 2012-07-03
      • 1970-01-01
      相关资源
      最近更新 更多