PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment éviter les appels de déclencheur en boucle dans PostgreSQL 9.2.1

Vous pouvez le faire avec des déclencheurs standard BEFORE UPDATE OF ... ON ... .
Le manuel sur CREATE TRIGGER informe :

Le déclencheur ne se déclenchera que si au moins une des colonnes répertoriées est mentionnée comme cible de la commande UPDATE.

Et plus bas :

Un déclencheur spécifique à une colonne (un déclencheur défini à l'aide de la syntaxe UPDATE OF nom_colonne) se déclenche lorsque l'une de ses colonnes est répertoriée comme cible dans la liste SET de la commande UPDATE. Il est possible que la valeur d'une colonne change même lorsque le déclencheur n'est pas déclenché, car les modifications apportées au contenu de la ligne par les déclencheurs BEFORE UPDATE ne sont pas prises en compte.

Bold emphase mienne. Donc pas de boucles infinies, car les mises à jour à l'intérieur du déclencheur n'invoquent pas un autre déclencheur.

Cas de test

Créer un tableau de test (simplifié, sans lignes non pertinentes) :

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

Déclencheur factice pour votre première exigence :

Lorsqu'une mise à jour est effectuée sur utm_zone , utm_easting , ou utm_northing , puiswgs_84_latitude , wgs84_longitude , et yt_albers_geom sont mis à jour par un déclencheur.

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

Le WHEN clause est facultative. Empêche le déclencheur de se déclencher lorsqu'aucune valeur n'a réellement changé.

Déclencheur factice pour votre deuxième exigence :

Lorsqu'une mise à jour est effectuée sur wgs84_latitude ou wgs84_longitude , puis tous les utm_ les champs sont mis à jour, ainsi que 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();

Déclencheur pour la troisième exigence dans ce sens...

Tester

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

Déclencher upbef_utm :mise à jour vide, rien ne se passe :

UPDATE soil_samples SET utm_zone = 1 RETURNING *;

Mise à jour avec changement réel :Le deuxième déclencheur upbef_wgs84 ne se déclenchera pas sur UPDATE OF utm_zone !

UPDATE soil_samples SET utm_zone = 0 RETURNING *;

Déclencher upbef_wgs84 :

UPDATE soil_samples SET wgs84_latitude = 0 RETURNING *;

-> Démo SQLfiddle.