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

Příkaz EXECUTE...INTO...USING v PL/pgSQL nelze provést do záznamu?

Jednodušší alternativa k vaší zveřejněné odpovědi. Mělo by fungovat mnohem lépe.

Tato funkce načte řádek z dané tabulky (in_table_name ) a hodnotu primárního klíče (in_row_pk ) a vloží jej jako nový řádek do stejné tabulky, přičemž některé hodnoty budou nahrazeny (in_override_values ). Vrátí se nová výchozí hodnota primárního klíče (pk_new ).

CREATE OR REPLACE FUNCTION f_clone_row(in_table_name regclass
                                     , in_row_pk int
                                     , in_override_values hstore
                                     , OUT pk_new int) AS
$func$
DECLARE
   _pk   text;  -- name of PK column
   _cols text;  -- list of names of other columns
BEGIN

-- Get name of PK column
SELECT INTO _pk  a.attname
FROM   pg_catalog.pg_index     i
JOIN   pg_catalog.pg_attribute a ON a.attrelid = i.indrelid
                                AND a.attnum   = i.indkey[0]  -- 1 PK col!
WHERE  i.indrelid = 't'::regclass
AND    i.indisprimary;

-- Get list of columns excluding PK column
_cols := array_to_string(ARRAY(
      SELECT quote_ident(attname)
      FROM   pg_catalog.pg_attribute
      WHERE  attrelid = in_table_name -- regclass used as OID
      AND    attnum > 0               -- exclude system columns
      AND    attisdropped = FALSE     -- exclude dropped columns
      AND    attname <> _pk           -- exclude PK column
      ), ',');

-- INSERT cloned row with override values, returning new PK
EXECUTE format('
   INSERT INTO %1$I (%2$s)
   SELECT %2$s
   FROM  (SELECT (t #= $1).* FROM %1$I t WHERE %3$I = $2) x
   RETURNING %3$I'
 , in_table_name, _cols, _pk)
USING   in_override_values, in_row_pk -- use override values directly
INTO    pk_new;                       -- return new pk directly

END
$func$ LANGUAGE plpgsql;

Volejte:

SELECT f_clone_row('t', 1, '"col1"=>"foo_new","col2"=>"bar_new"'::hstore);

SQL Fiddle.

  • Použijte regclass jako typ vstupního parametru, takže pro začátek lze použít pouze platné názvy tabulek a je vyloučena injekce SQL. Funkce také selže dříve a elegantněji, pokud zadáte neplatný název tabulky.

  • Použijte OUT parametr (pk_new ) pro zjednodušení syntaxe.

  • Není třeba zjišťovat další hodnotu primárního klíče ručně. Vkládá se automaticky a poté se vrací. To je nejen jednodušší a rychlejší, ale také se vyhnete plýtvání nebo nefunkčním pořadovým číslům.

  • Použijte format() zjednodušit sestavování řetězce dynamického dotazu a snížit jeho náchylnost k chybám. Všimněte si, jak používám poziční parametry pro identifikátory a řetězce.

  • Stavím na vašem implicitním předpokladu že povolené tabulky mají jeden sloupec primárního klíče typu integer s výchozí hodnotou sloupce . Obvykle sériový sloupce.

  • Klíčovým prvkem funkce je poslední INSERT :

    • Sloučit přepsané hodnoty se stávajícím řádkem pomocí #= operátor v dílčím výběru a okamžitě rozložte výsledný řádek.
    • Pak můžete vybrat pouze relevantní sloupce v hlavním SELECT .
    • Nechte Postgres přiřadit výchozí hodnotu pro PK a získat ji zpět pomocí RETURNING doložka.
    • Zapište vrácenou hodnotu do OUT parametr přímo.
    • Vše se provádí jediným příkazem SQL, který je obecně nejrychlejší.


  1. Nemohu přijít na to, jak aktualizovat čas posledního přihlášení

  2. MySQL - VYBERTE jméno, které je na prvním místě v abecedním pořadí

  3. Zombie připojení k MySQL pomocí c3p0 s tomcat

  4. Jak odstranit každou tabulku v konkrétním schématu v postgresu?