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

Comment enregistrer une donnée avec virgule en caractère variable qui passe par un trigger ?

Vous pouvez utiliser format() pour faciliter la création d'une requête SQL dynamique car elle traitera automatiquement correctement les identificateurs et les littéraux. Une chose que les gens oublient généralement est que vous pouvez étendre une seule expression d'enregistrement à toutes ses colonnes en utilisant (...).* - cela fonctionne aussi pour NEW et OLD enregistrer des variables dans un déclencheur, par ex. select (new).*

Vous pouvez également passer des variables à un SQL dynamique avec le using mot-clé du execute déclaration. Il n'est pas nécessaire de convertir l'enregistrement dans les deux sens entre un enregistrement et une représentation textuelle.

En utilisant cette possibilité, votre fonction de déclenchement peut être simplifiée pour :

DECLARE 
  l_sql text;
BEGIN
    IF TG_TABLE_SCHEMA = 'public' THEN
      newtable := TG_TABLE_NAME || '_actividad';
    ELSE
      newtable := TG_TABLE_SCHEMA || '_' || TG_TABLE_NAME || '_actividad';
    END IF;

    PERFORM creartablaactividad(TG_TABLE_SCHEMA, TG_TABLE_NAME);
    l_sql := 'INSERT INTO actividad.%I  SELECT current_user, current_timestamp, %L, ($1).*';

    IF TG_OP = 'DELETE' THEN
      execute format(l_sql, newtable, 'D') using OLD;
      RETURN OLD;
    ELSE
      -- covers UPDATE and INSERT
      execute format(l_sql, newtable, 'U') using NEW;
      RETURN NEW;
    END IF;

    RETURN NULL; -- result is ignored since this is an AFTER trigger
END;

Utiliser des espaces réservés comme %I et %L permet également de définir le SQL réel une seule fois et de le réutiliser. Ces "paramètres" sont remplacés par le format() fonction (qui conserve le $1 )

Notez l'utilisation de ($1).* à l'intérieur de la chaîne SQL. Cela fera execute instruction développer le paramètre d'enregistrement $1 à toutes ses colonnes. L'enregistrement lui-même est passé "nativement" avec le USING mot-clé.

L'utilisation de INSERT sans liste de colonnes cible (insert into some_table ... au lieu de insert into some_table (col1, col2, ...) ... ) est une chose assez fragile à faire. Si la source et la cible ne correspondent pas, l'insertion peut échouer assez facilement. .

Si vous n'exécutez pas de rapports massifs sur les tables d'audit (où avoir des noms de colonnes explicites serait beaucoup plus efficace), vous voudrez peut-être penser à un déclencheur d'audit plus générique utilisant un JSON ou HSTORE colonne pour stocker l'intégralité de l'enregistrement. Plusieurs déclencheurs d'audit prêts à l'emploi sont disponibles :