我想为PG SQL数据库中的模式创建更新功能。测试功能如下。它不起作用,因为它永远不会发出通知,但在运行test_schema_update('second')
时会这样做。
CREATE OR REPLACE FUNCTION test_schema_update(my_schema_name VARCHAR(200))
RETURNS void AS
$__marker__$
DECLARE
actualValue varchar(1000);
testValue varchar(1000);
BEGIN
EXECUTE 'SET search_path TO ' || quote_ident(my_schema_name);
testValue := (SELECT max(value) FROM setting WHERE settingkey = 'libraryname');
EXECUTE ('SELECT max(value) FROM setting WHERE settingkey = ''libraryname''')
INTO actualValue;
IF (actualValue != testValue)
THEN
RAISE NOTICE '% != %', actualValue, testValue;
RAISE INFO 'Schema was: %', current_schema();
END IF;
RESET search_path;
END;
$__marker__$ LANGUAGE plpgsql;
test_schema_update('first');
test_schema_update('second');
问题是PG SQL似乎每个会话只分析一次SELECT
语句,然后将表固定到特定的模式。有趣的是,你会得到Schema was: second
。
那么有没有办法重置SELECT
语句分析或其他一些方法来解决这个问题?
附注:所有架构创建功能(ALTER TABLE
,CREATE TABLE
...)都可以正常工作。只有数据操作功能似乎受到影响(SELECT
,INSERT
,UPDATE
)。
在:
IF (
SELECT max(id) FROM dimtime
)
THEN
INSERT INTO dimtime SELECT * FROM public.src_dimtime;
END IF;
后:
EXECUTE ('
SELECT max(id) FROM dimtime
')
INTO testInt;
IF (testInt IS NULL)
THEN
EXECUTE 'INSERT INTO dimtime SELECT * FROM public.src_dimtime';
END IF;
编辑:问题出现在PostgreSQL 9.2中,但似乎不会出现在9.3中。也许这是固定的?
答案 0 :(得分:4)
这种行为是可以预期的。原因是PL / pgSQL在SQL语句中使用计划缓存,内部使用标准的预处理语句。
首先在函数中执行每个表达式和SQL命令, PL / pgSQL解释器创建一个准备好的执行计划(使用 SPI经理的
SPI_prepare
和SPI_saveplan
功能)。随后 访问该表达式或命令重用已准备好的计划。
这也是为什么plpgsql函数通常比复杂操作的纯SQL函数更快的原因:
预备语句将在会话的生命周期内保存,而不仅仅是事务(但在基础对象更改时无效,这对于并发访问是安全的)。 The documentation once again:
PL / pgSQL为a中的特定命令制定了执行计划 函数,它将重用该计划用于数据库的生命周期 连接即可。这通常是性能的胜利,但它可能会导致 如果动态更改数据库架构,则会出现一些问题。
大胆强调我的。
如果你想"改变"表名的模式,你真的要引用一个完全不同的表, 需要 使用带有EXECUTE
的动态SQL,这会产生一个新的计划每一次(各有利弊):
因为PL / pgSQL以这种方式保存执行计划,所以SQL命令 直接出现在PL / pgSQL函数中必须引用相同的表 和每次执行的列;也就是说,你不能使用参数 SQL命令中的表或列的名称。绕过这个 限制,您可以使用PL / pgSQL构造动态命令
EXECUTE
声明 - 以构建新执行计划为代价 在每次执行时。
阅读手册中引用的章节。它非常全面。
您不需要动态SQL来添加代码示例,单个语句会更快:
INSERT INTO dimtime -- you may want list columns
SELECT * -- here as well
FROM public.src_dimtime
WHERE NOT EXISTS (SELECT 1 FROM dimtime);