sql >> Base de Datos >  >> RDS >> PostgreSQL

Cómo evitar llamadas de activación en bucle en PostgreSQL 9.2.1

Puede hacer esto con activadores estándar BEFORE UPDATE OF ... ON ... .
El manual sobre CREATE TRIGGER informa:

El activador solo se activará si al menos una de las columnas enumeradas se menciona como destino del comando ACTUALIZAR.

Y más abajo:

Un activador específico de columna (uno definido mediante la sintaxis UPDATE OF column_name) se activará cuando cualquiera de sus columnas se incluya como destino en la lista SET del comando UPDATE. Es posible que el valor de una columna cambie incluso cuando el activador no se activa, porque los cambios realizados en el contenido de la fila por los activadores ANTES DE LA ACTUALIZACIÓN no se tienen en cuenta.

Énfasis en negrita mío. Así que no hay bucles infinitos, porque las actualizaciones dentro del disparador no invocan otro disparador.

Caso de prueba

Crear tabla de prueba (simplificado, sin filas irrelevantes):

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

Disparador ficticio para su primer requisito:

Cuando se realiza una actualización en utm_zone , utm_easting , o utm_northing , luego wgs_84_latitude , wgs84_longitude y yt_albers_geom son actualizados por un disparador.

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

El WHEN cláusula es opcional. Evita que el activador se dispare cuando ningún valor ha cambiado realmente.

Disparador ficticio para su segundo requisito:

Cuando se realiza una actualización a wgs84_latitude o wgs84_longitude , luego todas las utm_ los campos se actualizan, así como 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();

Desencadenar para tercer requisito en este sentido...

Prueba

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

Activar upbef_utm :actualización vacía, no pasa nada:

UPDATE soil_samples SET utm_zone = 1 RETURNING *;

Actualizar con cambio real:el segundo activador upbef_wgs84 no se activará en UPDATE OF utm_zone !

UPDATE soil_samples SET utm_zone = 0 RETURNING *;

Activar upbef_wgs84 :

UPDATE soil_samples SET wgs84_latitude = 0 RETURNING *;

-> Demostración de SQLfiddle.