J'écris un déclencheur de validation. Le déclencheur doit valider que la somme d'un tableau est égale à un autre champ. Étant donné que j'ai de nombreuses instances de cette validation, je veux écrire une seule procédure et créer plusieurs déclencheurs, chacun avec un ensemble différent de champs à vérifier.
Par exemple, j'ai le schéma suivant:
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 validation doit le confirmer impressions_count = sum(impressions_graph)
.
Je suis bloqué car je ne sais pas comment accéder dynamiquement à un champ depuis 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');
J'ai essayé d' exécuter des commandes dynamiques en faisant EXECUTE 'SELECT $1 FROM NEW' INTO total USING TG_ARGV[0]
, mais PL / PGsql se plaint que NEW est une relation inconnue.
Je cible spécifiquement PostgreSQL 9.1.
postgresql
trigger
plpgsql
composite-types
François Beausoleil
la source
la source
NEW
pour le moment est d'utiliserhstore(NEW)
puis d'accéder aux champs en tant quehstore
valeurs saisies par nom de colonne. Ce qui est nul, car ils sont tous castéstext
et si vous souhaitez travailler avec eux dans leur type d'origine, vous devez les restituer. Alternativement, vous pouvez écrire un déclencheur dans un autre langage procédural comme PL / Python qui prend mieux en charge l'accès aux enregistrements dynamiques.Réponses:
En fait, comme il
NEW
s'agit d'un type composite bien défini, vous pouvez simplement accéder à n'importe quelle colonne avec une notation d'attribut simple et simple. SQL lui-même ne permet pas les identifiants dynamiques (noms de table ou de colonne, etc.). Mais vous pouvez utiliser du SQL dynamique avecEXECUTE
dans une fonction PL / pgSQL.Démo
La conversion en
text
est facultative. L'utiliser, car cela fonctionne universellement. Si vous connaissez le type, vous pouvez travailler sans lancer ...Utilisation
format()
avec%s
, car l'identifiant est déjà échappé à ce stade.Sinon, utilisez
format()
avec%I
pour vous protéger contre l'injection SQL.Alternativement , dans Postgres 9.3 ou version ultérieure, vous pouvez convertir
NEW
en JSON avecto_json()
et accéder aux colonnes en tant que clés:Étant donné que le nom de la colonne n'est pas concaténé dans une chaîne SQL, l'injection SQL n'est pas possible et le nom n'a pas besoin d'être échappé.
db <> joue ici (avec
EXCEPTION
au lieu deNOTICE
pour rendre l'effet visible).En relation:
la source