PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

So vermeiden Sie Looping-Trigger-Aufrufe in PostgreSQL 9.2.1

Sie können dies mit Standard-Triggern tun BEFORE UPDATE OF ... ON ... .
Das Handbuch zu CREATE TRIGGER informiert:

Der Trigger wird nur ausgelöst, wenn mindestens eine der aufgelisteten Spalten als Ziel des UPDATE-Befehls erwähnt wird.

Und weiter unten:

Ein spaltenspezifischer Trigger (einer, der mit der UPDATE OF-Spaltennamensyntax definiert wurde) wird ausgelöst, wenn eine seiner Spalten als Ziele in der SET-Liste des UPDATE-Befehls aufgeführt ist. Es ist möglich, dass sich der Wert einer Spalte ändert, auch wenn der Trigger nicht ausgelöst wird, da Änderungen am Inhalt der Zeile durch BEFORE UPDATE-Trigger nicht berücksichtigt werden.

Fette Hervorhebung von mir. Also keine Endlosschleifen, da die Updates innerhalb des Triggers keinen weiteren Trigger aufrufen.

Testfall

Testtabelle erstellen (vereinfacht, ohne irrelevante Zeilen):

CREATE TABLE soil_samples (
  pgid SERIAL PRIMARY KEY

 ,utm_zone integer
 ,utm_easting integer
 ,utm_northing integer

 ,wgs84_longitude double precision
 ,wgs84_latitude double precision

 ,yt_albers_geom double precision
);

Dummy-Trigger für Ihre erste Anforderung:

Wenn ein Update für utm_zone durchgeführt wird , utm_easting , oder utm_northing , dann wgs_84_latitude , wgs84_longitude und yt_albers_geom werden durch einen Trigger aktualisiert.

CREATE OR REPLACE FUNCTION trg_upbef_utm()  RETURNS trigger AS
$func$
BEGIN
   NEW.wgs84_latitude  := NEW.wgs84_latitude + 10;
   NEW.wgs84_longitude := NEW.wgs84_longitude + 10;
   NEW.yt_albers_geom  := NEW.yt_albers_geom + 10;

   RETURN NEW;
END
$func$ LANGUAGE plpgsql;

CREATE TRIGGER upbef_utm
BEFORE UPDATE OF utm_zone, utm_easting, utm_northing ON soil_samples
FOR EACH ROW
WHEN (NEW.utm_zone     IS DISTINCT FROM OLD.utm_zone    OR
      NEW.utm_easting  IS DISTINCT FROM OLD.utm_easting OR
      NEW.utm_northing IS DISTINCT FROM OLD.utm_northing)  -- optional
EXECUTE PROCEDURE trg_upbef_utm();

Das WHEN Klausel ist optional. Verhindert, dass der Trigger ausgelöst wird, wenn sich tatsächlich kein Wert geändert hat.

Dummy-Trigger für Ihre zweite Anforderung:

Wenn ein Update für wgs84_latitude durchgeführt wird oder wgs84_longitude , dann alle utm_ Felder werden aktualisiert, ebenso wie yt_albers_geom .

CREATE OR REPLACE FUNCTION trg_upbef_wgs84()  RETURNS trigger AS
$func$
BEGIN
   NEW.utm_zone       := NEW.utm_zone + 100;
   NEW.utm_easting    := NEW.utm_easting + 100;
   NEW.utm_northing   := NEW.utm_northing + 100;
   NEW.yt_albers_geom := NEW.yt_albers_geom + 100;

   RETURN NEW;
END
$func$ LANGUAGE plpgsql;

CREATE TRIGGER upbef_wgs84
 BEFORE UPDATE OF wgs84_latitude, wgs84_longitude ON soil_samples
 FOR EACH ROW
 WHEN (NEW.wgs84_latitude  IS DISTINCT FROM OLD.wgs84_latitude OR
       NEW.wgs84_longitude IS DISTINCT FROM OLD.wgs84_longitude)  -- optional
 EXECUTE PROCEDURE trg_upbef_wgs84();

Auslöser für dritte Anforderung in dieser Richtung ...

Test

INSERT INTO soil_samples VALUES (1, 1,1,1, 2,2, 3) RETURNING *;

Lösen Sie upbef_utm aus :leeres Update, nichts passiert:

UPDATE soil_samples SET utm_zone = 1 RETURNING *;

Update mit aktueller Änderung:Der zweite Trigger upbef_wgs84 wird bei UPDATE OF utm_zone nicht ausgelöst !

UPDATE soil_samples SET utm_zone = 0 RETURNING *;

Lösen Sie upbef_wgs84 aus :

UPDATE soil_samples SET wgs84_latitude = 0 RETURNING *;

-> SQLfiddle-Demo.