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

Dentro de una función de activación, cómo saber qué campos se están actualizando

Si una "fuente" no "envía un identificador", la columna permanecerá sin cambios. Entonces no puede detectar si el UPDATE actual fue realizada por la misma fuente que la última o por una fuente que no cambió la columna en absoluto. En otras palabras:esto no funciona correctamente.

Si la "fuente" es identificable por cualquier función de información de sesión, puede trabajar con eso. Me gusta:

NEW.column = session_user;

Incondicionalmente para cada actualización.

Solución general

Encontré una manera de resolver el problema original. La columna se establecerá en un valor predeterminado en cualquiera actualizar donde la columna no está actualizada (no en el SET lista de UPDATE ).

El elemento clave es un gatillo por columna introducido en PostgreSQL 9.0:un disparador específico de columna que usa UPDATE OF column_name cláusula.

El activador solo se activará si al menos una de las columnas enumeradas se menciona como objetivo de la UPDATE comando.

Esa es la única forma sencilla que encontré para distinguir si una columna se actualizó con un nuevo valor idéntico al anterior o si no se actualizó en absoluto.

Uno podría también analiza el texto devuelto por current_query() . Pero eso parece engañoso y poco confiable.

Funciones de activación

Asumo una columna col definido NOT NULL .

Paso 1: Establecer col a NULL si no cambia:

CREATE OR REPLACE FUNCTION trg_tbl_upbef_step1()
  RETURNS trigger AS
$func$
BEGIN
   IF OLD.col = NEW.col THEN
      NEW.col := NULL;      -- "impossible" value
   END IF;

   RETURN NEW;
END
$func$  LANGUAGE plpgsql;

Paso 2: Revertir al valor anterior. El activador solo se activará si el valor se actualizó realmente (ver más abajo):

CREATE OR REPLACE FUNCTION trg_tbl_upbef_step2()
  RETURNS trigger AS
$func$
BEGIN
   IF NEW.col IS NULL THEN
      NEW.col := OLD.col;
   END IF;

   RETURN NEW;
END
$func$  LANGUAGE plpgsql;

Paso 3: Ahora podemos identificar la actualización que falta y establecer un valor predeterminado en su lugar:

CREATE OR REPLACE FUNCTION trg_tbl_upbef_step3()
  RETURNS trigger AS
$func$
BEGIN
   IF NEW.col IS NULL THEN
      NEW.col := 'default value';
   END IF;

   RETURN NEW;
END
$func$  LANGUAGE plpgsql;

Disparadores

El desencadenante del Paso 2 se dispara por columna!

CREATE TRIGGER upbef_step1
  BEFORE UPDATE ON tbl
  FOR EACH ROW
  EXECUTE PROCEDURE trg_tbl_upbef_step1();

CREATE TRIGGER upbef_step2
  BEFORE UPDATE OF col ON tbl                -- key element!
  FOR EACH ROW
  EXECUTE PROCEDURE trg_tbl_upbef_step2();

CREATE TRIGGER upbef_step3
  BEFORE UPDATE ON tbl
  FOR EACH ROW
  EXECUTE PROCEDURE trg_tbl_upbef_step3();

Nombres de activadores son relevantes, porque se activan en orden alfabético (todos son BEFORE UPDATE )!

El procedimiento podría simplificarse con algo como "disparadores por columna" o cualquier otra forma de verificar la lista de objetivos de un UPDATE en un gatillo. Pero no veo ningún mango para esto.

Si col puede ser NULL , use cualquier otro valor intermedio "imposible" y busque NULL adicionalmente en la función de activación 1:

IF OLD.col IS NOT DISTINCT FROM NEW.col THEN
    NEW.col := '#impossible_value#';
END IF;

Adapte el resto en consecuencia.