2016-02-25 37 views
2

我有一个触发器函数,当COLUMN A更新时由几个表调用,以便可以根据不同函数的值更新COLUMN B. (解释比实际更复杂)。触发器函数接受col_a和col_b,因为它们对于不同的表是不同的。如何在触发程序中使用动态sql设置复合类型列

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); 

当我执行与我期待这样的事情发生(当直线执行其运作使用SQL时没有动态SQL):

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

相反,我得到:

[42601] ERROR: syntax error at or near "$1"

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

回答

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; 
+0

Ildar,谢谢你的回应。不幸的是,'needs_updated''背后有逻辑,每个表(和指定的列)都会重复使用''needs_updated''',那么我可能会为每个表创建单独的触发函数。我希望能够减少重复的逻辑。 – Airn5475

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; 
相关问题