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

All'interno di una funzione trigger, come ottenere quali campi vengono aggiornati

Se una "fonte" non "invia un identificatore", la colonna rimarrà invariata. Quindi non puoi rilevare se l'attuale UPDATE è stato eseguito dalla stessa fonte dell'ultima o da una fonte che non ha modificato affatto la colonna. In altre parole:questo non funziona correttamente.

Se la "fonte" è identificabile da qualsiasi funzione di informazioni sulla sessione, puoi lavorare con quella. Come:

NEW.column = session_user;

Incondizionatamente per ogni aggiornamento.

Soluzione generale

Ho trovato un modo per risolvere il problema originale. La colonna verrà impostata su un valore predefinito in qualsiasi aggiorna dove la colonna è non aggiornata (non nel SET elenco del UPDATE ).

L'elemento chiave è un attivatore per colonna introdotto in PostgreSQL 9.0 - un trigger specifico per la colonna che utilizza UPDATE OF column_name clausola.

L'attivatore si attiverà solo se almeno una delle colonne elencate è menzionata come destinazione di UPDATE comando.

Questo è l'unico modo semplice che ho trovato per distinguere se una colonna è stata aggiornata con un nuovo valore identico al vecchio e se non è stata aggiornata affatto.

Uno potrebbe analizza anche il testo restituito da current_query() . Ma sembra complicato e inaffidabile.

Funzioni di attivazione

Presumo una colonna col definito NOT NULL .

Passaggio 1: Imposta col a NULL se invariato:

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;

Passaggio 2: Ripristina il vecchio valore. Il trigger verrà attivato solo se il valore è stato effettivamente aggiornato (vedi sotto):

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;

Passaggio 3: Ora possiamo identificare l'aggiornamento mancante e impostare invece un valore predefinito:

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;

Trigger

Il trigger per il Passaggio 2 viene sparato per colonna!

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

Nomi trigger sono rilevanti, perché vengono attivati ​​in ordine alfabetico (tutti BEFORE UPDATE )!

La procedura potrebbe essere semplificata con qualcosa come "attivatori per non colonna" o in qualsiasi altro modo per controllare l'elenco di destinazione di un UPDATE in un grilletto. Ma non vedo alcuna maniglia per questo.

Se col può essere NULL , usa qualsiasi altro valore intermedio "impossibile" e controlla NULL inoltre nella funzione trigger 1:

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

Adatta il resto di conseguenza.