sql >> Database >  >> RDS >> PostgreSQL

EXECUTE...INTO...USING statement in PL/pgSQL kan niet worden uitgevoerd in een record?

Eenvoudiger alternatief voor uw geposte antwoord. Zou veel beter moeten presteren.

Deze functie haalt een rij op uit een bepaalde tabel (in_table_name ) en primaire sleutelwaarde (in_row_pk ), en voegt deze als nieuwe rij in dezelfde tabel in, waarbij enkele waarden zijn vervangen (in_override_values ). De nieuwe primaire sleutelwaarde wordt standaard geretourneerd (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;

Bel:

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

SQL Fiddle.

  • Gebruik regclass als invoerparametertype, dus alleen geldige tabelnamen kunnen worden gebruikt om mee te beginnen en SQL-injectie is uitgesloten. De functie faalt ook eerder en mooier als je een illegale tabelnaam opgeeft.

  • Gebruik een OUT parameter (pk_new ) om de syntaxis te vereenvoudigen.

  • Het is niet nodig om de volgende waarde voor de primaire sleutel handmatig te achterhalen. Het wordt automatisch ingevoegd en achteraf teruggestuurd. Dat is niet alleen eenvoudiger en sneller, u voorkomt ook verspilde of niet-bestaande volgnummers.

  • Gebruik format() om de assemblage van de dynamische queryreeks te vereenvoudigen en deze minder foutgevoelig te maken. Merk op hoe ik positionele parameters gebruik voor respectievelijk identifiers en strings.

  • Ik bouw voort op uw impliciete aanname dat toegestane tabellen een enkele primaire sleutelkolom van het type integer hebben met een standaardkolom . Typisch serial kolommen.

  • Het belangrijkste element van de functie is de laatste INSERT :

    • Override-waarden samenvoegen met de bestaande rij met behulp van de #= operator in een subselectie en ontleed de resulterende rij onmiddellijk.
    • Vervolgens kunt u alleen relevante kolommen selecteren in het hoofdvenster SELECT .
    • Laat Postgres de standaardwaarde voor de PK toewijzen en terugkrijgen met de RETURNING clausule.
    • Schrijf de geretourneerde waarde in de OUT parameter direct.
    • Alles gedaan in een enkele SQL-opdracht, dat is over het algemeen het snelst.


  1. Geen reactie ontvangen van PHP / MySQL NuSOAP

  2. Externe sleutel toevoegen aan een railsmodel

  3. Bereken het verschil tussen de resultaten van twee count(*)-query's op basis van 2 tabellen in PostgreSQL

  4. SQL-resultatentabel, match in tweede tabel SET-type