SQL函数的整个主体在执行任何函数之前都会被分析。尽管SQL函数可以包含个命令,这些命令会更改 系统目录(例如
CREATE TABLE
),这些命令的效果 在后面的命令的解析分析中将不可见 功能。因此,例如CREATE TABLE foo (...); INSERT INTO foo VALUES(...);
如果打包成一个,将无法按预期工作 SQL函数,因为解析INSERT
命令时foo还不存在。建议使用PL / pgSQL代替SQL函数 在这种情况下。
为什么“在这种情况下,建议使用PL / pgSQL代替SQL函数”,其中PL / pgSQL或SQL函数包含更改系统目录的命令,例如CREATE TABLE foo (...); INSERT INTO foo VALUES(...);
?
“ SQL函数的主体在执行任何函数之前就已解析”。 PL / pgSQL函数不是真的吗?在解析和执行其主体中的命令方面,SQL函数和PL / pgSQL函数之间有什么区别?
答案 0 :(得分:1)
Plpgsql函数在定义时进行解析和语法检查,然后在第一次执行时生成一个计划。
https://www.postgresql.org/docs/current/static/plpgsql-implementation.html#PLPGSQL-PLAN-CACHING
然后使用给定的参数执行该计划。
临时文件似乎可以按预期工作,除了第一次执行时已经存在的文件。
如其中提到的那样,使用动态SQL(EXECUTE)是一种挫败计划程序的方法,允许访问任意表。
答案 1 :(得分:1)
您自己加粗了key sentence in the manual:
在执行任何SQL函数之前,都会对其进行分析。
另请参阅The Parser Stage in the manual。
它包括两个主要部分:解析器和转换过程。 Quoting the manual:
转换过程将解析器返回的树作为 输入并进行语义解释以了解哪个 查询引用表,函数和运算符。
如果SQL函数包含以下命令:
CREATE TABLE foo (...);
INSERT INTO foo VALUES(...);
两个语句实际上是在同一时间计划的(基于系统目录的相同快照)。因此,INSERT
无法看到由上一个CREATE
命令创建的表“ foo”。这会产生以下问题之一:
如果还没有名为“ foo” in your search_patch
的 other 表,则Postgres在尝试创建功能时会抱怨 :>
ERROR: relation "foo" does not exist
如果您的search_patch
中已经存在另一个名为“ foo”的表(并且您没有使用冲突的列名),则Postgres将基于该预先存在的表来计划INSERT
。如果任何值导致(错误!)表中的冲突,通常会在执行时错误。或者,如果运气不好,它甚至可能在没有错误消息的情况下写入该表!非常狡猾的错误。
使用 PL / pgSQL 函数不会发生这种情况,因为它会将SQL命令像已准备好的语句一样对待,并按 顺序执行。因此,每个语句都可以查看先前语句中创建的对象。
因此,从未访问过的语句甚至从未计划过-与SQL函数不同。语句的执行计划可以缓存在同一会话中-与SQL函数不同。 Read details about plan caching in PL/pgSQL functions in the manual here.
对于某些用例,每种方法都具有优势。进一步阅读: