2016-02-25 5 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''', которая будет повторяться для каждой таблицы (и указанных столбцов), и в этот момент я мог бы также создать отдельные триггерные функции для каждой таблицы. Я надеялся сократить повторяющуюся логику. – Airn5475

0

Первое: Это гигантская боль в plpgsql. Поэтому моя лучшая рекомендация - сделать это в некоторых других PL, таких как plpythonu или plperl. Выполнение этого в любом из них было бы тривиальным. Даже если вы не хотите, чтобы сделать весь триггер в другой PL, еще можно было сделать что-то вроде:

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

Ключ к делать это в plpgsql создает КТР, который имеет то, что вам нужно в нем:

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;