not*_*ain 6 postgresql trigger plpgsql json postgresql-9.6
当表具有 json 或 jsonb 列时,是否无法在 INSERT/UPDATE 触发器中进行全行比较?我收到的错误让我认为我需要单独比较每一列,因为该NEW.*/OLD.*格式不能用于比较 json 列。
CREATE OR REPLACE FUNCTION on_insert_update_modified()
RETURNS TRIGGER AS $$
BEGIN
IF row(NEW.*) IS DISTINCT FROM row(OLD.*) THEN
NEW.modified_at = now();
RETURN NEW;
ELSE
RETURN OLD;
END IF;
END;
$$ language 'plpgsql';
CREATE TRIGGER mytable_insert_update
BEFORE INSERT OR UPDATE ON mytable
FOR EACH ROW
EXECUTE PROCEDURE on_insert_update_modified();
Run Code Online (Sandbox Code Playgroud)
当我插入包含 json 和 jsonb 列的表时,出现以下错误:
CREATE OR REPLACE FUNCTION on_insert_update_modified()
RETURNS TRIGGER AS $$
BEGIN
IF row(NEW.*) IS DISTINCT FROM row(OLD.*) THEN
NEW.modified_at = now();
RETURN NEW;
ELSE
RETURN OLD;
END IF;
END;
$$ language 'plpgsql';
CREATE TRIGGER mytable_insert_update
BEFORE INSERT OR UPDATE ON mytable
FOR EACH ROW
EXECUTE PROCEDURE on_insert_update_modified();
Run Code Online (Sandbox Code Playgroud)
有更好的办法解决这个问题吗?
json没有为 Postgres 数据类型定义相等或不等运算符json。看:
因此,涉及列的行比较json也必然会失败 - 有明显的例外,请参见下文。
有(不完美!)解决方法,但不必费心并切换到jsonb,它允许这些检查。
您也无法比较OLDand NEWforINSERT运算,其中没有OLD- only for UPDATEor DELETE。我建议使用 的列默认值modified_at,或单独的触发函数和触发器BEFORE INSERT来now()无条件覆盖任何输入。
这个函数和触发器UPDATE:
CREATE OR REPLACE FUNCTION on_update_modified()
RETURNS trigger
LANGUAGE plpgsql AS
$func$
BEGIN
IF NEW IS DISTINCT FROM OLD THEN
NEW.modified_at = now();
RETURN NEW;
ELSE
RETURN NULL; -- skip empty update, see below
END IF;
END
$func$;
CREATE TRIGGER mytable_update -- doesn't work!
BEFORE UPDATE ON tbl_js
FOR EACH ROW EXECUTE PROCEDURE on_update_modified();
Run Code Online (Sandbox Code Playgroud)
db<>在这里摆弄(Postgres 9.6)
Postgres 13 中没有什么不同:db<>fiddle这里
RETURN NULL;是可选的。如果该行根本没有更改(并且无论如何已经运行触发器函数),您也可以跳过该UPDATE行(如果它没有更改)。这节省了徒劳地编写新行版本的大量成本。如果其他触发器依赖于它,或者对于其他奇异的边缘情况,您可能仍然想继续使用它。然后RETURN NEW;- 无条件地在触发函数结束时。RETURN OLD;在我们确定两行值相同后,将没有任何好处。
json还能用吗?奇怪的是,是的。行比较是从左到右处理的。对于表达式NEW IS DISTINCT FROM OLDPostgres 可以true在找到第一个不匹配时立即返回(在遇到问题之前json)。这可能会也可能不会发生,具体取决于代码路径。引用有关逐行比较的手册:
笔记
如果使用较早的列解决比较,则可能不会发生与元素数量或类型相关的错误。