Я пишу триггер проверки. Триггер должен проверить, что сумма массива равна другому полю. Поскольку у меня много экземпляров этой проверки, я хочу написать одну процедуру и создать несколько триггеров, каждый из которых должен иметь свой набор полей для проверки.
Например, у меня есть следующая схема:
CREATE TABLE daily_reports(
start_on date
, show_id uuid
, primary key(start_on, show_id)
-- _graph are hourly values, while _count is total for the report
, impressions_count bigint not null
, impressions_graph bigint[] not null
-- interactions_count, interactions_graph
-- twitter_interactions_count, twitter_interactions_graph
);
Проверка должна подтвердить это impressions_count = sum(impressions_graph)
.
Я застрял, потому что я не знаю, как динамически получить доступ к полю NEW
изнутри plpgsql:
CREATE FUNCTION validate_sum_of_array_equals_other() RETURNS TRIGGER AS $$
DECLARE
total bigint;
array_sum bigint;
BEGIN
-- TG_NARGS = 2
-- TG_ARGV[0] = 'impressions_count'
-- TG_ARGV[1] = 'impressions_graph'
-- How to access impressions_count and impressions_graph from NEW?
RETURN NEW;
END
$$ LANGUAGE plpgsql;
CREATE TRIGGER validate_daily_reports_impressions
ON daily_reports BEFORE INSERT OR UPDATE
FOR EACH ROW EXECUTE
validate_sum_of_array_equals_other('impressions_count', 'impressions_graph');
Я пытался выполнить динамические командыEXECUTE 'SELECT $1 FROM NEW' INTO total USING TG_ARGV[0]
, но PL / PGsql жалуется, что NEW - неизвестное отношение.
Я специально ориентируюсь на PostgreSQL 9.1.
postgresql
trigger
plpgsql
composite-types
Франсуа Босолей
источник
источник
NEW
в данный момент состоит в том, чтобы использоватьhstore(NEW)
и затем обращаться к полям какhstore
значениям, указанным в имени столбца. Который отстой, потому что тогда они все брошены,text
и если вы хотите работать с ними в их первоначальном виде, вы должны отбросить их обратно. Кроме того, вы можете написать триггер на другом процедурном языке, таком как PL / Python, который лучше поддерживает динамический доступ к записи.Ответы:
На самом деле, поскольку
NEW
это хорошо определенный составной тип, вы можете просто получить доступ к любому столбцу с простой и простой нотацией атрибутов. Сам по себе SQL не допускает динамические идентификаторы (имена таблиц или столбцов и т. Д.). Но вы можете использовать динамический SQL сEXECUTE
функцией PL / pgSQL.демонстрация
Приведение к не
text
является обязательным. Используя это, потому что это работает универсально. Если вы знаете тип, вы можете работать без кастинга ...Использование
format()
с%s
, потому что идентификатор уже экранирован в этой точке.В противном случае, использование
format()
с%I
для защиты от SQL инъекций.В качестве альтернативы , в Postgres 9.3 или новее вы можете конвертировать
NEW
в JSON сto_json()
ключами и получать к ним доступ:Поскольку имя столбца не объединяется в строку SQL, внедрение SQL невозможно, и имя не нужно экранировать.
db <> fiddle здесь (
EXCEPTION
вместо того,NOTICE
чтобы сделать эффект видимым).Связанные с:
источник