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

Dans une fonction de déclenchement, comment obtenir quels champs sont mis à jour

Si une "source" n'"envoie pas d'identifiant", la colonne sera inchangée. Ensuite, vous ne pouvez pas détecter si la UPDATE actuelle a été fait par la même source que la dernière ou par une source qui n'a pas du tout changé la colonne. En d'autres termes :cela ne fonctionne pas correctement.

Si la "source" est identifiable par n'importe quelle fonction d'information de session, vous pouvez travailler avec cela. Comme :

NEW.column = session_user;

Inconditionnellement pour chaque mise à jour.

Solution générale

J'ai trouvé un moyen de résoudre le problème d'origine. La colonne sera définie sur une valeur par défaut dans tout mettre à jour où la colonne n'est pas mise à jour (pas dans le SET liste des UPDATE ).

L'élément clé est un déclencheur par colonne introduit dans PostgreSQL 9.0 - un déclencheur spécifique à une colonne utilisant le UPDATE OF column_name clause.

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

C'est le seul moyen simple que j'ai trouvé pour distinguer si une colonne a été mise à jour avec une nouvelle valeur identique à l'ancienne, ou pas du tout mise à jour.

On pourrait analyse également le texte renvoyé par current_query() . Mais cela semble délicat et peu fiable.

Fonctions de déclenchement

Je suppose une colonne col défini NOT NULL .

Étape 1 : Définir col à NULL si inchangé :

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;

Étape 2 : Revenir à l'ancienne valeur. Le déclencheur ne sera activé que si la valeur a été réellement mise à jour (voir ci-dessous) :

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;

Étape 3 : Nous pouvons maintenant identifier la mise à jour manquante et définir une valeur par défaut à la place :

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;

Déclencheurs

Le déclencheur de l'Étape 2 est déclenché par colonne !

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

Noms des déclencheurs sont pertinents, car ils sont déclenchés par ordre alphabétique (tous étant BEFORE UPDATE ) !

La procédure pourrait être simplifiée avec quelque chose comme des "déclencheurs par colonne" ou tout autre moyen de vérifier la liste cible d'un UPDATE dans un déclencheur. Mais je ne vois pas de poignée pour cela.

Si col peut être NULL , utilisez toute autre valeur intermédiaire "impossible" et vérifiez NULL en plus dans la fonction de déclenchement 1 :

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

Adaptez le reste en conséquence.