PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

EXECUTE...INTO...USING изразът в PL/pgSQL не може да се изпълни в запис?

По-проста алтернатива на публикувания от вас отговор. Трябва да работи много по-добре.

Тази функция извлича ред от дадена таблица (in_table_name ) и стойност на първичен ключ (in_row_pk ) и го вмъква като нов ред в същата таблица, като някои стойности са заменени (in_override_values ). Връща се новата стойност на първичния ключ по подразбиране (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;

Обаждане:

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

SQL Fiddle.

  • Използвайте regclass като тип входен параметър, така че само валидни имена на таблици могат да се използват като начало и SQL инжектирането е изключено. Функцията също се проваля по-рано и по-елегантно, ако предоставите нелегално име на таблица.

  • Използвайте OUT параметър (pk_new ), за да опростите синтаксиса.

  • Няма нужда да намирате следващата стойност за първичния ключ ръчно. Вмъква се автоматично и се връща след факта. Това е не само по-просто и по-бързо, но също така избягвате пропилени или неправилни поредни номера.

  • Използвайте format() за да се опрости сглобяването на динамичния низ на заявката и да го направи по-малко податлив на грешки. Обърнете внимание как използвам позиционни параметри съответно за идентификатори и низове.

  • Разчитам на вашето имплицитно предположение че разрешените таблици имат единична колона с първичен ключ от тип integer с колона по подразбиране . Обикновено сериен колони.

  • Ключов елемент на функцията е крайният INSERT :

    • Слейте стойностите за замяна със съществуващия ред с помощта на #= оператор в подизбор и незабавно разложете получения ред.
    • След това можете да изберете само подходящи колони в главния SELECT .
    • Нека Postgres присвои стойността по подразбиране за PK и да го върне с RETURNING клауза.
    • Запишете върнатата стойност в OUT параметър директно.
    • Всичко се прави с една SQL команда, която обикновено е най-бърза.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Защо заявката няма да запише в csv файл, докато изглежда нормално в конзолата на postgresql

  2. Грешка в Castle Activerecord е „връзката не съществува“ на Postgresql?

  3. Как да зададете потребителска парола по подразбиране в PostgreSQL

  4. свързване на postgresql и codeigniter

  5. Актуализирайте част (номер на поръчка), която е първичен ключ в Postgre