Създайте SQL функция, отнасяща се до таблица или колона, която (все още) не съществува

Искам да заредя някои SQL функции в празна база данни чрез psql:

psql -d my_database -f fuctions.sql --set ON_ERROR_STOP=1 

Използвам --set ON_ERROR_STOP=1, защото искам psql да се провали, ако скриптът съдържа грешки.

Съдържанието на functions.sql е:

CREATE or REPLACE FUNCTION test_function() RETURNS INT AS $$
  SELECT id from test_table;
$$ LANGUAGE sql;

Проблемът ми е, че psql проверява дали test_table съществува при зареждане на функция и се проваля с тази грешка:

ERROR:  relation "test_table" does not exist LINE 2: SELECT id from test_table;

Но не искам тази psql проверка дали таблицата съществува, защото ще създам тази таблица по-късно.

Следните решения ще работят, но не мога да ги използвам:

  • Игнорирайте грешките. Искам psql да излезе с грешка, ако скриптът съдържа т.е. sql синтактични грешки.
  • Използвайте plpgsql функции вместо sql. Разбира се, бих могъл, но простите sql функции често са най-добрият избор.
  • Първо създайте таблицата. Моят реален сценарий всъщност е по-сложен от този пример.

person Tom-db    schedule 20.03.2015    source източник
comment
Знаете ли имената на засегнатите таблици (и съответните функции) предварително ( := преди дори да съществуват)?   -  person joop    schedule 14.04.2015
comment
Можете да използвате таблица като каталог на приложения, където са регистрирани таблиците (и функциите). С тригери на тази таблица бихте могли да автоматизирате генерирането на действителните функции (замествайки функциите-заглушки) и може би дори на таблиците.   -  person joop    schedule 16.04.2015


Отговори (3)


Съобщението за грешка идва от Postgres, а не от psql.

Заобиколно решение

Ако не можете първо да създадете таблицата (по каквато и да е причина), можете да „фалшифицирате, докато не я направите“: Създайте временна таблица със съответстваща структура. Необходимо е само имената и типовете на колоните да съвпадат. За вашата примерна функция:

CREATE TEMP TABLE test_table (id int);

След това CREATE FUNCTION преминава. Пускането на масата по-късно не е забранено. Postgres не записва зависимости за код в тялото на функцията. Така че можете да премахнете таблицата, след като функцията бъде създадена. Ако извикате функцията след премахване на временната таблица, ще получите грешка.

След като създадете действителната таблица по-късно, функцията ще работи нормално.

Да се ​​деактивира ли анализирането на SQL функция по време на създаване?

Доколкото ми е известно, това не е възможно. Може би има опция по време на компилиране за Postgres, за да го деактивира. Ръководството съветва да използвате PL/PgSQL за случаи като вашия:

Забележка: Цялото тяло на SQL функция се анализира, преди която и да е от тях да бъде изпълнена. Въпреки че SQL функция може да съдържа команди, които променят системните каталози (напр. CREATE TABLE), ефектите от такива команди няма да бъдат видими по време на анализ на анализ на по-късни команди във функцията. По този начин, например, CREATE TABLE foo (...); INSERT INTO foo VALUES(...); няма да работи както желаете, ако е пакетиран в една SQL функция, тъй като foo все още няма да съществува, когато командата INSERT бъде анализирана. Препоръчително е да използвате PL/PgSQL вместо SQL функция в този тип ситуации.

Удебелен акцент мой.

person Erwin Brandstetter    schedule 20.03.2015
comment
Всъщност имам голям брой скриптове и функции и не искам да проверявам схемата на базата данни във всяка функция. Надявах се, че има проста опция в psql (или вътре в sql функцията?), която казва на postgres „не проверявайте схемата!“ - person Tom-db; 20.03.2015
comment
@TommasoDiBucchianico: Не знам за никаква опция за потискане на анализирането по време на създаване на функция. Добавих цитат и връзка към ръководството. - person Erwin Brandstetter; 20.03.2015
comment
Благодаря ти Ервин, ще използвам pl/pgsql вместо sql процедури. - person Tom-db; 16.04.2015

Можете да зададете конфигурационната променлива check_function_bodies на false, преди да създадете функциите.

Например, това трябва да ви позволи да създадете вашата тестова функция, въпреки че test_table не съществува:

BEGIN;
SET LOCAL check_function_bodies TO FALSE;
CREATE or REPLACE FUNCTION test_function() RETURNS INT AS $$
  SELECT id from test_table;
$$ LANGUAGE sql;
COMMIT;

Документация: http://www.postgresql.org/docs/9.5/static/runtime-config-client.html#GUC-CHECK-FUNCTION-BODIES

person Martin Bouladour    schedule 02.05.2016
comment
Възможно ли е да принудите повторна проверка, след като всички функции/таблици са на мястото си? подобно на компилирането на Oracle? - person Pyrocks; 29.01.2019

Можете да разделите своя sql-файл, напр. в DDL, DML и след това изпълнение на функциите.

Значи нещо подобно

файл1:

CREATE TABLE foo (
   id int primary key,
   data int);

файл2:

CREATE or REPLACE FUNCTION test_function() RETURNS INT AS $$
  SELECT id from test_table;
$$ LANGUAGE sql;
....

И след това извикване на psql нещо подобно

psql -f file1 
psql -f file2
psql -f ....
person frlan    schedule 20.03.2015
comment
Благодаря, но не мога първо да създам таблицата. Моят реален сценарий всъщност е по-сложен от този пример. - person Tom-db; 20.03.2015