Имя динамической таблицы для запроса INSERT INTO

Я пытаюсь понять, как написать запрос INSERT INTO с именем таблицы и именем столбца источника в качестве параметра.

Для начала я просто пытался параметризовать имя исходной таблицы. Я написал следующий запрос. На данный момент я объявляю и присваиваю значение переменной tablename напрямую, но в реальном примере это будет происходить из какого-то другого источника/списка. Целевая таблица имеет только один столбец.

CREATE OR REPLACE FUNCTION foo()
RETURNS void AS
$$
DECLARE
    tablename text;
BEGIN
   tablename := 'Table_1';
   EXECUTE 'INSERT INTO "Schemaname"."targettable"
   SELECT "Col_A"
   FROM "schemaname".'
   ||quote_ident(tablename);
END
$$ LANGUAGE PLPGSQL;

Хотя запрос выполняется без ошибок, никакие изменения не отражаются в целевой таблице. При выполнении запроса я получаю следующий вывод.

Запрос в порядке, затронуто 0 строк (время выполнения: 296 мс; общее время: 296 мс)

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


person Nishchal    schedule 05.11.2014    source источник
comment
Если у вас есть несколько таблиц с одной и той же схемой, так что они содержат данные одного типа, это обычно указывает на то, что они должны быть одной таблицей с дополнительным столбцом для хранения данных, которые, вероятно, в настоящее время встроены как часть таблица имена. т.е. если вы моделировали организацию, у вас почти наверняка не должно быть таблиц maleEmployees и femaleEmployees.   -  person Damien_The_Unbeliever    schedule 05.11.2014
comment
Возможно ли, что "schemaname"."Table_1" имеет нулевые строки? Что выводит: SELECT count("Col_A") FROM "schemaname"."Table_1";   -  person Antoan Milkov    schedule 05.11.2014


Ответы (1)


Проверенный код

CREATE OR REPLACE FUNCTION foo()
   RETURNS void AS
$func$
DECLARE
   _tbl text := 'Table_1';  -- or 'table_1'?
BEGIN       
   EXECUTE 'INSERT INTO schemaname.targettable(column_name)
   SELECT  "Col_A"
   FROM    schemaname.' || quote_ident(_tbl);  -- or "Schemaname"?
END
$func$  LANGUAGE plpgsql;
  • Всегда используйте явный целевой список для постоянных операторов INSERT.

  • Вы можете назначать переменные во время объявления.

  • Широко распространенной глупостью является использование идентификаторов в двойных кавычках для сохранения недопустимого правописания. Вы должны держать имя в двойных кавычках до конца его существования. Кажется, в ваш код закралась одна или несколько из этих ошибок: "Schemaname" или "schemaname"? Table_1 или "Table_1"?

  • Когда вы предоставляете идентификатор, например имя таблицы, в качестве параметра text и экранируете его с помощью quote_ident(), он чувствителен к регистру!
    Идентификаторы в коде SQL преобразуются в нижний регистр, если двойные кавычки. Но quote-ident() (которое вы должны использовать для защиты от SQL-инъекций) сохраняет написанное вами правописание с двойными кавычками, где это необходимо.

Функция с параметром

CREATE OR REPLACE FUNCTION foo(_tbl text)
   RETURNS void AS
$func$
BEGIN       
   EXECUTE 'INSERT INTO schemaname.targettable(column_name)
   SELECT  "Col_A"
   FROM    schemaname.' || quote_ident(_tbl);
END
$func$  LANGUAGE plpgsql;

Вызов:

SELECT foo('tablename');  -- tablename is case sensitive

Есть и другие способы:

person Erwin Brandstetter    schedule 13.04.2015