sql >> Databasteknik >  >> RDS >> PostgreSQL

EXECUTE...INTO...USING-satsen i PL/pgSQL kan inte köras i en post?

Enklare alternativ till ditt postade svar. Borde prestera mycket bättre.

Denna funktion hämtar en rad från en given tabell (in_table_name ) och primärnyckelvärde (in_row_pk ), och infogar den som en ny rad i samma tabell, med några värden ersatta (in_override_values ). Det nya primärnyckelvärdet returneras 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:

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

SQL-fiol.

  • Använd regclass som indataparametertyp, så endast giltiga tabellnamn kan användas till att börja med och SQL-injektion är utesluten. Funktionen misslyckas också tidigare och mer elegant om du skulle ange ett olagligt tabellnamn.

  • Använd en OUT parameter (pk_new ) för att förenkla syntaxen.

  • Du behöver inte räkna ut nästa värde för primärnyckeln manuellt. Den infogas automatiskt och returneras i efterhand. Det är inte bara enklare och snabbare, du slipper också bortkastade eller felaktiga sekvensnummer.

  • Använd format() för att förenkla sammansättningen av den dynamiska frågesträngen och göra den mindre felbenägen. Notera hur jag använder positionsparametrar för identifierare respektive strängar.

  • Jag bygger på ditt underförstådda antagande att tillåtna tabeller har en enkla primärnyckelkolumn av typen heltal med en kolumnstandard . Vanligtvis seriell kolumner.

  • Nyckelelementet i funktionen är den sista INSERT :

    • Slå samman åsidosättningsvärden med den befintliga raden med #= operatör i en undermarkering och dekomponera den resulterande raden omedelbart.
    • Då kan du bara välja relevanta kolumner i huvud SELECT .
    • Låt Postgres tilldela standardvärdet för PK och få tillbaka det med RETURNING klausul.
    • Skriv det returnerade värdet i OUT parameter direkt.
    • Allt gjort i ett enda SQL-kommando, det är vanligtvis snabbast.


  1. När spolar SQL Server-sorter tillbaka?

  2. Konfigurera Oracle XStream

  3. Fatalt fel:Maximal exekveringstid på 30 sekunder har överskridits i ...\model.php på rad 183

  4. MySql välj alla rader i en tabell baserat på MAX-värdet i en annan tabell