Как создать таблицу и вставить данные со значениями Dynami c в postgres - PullRequest
0 голосов
/ 06 февраля 2020

Я пытаюсь написать хранимую процедуру, в которой имя таблицы происходит динамически. Также он должен проверить, существует ли таблица и создать ее, только если она не существует.

Затем позже я пытаюсь вставить данные в таблицу, как показано ниже. Здесь я передаю pkey и filedata в качестве параметров для вставки запроса, в котором pkey - это строка, а filedata - это json данные, которые выглядят как { "customer": "John Doe", "items": {"product": "Beer","qty": 6}}

. Я пробовал ниже запроса, но таблица не создается, она выдает сообщение

Примечание: идентификатор publi c .tablename_11111 будет усечен до publi c .tablename_11111

здесь имя таблицы public.tablename_11111

    CREATE OR REPLACE FUNCTION public.generate_table(tb_name text)
    RETURNS text LANGUAGE 'plpgsql'
    COST 100 VOLATILE AS $BODY$

    BEGIN
        EXECUTE format('
            CREATE TABLE IF NOT EXISTS %I(
               id serial PRIMARY KEY,
               pkey VARCHAR (250)  NULL,
               fpo_data TEXT NULL
            )', tb_name || '_pk');


            EXECUTE 'INSERT INTO' || tb_name || '_pk (pkey, fpo_data) VALUES
        ('|| pkey ||', '|| filedata ||')';

        END;
    $BODY$;

Ответы [ 2 ]

0 голосов
/ 06 февраля 2020

В идеале вы должны передавать имя схемы и имя таблицы как два отдельных значения. И лучше не объединять значения в строку SQL, а использовать заполнители. Главным образом, чтобы вам не пришлось беспокоиться о правильном их форматировании.

Что-то вроде следующего:

CREATE OR REPLACE FUNCTION public.generate_table(tb_schema text, tb_name text, ???)
RETURNS text 
  LANGUAGE plpgsql --<< the language name is an identifier, don't quote it
  COST 100 VOLATILE 
AS $BODY$
BEGIN
  tb_name := tb_name ||'_pk';

  EXECUTE format('
        CREATE TABLE IF NOT EXISTS %I.%I (
           id serial PRIMARY KEY,
           pkey VARCHAR (250)  NULL,
           fpo_data TEXT NULL
        )', tb_schema, tb_name);

  -- where do pkey and filedata come from? 
  EXECUTE format('INSERT INTO %I.%I (pkey, fpo_data) VALUES (:1, :2)', 
                 tb_schema, tb_name)
      using pkey, filedata;  

END;
$BODY$;
0 голосов
/ 06 февраля 2020

Первое: %I, при использовании с именем, подобным public.tablename_11111, не будет делать то, что вы хотите.

В итоге вы получите таблицу с именем "public.tablename_11111", а не таблицу tablename_11111 в схеме public. Для этого вам следует разделить схему и имя таблицы и использовать формат %I.%I:

EXECUTE
   format(
      'CREATE TABLE %I.%I (...)',
      schema_name, tb_name || '_pk'
   );

Во-вторых, ваш оператор INSERT уязвим для инъекции SQL. Здесь вы также должны использовать функцию format, как и в CREATE TABLE.

...