是否可以动态循环表的列?

时间:2010-06-21 10:12:12

标签: postgresql plpgsql database-trigger

我有一个表测试的触发器函数,其中包含以下代码片段:

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

所以我静态检查所有列的新值及其先前的值以确保完整性。现在,每当我的业务逻辑发生变化并且我必须在该表中添加新列时,我每次都必须修改此触发器。我认为如果能以某种方式动态检查该表的所有列,而不显式输入其名称,那会更好。

怎么做?

5 个答案:

答案 0 :(得分:8)

关于触发器中WHEN子句的9.0 beta2文档,可能在触发器体内的早期版本中使用:

OLD.* IS DISTINCT FROM NEW.*

或可能(from 8.2 release notes

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 ,其中OLDNEW都已定义。您尝试将此WHEN子句与INSERTDELETE触发器一起使用时会遇到异常。

并从根本上简化触发器功能

...
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,仅在需要时才会调用。

Read the fine print:

  

BEFORE触发器中,WHEN条件在之前评估   函数是或将被执行,因此使用WHEN并不重要   不同于在开始时测试相同的条件   触发功能。特别要注意的是NEW行   condition是当前值,可能由之前修改过   触发。此外,不允许BEFORE触发器WHEN条件   检查NEW行的系统列(例如oid),因为那些   还没有成功。

     

AFTER触发器中,WHEN条件在评估之后进行评估   发生行更新,它确定事件是否排队到   在声明结束时触发触发器。因此当AFTER触发时   WHEN条件不返回true,没有必要排队   事件也不会在语句结束时重新获取行。这可能导致   修改许多行的语句中的显着加速,如果是   触发器只需要为几行触发。

相关:

还要解决问题标题

  

是否可以动态循环表格的列?

是。例子: