PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

INSERT z dynamiczną nazwą tabeli w funkcji wyzwalacza

PostgreSQL 9.1 lub nowszy

format() ma wbudowany sposób ucieczki identyfikatorów. Prostsze niż wcześniej:

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;

Działa z VALUES również wyrażenie.

db<>graj tutaj
Stary sqlfiddle.

Główne punkty

  • Użyj format() lub quote_ident() cytować identyfikatory (automatycznie i tylko w razie potrzeby), chroniąc w ten sposób przed wstrzyknięciem SQL i prostymi naruszeniami składni.
    Jest to konieczne , nawet z własnymi nazwami stołów!
  • Kwalifikacja schematu nazwy tabeli. W zależności od bieżącej search_path ustawienie samej nazwy tabeli może w inny sposób rozwiązać inną tabelę o tej samej nazwie w innym schemacie.
  • Użyj EXECUTE dla dynamicznych instrukcji DDL.
  • Przekaż wartości bezpiecznie z USING klauzula.
  • Zapoznaj się z doskonałą instrukcją wykonywania poleceń dynamicznych w plpgsql.
  • Pamiętaj, żeRETURN OLD; w funkcji wyzwalacza jest wymagane dla wyzwalacza BEFORE DELETE . Szczegóły w instrukcji tutaj.

Otrzymujesz komunikat o błędzie w Twojej prawie udanej wersji, ponieważ OLD jest niewidoczny wewnątrz EXECUTE . A jeśli chcesz połączyć poszczególne wartości rozłożonego wiersza, tak jak próbowałeś, musisz przygotować reprezentację tekstową każdej kolumny za pomocą quote_literal() aby zagwarantować poprawną składnię. Trzeba by też wiedzieć nazwy kolumn wcześniej, aby je obsłużyć lub przeszukać katalogi systemowe - co stoi w sprzeczności z twoją ideą posiadania prostej, dynamicznej funkcji wyzwalania ...

Moje rozwiązanie pozwala uniknąć tych wszystkich komplikacji. Również nieco uproszczona.

PostgreSQL 9.0 lub starszy

format() nie jest jeszcze dostępny, więc:

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;

Powiązane:

  • Jak dynamicznie używać TG_TABLE_NAME w PostgreSQL 8.2?


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL 11:Co nowego

  2. Jak działa funkcja Sign() w PostgreSQL

  3. pgDash Alternatives - Monitorowanie bazy danych PostgreSQL za pomocą ClusterControl

  4. Dodaj tygodnie do daty w PostgreSQL

  5. Identyfikator automatycznego przypisywania Railsów, który już istnieje