我有一个表测试的触发器函数,其中包含以下代码片段:
IF TG_OP='UPDATE' THEN
IF OLD.locked > 0 AND
( OLD.org_id <> NEW.org_id OR
OLD.document_code <> NEW.document_code OR
-- other columns ...
)
THEN
RAISE EXCEPTION 'Message';
-- more code
所以我静态检查所有列的新值及其先前的值以确保完整性。现在,每当我的业务逻辑发生变化并且我必须在该表中添加新列时,我每次都必须修改此触发器。我认为如果能以某种方式动态检查该表的所有列,而不显式输入其名称,那会更好。
怎么做?
答案 0 :(得分:8)
关于触发器中WHEN
子句的9.0 beta2文档,可能在触发器体内的早期版本中使用:
OLD.* IS DISTINCT FROM NEW.*
IF row(new.*) IS DISTINCT FROM row(old.*)
答案 1 :(得分:7)
看一下information_schema,有一个视图“列”。执行查询以从触发触发器的表中获取所有当前列名:
SELECT
column_name
FROM
information_schema.columns
WHERE
table_schema = TG_TABLE_SCHEMA
AND
table_name = TG_TABLE_NAME;
循环结果然后你就去了!
更多信息可在fine manual。
中找到答案 2 :(得分:2)
答案 3 :(得分:1)
使用pl / perl或pl / python。它们更适合这些任务。 很多更好。
您也可以安装hstore-new,并使用它的row-&gt; hstore语义,但在使用普通数据类型时,这绝对不是一个好主意。
答案 4 :(得分:0)
在Postgres 9.0或更高版本中,在触发器定义(CREATE TRIGGER
语句)中添加WHEN
clause:
CREATE TRIGGER foo
BEFORE UPDATE
FOR EACH ROW
WHEN (OLD IS DISTINCT FROM NEW) -- parentheses required!
EXECUTE PROCEDURE ...;
仅适用于触发器BEFORE
/ AFTER
UPDATE
,其中OLD
和NEW
都已定义。您尝试将此WHEN
子句与INSERT
或DELETE
触发器一起使用时会遇到异常。
并从根本上简化触发器功能:
...
IF OLD.locked > 0 THEN
RAISE EXCEPTION 'Message';
END IF;
...
无需测试IF TG_OP='UPDATE' ...
,因为此触发器仅适用于UPDATE
。
或者在WHEN子句中移动该条件:
CREATE TRIGGER foo
BEFORE UPDATE
FOR EACH ROW
WHEN (OLD.locked > 0
AND OLD IS DISTINCT FROM NEW)
EXECUTE PROCEDURE ...;
在您的触发器功能中只保留无条件RAISE EXCEPTION
,仅在需要时才会调用。
在
BEFORE
触发器中,WHEN
条件在之前评估 函数是或将被执行,因此使用WHEN
并不重要 不同于在开始时测试相同的条件 触发功能。特别要注意的是NEW
行 condition是当前值,可能由之前修改过 触发。此外,不允许BEFORE
触发器WHEN
条件 检查NEW
行的系统列(例如oid
),因为那些 还没有成功。在
AFTER
触发器中,WHEN
条件在评估之后进行评估 发生行更新,它确定事件是否排队到 在声明结束时触发触发器。因此当AFTER
触发时WHEN
条件不返回true,没有必要排队 事件也不会在语句结束时重新获取行。这可能导致 修改许多行的语句中的显着加速,如果是 触发器只需要为几行触发。
相关:
是否可以动态循环表格的列?
是。例子: