Въпреки че отговорът на @Gary е технически правилен, той пропуска да спомене, че PostgreSQL прави поддържа този формуляр:
UPDATE tbl
SET (col1, col2, ...) = (expression1, expression2, ..)
Прочетете ръководството на UPDATE
още веднъж.
Все още е трудно да го свърши с динамичен SQL. Тъй като не сте посочили, предполагам прост случай, при който изгледите се състоят от същите колони като техните основни таблици.
CREATE VIEW tbl_view AS SELECT * FROM tbl;
Проблеми
-
Специалният запис
NEW
не се вижда вътре вEXECUTE
. ПоддържамNEW
като единичен параметър сUSING
клауза наEXECUTE
. -
Както беше обсъдено,
UPDATE
със списъчна форма се нуждае от отделни стойности . Използвам подселекция, за да разделя записа на отделни колони:UPDATE ... FROM (SELECT ($1).*) x
(Скоба около
$1
не са по избор.) Това ми позволява просто да използвам два списъка с колони, изградени сstring_agg()
от каталожната таблица:един с и един без квалификация на таблицата. -
Не е възможно да се присвои стойност на ред като цяло на отделни колони. Ръководството:
Съгласно стандарта, изходната стойност за подсписък в скоби с имена на целеви колони може да бъде всеки израз със стойност на ред, който дава правилния брой колони. PostgreSQL позволява само стойността на източника да бъде конструктор на ред или под
SELECT
. -
INSERT
се реализира по-просто. Ако приемем, че структурата на изгледа и таблицата са идентични, пропускам списъка с дефиниции на колони. (Може да се подобри, вижте по-долу.)
Решение
Направих редица актуализации на подхода ви, за да го накарам да блести.
Функция за задействане за UPDATE
:
CREATE OR REPLACE FUNCTION f_trg_up()
RETURNS TRIGGER AS
$func$
DECLARE
tbl text := quote_ident(TG_TABLE_SCHEMA) || '.'
|| quote_ident(substring(TG_TABLE_NAME from '(.+)_view$'));
cols text;
vals text;
BEGIN
SELECT INTO cols, vals
string_agg(quote_ident(attname), ', ')
,string_agg('x.' || quote_ident(attname), ', ')
FROM pg_attribute
WHERE attrelid = tbl::regclass
AND NOT attisdropped -- no dropped (dead) columns
AND attnum > 0; -- no system columns
EXECUTE format('
UPDATE %s t
SET (%s) = (%s)
FROM (SELECT ($1).*) x
WHERE t.id = ($2).id'
, tbl, cols, vals) -- assuming unique "id" in every table
USING NEW, OLD;
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
Функция за задействане за INSERT
:
CREATE OR REPLACE FUNCTION f_trg_ins()
RETURNS TRIGGER AS
$func$
DECLARE
tbl text := quote_ident(TG_TABLE_SCHEMA) || '.'
|| quote_ident(substring(TG_TABLE_NAME from '(.+)_view$'));
BEGIN
EXECUTE 'INSERT INTO ' || tbl || ' SELECT ($1).*'
USING NEW;
RETURN NEW; -- don't return NULL unless you know what you're doing
END
$func$ LANGUAGE plpgsql;
Тригери:
CREATE TRIGGER trg_instead_up
INSTEAD OF UPDATE ON a_view
FOR EACH ROW EXECUTE PROCEDURE f_trg_up();
CREATE TRIGGER trg_instead_ins
INSTEAD OF INSERT ON a_view
FOR EACH ROW EXECUTE PROCEDURE f_trg_ins();
SQL Fiddle демонстриращ INSERT
и UPDATE
.
Основни точки
-
Включете името на схемата, за да направите препратката към таблицата недвусмислена. Може да има множество екземпляри на едно и също име на таблица в една и съща база данни в множество схеми!
-
Заявка
pg_attribute
вместоinformation_schema.columns
. Това е по-малко преносимо, но много по-бързо и ми позволява да използвам таблицата-OID.- Как да проверите дали таблица съществува в дадена схема
-
Имената на таблици НЕ са безопасни срещу SQLi когато се обработват като низове, както при изграждане на заявки за динамичен SQL. Избягайте с
quote_ident()
илиformat()
или с тип идентификатор на обект. Това включва специалните променливи на функцията за задействанеTG_TABLE_SCHEMA
иTG_TABLE_NAME
! -
Прехвърляне към идентификатора на обект тип
regclass
за да потвърдите, че името на таблицата е валидно и да получите OID за търсене в каталога. -
По избор използвайте
format()
за безопасно изграждане на динамичния низ на заявка. -
Няма нужда от динамичен SQL за първата заявка в каталожните таблици. По-бързо, по-лесно.
-
Използвайте
RETURN NEW
вместоRETURN NULL
в тези тригерни функции, освен ако не знаете какво правите. (NULL
ще отмениINSERT
за текущия ред.) -
Тази проста версия предполага, че всяка таблица (и изглед) има уникална колона с име
id
. По-сложна версия може да използва първичния ключ динамично. -
Функцията за
UPDATE
позволява колоните на изглед и таблица да бъдат в произволен ред , стига наборът да е същият. Функцията заINSERT
очаква колоните изглед и таблица да бъдат в идентичен ред . Ако искате да разрешите произволен ред, добавете списък с дефиниции на колони къмINSERT
команда, точно както сUPDATE
. -
Актуализираната версия обхваща и промените в
id
колона с помощта наOLD
допълнително.