sql >> Database teknologi >  >> RDS >> PostgreSQL

EXECUTE...INTO...USING-sætning i PL/pgSQL kan ikke udføres i en post?

Enklere alternativ til dit indsendte svar. Bør præstere meget bedre.

Denne funktion henter en række fra en given tabel (in_table_name ) og primær nøgleværdi (in_row_pk ), og indsætter den som en ny række i den samme tabel, med nogle værdier erstattet (in_override_values ). Den nye primærnøgleværdi returneres som standard (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;

Ring til:

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

SQL Fiddle.

  • Brug regclass som inputparametertype, så kun gyldige tabelnavne kan bruges til at begynde med, og SQL-injektion er udelukket. Funktionen fejler også tidligere og mere yndefuldt, hvis du skulle angive et ulovligt tabelnavn.

  • Brug en OUT parameter (pk_new ) for at forenkle syntaksen.

  • Det er ikke nødvendigt at finde ud af den næste værdi for den primære nøgle manuelt. Det indsættes automatisk og returneres efter kendsgerningen. Det er ikke kun enklere og hurtigere, du undgår også spildte eller ude af rækkefølge numre.

  • Brug format() for at forenkle samlingen af ​​den dynamiske forespørgselsstreng og gøre den mindre fejltilbøjelig. Bemærk, hvordan jeg bruger positionsparametre til henholdsvis identifikatorer og strenge.

  • Jeg bygger på din implicitte antagelse at tilladte tabeller har en enkelt primær nøglekolonne af typen heltal med en kolonnestandard . Typisk serial kolonner.

  • Funktionens nøgleelement er den sidste INSERT :

    • Flet tilsidesættelsesværdier med den eksisterende række ved hjælp af #= operatør i et undervælg og nedbryd den resulterende række med det samme.
    • Så kan du kun vælge relevante kolonner i hoved-SELECT .
    • Lad Postgres tildele standardværdien for PK'en og få den tilbage med RETURNING klausul.
    • Skriv den returnerede værdi i OUT parameter direkte.
    • Alt gjort i en enkelt SQL-kommando, det er generelt hurtigst.


  1. MYSQL Indsæt Send-knap PHP

  2. SEC_TO_TIME() Eksempler – MySQL

  3. onbeforeprint() og onafterprint() tilsvarende for ikke-IE-browsere

  4. hurtigt valg af en tilfældig række fra en stor tabel i mysql