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

INSERTAR con nombre de tabla dinámica en la función de activación

PostgreSQL 9.1 o posterior

format() tiene una forma integrada de escapar de los identificadores. Más simple que antes:

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;

Funciona con un VALUES expresión también.

db<>violín aquí
Antiguo sqlfiddle.

Puntos principales

  • Usar format() o quote_ident() para citar identificadores (automáticamente y solo cuando sea necesario), protegiendo así contra la inyección de SQL y violaciones de sintaxis simples.
    Esto es necesario , ¡incluso con sus propios nombres de tabla!
  • Esquema:califique el nombre de la tabla. Dependiendo de la search_path actual de lo contrario, establecer un nombre de tabla simple podría resolverse en otra tabla con el mismo nombre en un esquema diferente.
  • Utilice EXECUTE para sentencias DDL dinámicas.
  • Pasar valores de forma segura con el USING cláusula.
  • Consulte el excelente manual sobre la ejecución de comandos dinámicos en plpgsql.
  • Tenga en cuenta que RETURN OLD; en la función de disparo es necesario para un disparo BEFORE DELETE . Detalles en el manual aquí.

Recibe el mensaje de error en su versión casi exitosa porque OLD es no visible dentro de EXECUTE . Y si desea concatenar valores individuales de la fila descompuesta como lo intentó, debe preparar la representación de texto de cada columna con quote_literal() para garantizar una sintaxis válida. También tendrías que saber nombres de columna de antemano para manejarlos o consultar los catálogos del sistema, lo que va en contra de su idea de tener una función de activación simple y dinámica...

Mi solución evita todas estas complicaciones. También simplificado un poco.

PostgreSQL 9.0 o anterior

format() aún no está disponible, así que:

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;

Relacionado:

  • ¿Cómo utilizar dinámicamente TG_TABLE_NAME en PostgreSQL 8.2?