2

我有一个触发器函数,在更新 COLUMN A 时由多个表调用,以便可以根据来自不同函数的值更新 COLUMN B。(解释起来比实际上更复杂)。触发器函数接受 col_a 和 col_b,因为它们对于不同的表是不同的。

IF needs_updated THEN
    sql = format('($1).%2$s = dbo.foo(($1).%1$s); ', col_a, col_b);

    EXECUTE sql USING NEW;
END IF;

当我尝试运行上述内容时,格式会生成以下 sql:

($1).NameText = dbo.foo(($1).Name); 

当我使用 USING 执行 SQL 时,我期望会发生这样的事情(在没有动态 sql 的情况下直接执行时有效):

NEW.NameText = dbo.foo(NEW.Name); 

相反,我得到:

[42601] 错误:“$1”处或附近的语法错误

如何动态更新记录/复合类型 NEW 上的列?

4

2 回答 2

0

第一:这是 plpgsql 的一大痛点。所以我最好的建议是在其他一些 PL 中执行此操作,例如 plpythonu 或 plperl。在其中任何一个中这样做都是微不足道的。即使您不想在另一个 PL 中执行整个触发器,您仍然可以执行以下操作:

v_new RECORD;
BEGIN
v_new := plperl_function(NEW, column_a...)

在 plpgsql 中执行此操作的关键是创建一个包含您需要的 CTE:

c_new_old CONSTANT text := format(
  'WITH
    NEW AS (SELECT (r).* FROM (SELECT ($1)::%1$s r) s)
    , OLD AS (SELECT (r).* FROM (SELECT ($2)::%1$s r) s
    '
  , TG_RELID::regclass
);

您还需要定义一个纯记录的 v_new。然后,您可以执行以下操作:

-- Replace 2nd field in NEW with a new value
sql := c_new_old || $$SELECT row(NEW.a, $3, NEW.c) FROM NEW$$
EXECUTE sql INTO v_new USING NEW, OLD, new_value;
于 2016-02-29T20:13:48.920 回答
0

这行不通,因为NEW.NameText = dbo.foo(NEW.Name);不是正确的 sql 查询。而且我想不出你可以动态更新 NEW 的变量属性的方式。我的建议是明确定义每个表的行为:

IF TG_TABLE_SCHEMA = 'my_schema' THEN
    IF TG_TABLE_NAME = 'my_table_1' THEN
        NEW.a1 = foo(NEW.b1);
    ELSE IF TG_TABLE_NAME = 'my_table_2' THEN
        NEW.a2 = foo(NEW.b2);
    ... etc ...
    END IF;
END IF;
于 2016-02-25T18:31:31.350 回答