Estou escrevendo um gatilho de validação. O gatilho deve validar que a soma de uma matriz seja igual a outro campo. Como tenho muitas instâncias dessa validação, quero escrever um único procedimento e criar vários gatilhos, cada um com um conjunto diferente de campos para verificar.
Por exemplo, eu tenho o seguinte esquema:
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
);
A validação deve confirmar isso impressions_count = sum(impressions_graph)
.
Estou preso porque não sei como acessar dinamicamente um campo NEW
de dentro do 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');
Tentei Execução de comandos dinâmicos fazendo EXECUTE 'SELECT $1 FROM NEW' INTO total USING TG_ARGV[0]
, mas PL / pgSQL reclama que NOVO é uma relação desconhecida.
Estou direcionado especificamente ao PostgreSQL 9.1.
postgresql
trigger
plpgsql
composite-types
François Beausoleil
fonte
fonte
NEW
no momento é usarhstore(NEW)
e acessar os campos comohstore
valores digitados pelo nome da coluna. O que é péssimo, porque eles são todos convertidostext
e, se você quiser trabalhar com eles no tipo original, precisará revertê-los. Como alternativa, você pode escrever um gatilho em outra linguagem processual, como PL / Python, que tenha melhor suporte para acesso dinâmico a registros.Respostas:
Na verdade, como
NEW
é um tipo composto bem definido, você pode acessar qualquer coluna com notação de atributo simples e simples. O próprio SQL não permite identificadores dinâmicos (nomes de tabelas ou colunas etc.). Mas você pode usar o SQL dinâmico comEXECUTE
uma função PL / pgSQL.Demo
O elenco para
text
é opcional. Usá-lo, porque funciona universalmente. Se você conhece o tipo, pode trabalhar sem transmitir ...Usando
format()
with%s
, porque o identificador já escapou nesse ponto.Senão, use
format()
com%I
para proteger contra injeção de SQL.Como alternativa , no Postgres 9.3 ou posterior, você pode converter
NEW
para JSON comto_json()
e acessar colunas como chaves:Como o nome da coluna não é concatenado em uma sequência SQL, a injeção SQL não é possível e o nome não precisa ser escapado.
db <> mexe aqui (com em
EXCEPTION
vez deNOTICE
para tornar o efeito visível).Palavras-chave:
fonte