sql >> Databáze >  >> RDS >> PostgreSQL

INSERT s názvem dynamické tabulky ve funkci spouštění

PostgreSQL 9.1 nebo novější

format() má vestavěný způsob, jak uniknout identifikátorům. Jednodušší než dříve:

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;

Pracuje s VALUES výraz také.

db<>zde hrajte
Starý sqlfiddle.

Hlavní body

  • Použijte format() nebo quote_ident() citovat identifikátory (automaticky a pouze tam, kde je to nutné), a bránit se tak před vkládáním SQL a jednoduchým porušením syntaxe.
    To je nezbytné , dokonce i s vlastními názvy tabulek!
  • Uveďte název tabulky podle schématu. V závislosti na aktuální search_path nastavení holého názvu tabulky by se jinak mohlo převést na jinou tabulku se stejným názvem v jiném schématu.
  • Použijte EXECUTE pro dynamické příkazy DDL.
  • Předávejte hodnoty bezpečně pomocí USING doložka.
  • Prostudujte si podrobnou příručku o provádění dynamických příkazů v plpgsql.
  • Všimněte si, žeRETURN OLD; ve funkci spouštění je vyžadováno pro spouštění BEFORE DELETE . Podrobnosti v návodu zde.

Zobrazí se chybová zpráva ve vaší téměř úspěšné verzi, protože OLD není vidět uvnitř EXECUTE . A pokud chcete zřetězit jednotlivé hodnoty rozloženého řádku, jak jste to zkusili, musíte připravit textovou reprezentaci každého jednotlivého sloupce pomocí quote_literal() aby byla zaručena platná syntaxe. Také byste to museli vědět názvy sloupců předem, abyste je mohli zpracovat nebo se dotazovat na systémové katalogy – což je v rozporu s vaší představou jednoduché, dynamické spouštěcí funkce...

Mé řešení se všem těmto komplikacím vyhne. Také trochu zjednodušené.

PostgreSQL 9.0 nebo starší

format() zatím není k dispozici, takže:

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;

Související:

  • Jak dynamicky používat TG_TABLE_NAME v PostgreSQL 8.2?


  1. Skriptujte celou databázi SQL-Server

  2. Naučte se ukládat a analyzovat dokumenty v systému souborů Windows pomocí SQL Server Semantic Search – část 1

  3. Jak změnit prioritu pro souběžný program

  4. SQL UNION Cheat Sheet s 10 snadnými a užitečnými tipy