Ich schreibe einen Validierungsauslöser. Der Trigger muss überprüfen, ob die Summe eines Arrays einem anderen Feld entspricht. Da ich viele Instanzen dieser Validierung habe, möchte ich eine einzelne Prozedur schreiben und mehrere Trigger mit jeweils unterschiedlichen Feldern erstellen, die überprüft werden sollen.
Zum Beispiel habe ich das folgende Schema:
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
);
Die Validierung muss dies bestätigen impressions_count = sum(impressions_graph)
.
Ich stecke fest, weil ich nicht weiß, wie ich NEW
von plpgsql aus dynamisch auf ein Feld zugreifen kann:
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');
Ich habe versucht , dynamisches Kommando ausführen , indem Sie EXECUTE 'SELECT $1 FROM NEW' INTO total USING TG_ARGV[0]
, aber PL / pgSQL beklagt , dass NEU eine unbekannte Beziehung ist.
Ich ziele speziell auf PostgreSQL 9.1 ab.
quelle
NEW
zu verwendenhstore(NEW)
und dann darauf zuzugreifenhstore
. Was scheiße ist, denn dann sind sie alle besetzttext
und wenn Sie mit ihnen in ihrem ursprünglichen Typ arbeiten möchten, müssen Sie sie zurückwerfen. Alternativ können Sie einen Trigger in einer anderen prozeduralen Sprache wie PL / Python schreiben, die den dynamischen Datensatzzugriff besser unterstützt.Antworten:
Da
NEW
es sich um einen genau definierten zusammengesetzten Typ handelt, können Sie einfach auf jede Spalte mit einfacher Attributnotation zugreifen. SQL selbst erlaubt keine dynamischen Bezeichner (Tabellen- oder Spaltennamen usw.). Sie können jedoch dynamisches SQL mitEXECUTE
in einer PL / pgSQL-Funktion verwenden.Demo
Die Besetzung
text
ist optional. Verwenden Sie es, weil es universell funktioniert. Wenn Sie wissen , die Art, können Sie ohne Gießen arbeiten ...Verwendung
format()
mit%s
, da der Bezeichner zu diesem Zeitpunkt bereits maskiert ist.Andernfalls verwenden Sie
format()
mit%I
, um sich vor SQL-Injection zu schützen.Alternativ können Sie in Postgres 9.3 oder höher
NEW
in JSON konvertierento_json()
und auf Spalten als Schlüssel zugreifen:Da der Spaltenname nicht mit einer SQL-Zeichenfolge verknüpft ist, ist eine SQL-Injection nicht möglich und der Name muss nicht maskiert werden.
db <> hier fummeln (mit
EXCEPTION
anstattNOTICE
den Effekt sichtbar zu machen).Verbunden:
quelle