2016-02-25 16 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; 
相關問題