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

INSERT avec le nom de la table dynamique dans la fonction de déclenchement

PostgreSQL 9.1 ou version ultérieure

format() a un moyen intégré d'échapper aux identifiants. Plus simple qu'avant :

CREATE OR REPLACE FUNCTION foo_before()
  RETURNS trigger AS
$func$
BEGIN
   EXECUTE format('INSERT INTO %I.%I SELECT $1.*'
                , TG_TABLE_SCHEMA, TG_TABLE_NAME || 'shadow')
   USING OLD;

   RETURN OLD;
END
$func$  LANGUAGE plpgsql;

Fonctionne avec un VALUES expression également.

db<>jouez ici
Vieux sqlfiddle.

Points majeurs

  • Utilisez format() ou quote_ident() pour citer les identifiants (automatiquement et uniquement si nécessaire), se défendant ainsi contre l'injection SQL et les simples violations de syntaxe.
    C'est nécessaire , même avec vos propres noms de table !
  • Schéma-qualifie le nom de la table. En fonction du search_path actuel la définition d'un nom de table simple pourrait sinon être résolue en une autre table du même nom dans un schéma différent.
  • Utilisez EXECUTE pour les instructions DDL dynamiques.
  • Transmettre des valeurs en toute sécurité avec le USING clause.
  • Consultez le bon manuel sur l'exécution des commandes dynamiques dans plpgsql.
  • Notez queRETURN OLD; dans la fonction trigger est requis pour un trigger BEFORE DELETE . Détails dans le manuel ici.

Vous obtenez le message d'erreur dans votre version presque réussie car OLD n'est pas visible dans EXECUTE . Et si vous voulez concaténer des valeurs individuelles de la ligne décomposée comme vous l'avez essayé, vous devez préparer la représentation textuelle de chaque colonne avec quote_literal() pour garantir une syntaxe valide. Vous devriez également savoir noms de colonnes au préalable pour les manipuler ou interroger les catalogues système - ce qui va à l'encontre de votre idée d'avoir une fonction de déclenchement simple et dynamique...

Ma solution évite toutes ces complications. Aussi simplifié un peu.

PostgreSQL 9.0 ou version antérieure

format() n'est pas encore disponible, donc :

CREATE OR REPLACE FUNCTION foo_before()
  RETURNS trigger AS
$func$
BEGIN
    EXECUTE 'INSERT INTO ' || quote_ident(TG_TABLE_SCHEMA)
                    || '.' || quote_ident(TG_TABLE_NAME || 'shadow')
                    || ' SELECT $1.*'
    USING OLD;

    RETURN OLD;
END
$func$  LANGUAGE plpgsql;

Connexe :

  • Comment utiliser dynamiquement TG_TABLE_NAME dans PostgreSQL 8.2 ?