PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Come evitare il loop delle chiamate trigger in PostgreSQL 9.2.1

Puoi farlo con attivatori standard BEFORE UPDATE OF ... ON ... .
Il manuale su CREATE TRIGGER informa:

Il trigger si attiverà solo se almeno una delle colonne elencate è menzionata come destinazione del comando UPDATE.

E più in basso:

Un trigger specifico della colonna (definito utilizzando UPDATE OF column_namesyntax) si attiverà quando una qualsiasi delle sue colonne viene elencata come destinazione nell'elenco SET del comando UPDATE. È possibile che il valore di una colonna cambi anche quando l'attivatore non viene attivato, perché le modifiche apportate al contenuto della riga dagli attivatori PRIMA DELL'AGGIORNAMENTO non vengono considerate.

Enfasi in grassetto mio. Quindi nessun ciclo infinito, perché gli aggiornamenti all'interno del trigger non richiamano un altro trigger.

Caso di prova

Crea tabella di test (semplificata, senza righe irrilevanti):

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
);

Attivatore fittizio per il tuo primo requisito:

Quando viene eseguito un aggiornamento a utm_zone , utm_easting o utm_northing , quindi wgs_84_latitude , wgs84_longitude e yt_albers_geom vengono aggiornati da un trigger.

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();

Il WHEN la clausola è facoltativa. Impedisce l'attivazione del trigger quando nessun valore è effettivamente cambiato.

Attivatore fittizio per il tuo secondo requisito:

Quando viene eseguito un aggiornamento a wgs84_latitude o wgs84_longitude , quindi tutti gli utm_ i campi vengono aggiornati, così come 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();

Attivazione del terzo requisito in questo senso...

Prova

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

Attiva upbef_utm :aggiornamento vuoto, non succede nulla:

UPDATE soil_samples SET utm_zone = 1 RETURNING *;

Aggiornamento con modifica effettiva:il secondo trigger upbef_wgs84 non si attiverà su UPDATE OF utm_zone !

UPDATE soil_samples SET utm_zone = 0 RETURNING *;

Attiva upbef_wgs84 :

UPDATE soil_samples SET wgs84_latitude = 0 RETURNING *;

-> Demo di SQLfiddle.