Estoy escribiendo un activador de validación. El disparador debe validar que la suma de una matriz es igual a otro campo. Como tengo muchas instancias de esta validación, quiero escribir un solo procedimiento y crear múltiples disparadores, cada uno con un conjunto diferente de campos para verificar.
Por ejemplo, tengo el siguiente 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
);
La validación debe confirmar eso impressions_count = sum(impressions_graph)
.
Estoy atascado porque no sé cómo acceder dinámicamente a un campo desde 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');
Intenté ejecutar comandos dinámicos haciendo EXECUTE 'SELECT $1 FROM NEW' INTO total USING TG_ARGV[0]
, pero PL / PGsql se queja de que NUEVO es una relación desconocida.
Me dirijo específicamente a PostgreSQL 9.1.
postgresql
trigger
plpgsql
composite-types
François Beausoleil
fuente
fuente
NEW
en este momento es usarhstore(NEW)
y luego acceder a los campos comohstore
valores ingresados por nombre de columna. Lo que apesta, porque entonces todos están emitidostext
y si quieres trabajar con ellos en su tipo original, tienes que devolverlos. Alternativamente, puede escribir un activador en otro lenguaje de procedimiento como PL / Python que tenga un mejor soporte para el acceso dinámico a registros.Respuestas:
En realidad, dado que
NEW
es un tipo compuesto bien definido, puede acceder a cualquier columna con notación de atributo simple y llanamente. El propio SQL no permite identificadores dinámicos (nombres de tabla o columna, etc.). Pero puede usar SQL dinámico conEXECUTE
una función PL / pgSQL.Manifestación
El reparto a
text
es opcional. Usándolo, porque funciona universalmente. Si conoce el tipo, puede trabajar sin lanzar ...Usando
format()
con%s
, porque el identificador ya se escapó en ese punto.De lo contrario, el uso
format()
de%I
para proteger contra la inyección de SQL.Alternativamente , en Postgres 9.3 o posterior, puede convertir
NEW
a JSON conto_json()
y acceder a las columnas como claves:Dado que el nombre de la columna no se concatena en una cadena SQL, la inyección SQL no es posible y no es necesario escapar del nombre.
db <> violín aquí (con en
EXCEPTION
lugar deNOTICE
hacer visible el efecto).Relacionado:
fuente