创建 SQL 函数引用 table 或(尚)不存在的列

Create SQL function referring to a table or column that does not exist (yet)

我想通过 psql 在空数据库中加载一些 SQL 函数:

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 检查 table 是否存在,因为我稍后会创建这个 table。

以下解决方法可行,但我无法使用它们:

您可以拆分您的 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 ....

错误消息来自 Postgres,而不是来自 psql。

解决方法

如果您不能首先创建 table(无论出于何种原因),您可以 "fake it until you make it":创建一个临时的 table匹配结构。您只需要匹配列名和类型。对于您的示例函数:

CREATE TEMP TABLE test_table (id int);

然后 CREATE FUNCTION 通过。不禁止稍后删除 table。 Postgres 不在函数体中保存代码的依赖关系。因此,您可以在创建函数后删除 table 。如果在删除临时 table 后调用该函数,则会出现错误。

稍后创建实际table后,该功能将正常运行。

在创建时禁用 SQL 函数的解析?

据我所知,这不可能。也许 Postgres 有一个编译时选项来禁用它。 The manual advises to use PL/PgSQL for cases like yours:

Note: The entire body of a SQL function is parsed before any of it is executed. While a SQL function can contain commands that alter the system catalogs (e.g., CREATE TABLE), the effects of such commands will not be visible during parse analysis of later commands in the function. Thus, for example, CREATE TABLE foo (...); INSERT INTO foo VALUES(...); will not work as desired if packaged up into a single SQL function, since foo won't exist yet when the INSERT command is parsed. It's recommended to use PL/PgSQL instead of a SQL function in this type of situation.

大胆强调我的。

您可以在创建函数之前将配置变量 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