我有一个触发器函数,当更新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?
上的列答案 0 :(得分: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;
答案 1 :(得分: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;