如何在不创建函数的情况下运行 plpgsql?
Posted
技术标签:
【中文标题】如何在不创建函数的情况下运行 plpgsql?【英文标题】:How to run plpgsql without creating a function? 【发布时间】:2016-07-13 15:18:39 【问题描述】:我想在 Postgres 中以编程方式运行 SQL,而不创建函数。
原因:确保我的 plpgsql 事先工作并在将查询提交给函数之前“解释分析”查询。
我是 Postgres 的新手,我认为这很简单。我在那里找不到任何例子。也许这是不可能的?下面的代码如何工作?
DO
$body$
DECLARE
v_name_short VARCHAR;
BEGIN
v_name_short := 'test Account 1';
RETURN QUERY
SELECT
a.name_short,
a.name_long
FROM enterprise.account a
WHERE
CASE WHEN v_name_short IS NOT NULL THEN
LOWER(a.name_short) = LOWER(v_name_short)
ELSE
1 = 1
END;
END;
$body$
LANGUAGE 'plpgsql';
同样,这里的目标是测试我的 SQL,就像在这种情况下,我想确保我的 CASE 语句仍在使用我创建的索引 (LOWER(name_short))。无论如何,我收到此错误消息:
错误:不能在非 SETOF 函数中使用 RETURN QUERY
我的要求在 Postgres 中可行吗?如果没有,有没有办法在函数内部查询分析计划?
【问题讨论】:
为什么要使用do
块来运行explain
?为什么不能简单地运行explain select ...
?
【参考方案1】:
匿名代码块返回 void。但是,您可以使用临时表的技巧,例如
CREATE TEMP TABLE IF NOT EXISTS trace (name_short text, name_long text);
DO
$body$
DECLARE
v_name_short VARCHAR;
BEGIN
v_name_short := 'test Account 1';
INSERT INTO trace
SELECT
a.name_short,
a.name_long
FROM enterprise.account a
WHERE
CASE WHEN v_name_short IS NOT NULL THEN
LOWER(a.name_short) = LOWER(v_name_short)
ELSE
1 = 1
END;
END;
$body$
LANGUAGE 'plpgsql';
SELECT * FROM trace;
-- DROP TABLE trace;
使用EXPLAIN ANALYSE
,您只能分析单个普通 sql 查询,而不是函数、do 块或脚本。所以你可以试试:
EXPLAIN ANALYSE
SELECT
a.name_short,
a.name_long
FROM enterprise.account a
WHERE
CASE WHEN 'test Account 1' IS NOT NULL THEN
LOWER(a.name_short) = LOWER('test Account 1')
ELSE
1 = 1
END;
请注意,在这种情况下,您不能使用变量,因为规划器无法识别它,请改用文字。
【讨论】:
克林,感谢您的回答。我只是很惊讶我不能在 Postgres 中干净地运行它。尽管您的解决方案执行了,但我无法从 pgAdmin 运行“解释分析”,因为它在 CREATE 语句中直接爆炸(无法分析)。我想我需要找到一种方法来分析函数内部的查询计划...... 您只能分析单个纯 sql 查询,不能分析函数、do 块或脚本。在这种情况下尝试explain analyse select ...
,但您不能使用该变量。用文字 'test Account 1'
代替。
克林,帮个忙:您介意用您刚刚发布的评论更新您的答案吗?然后答案将完成,我可以将其标记为已接受。再次感谢您的帮助!【参考方案2】:
do
匿名代码块总是返回void
:
代码块被视为没有参数的函数体,返回 void
要在 do
块内执行查询,请使用 perform
do $$
begin
perform * from t;
end
$$;
https://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-SQL-NORESULT
【讨论】:
谢谢,但是有没有办法用另一种语法来执行上面的代码? 我们更近了一步,但现在我明白了:“查询成功返回,28 毫秒内没有结果”。现在,有一个结果......但就像你说的“DO”总是返回无效。那么有没有办法在没有 DO 的情况下运行查询?再次感谢您的帮助!【参考方案3】:在常规 PL/pgSQL 函数和 DO
语句之间还有第三个(未记录的)选项:临时函数:
您实际上可以使用附加模块auto-explain 获得plpgsql 函数中每个SQL 语句的详细查询计划。详情:
Postgres query plan of a UDF invocation written in pgpsql但是您必须使用 CASE
表达式中每个分支的值来测试您的函数,以确保涵盖所有内容。 Postgres 只对CREATE FUNCTION
进行表面语法检查。
Prepared statements 可能是另一个可以使用的选项。 PL/pgSQL 在内部处理 SQL 语句,就像准备好的语句一样:
Difference between language sql and language plpgsql in PostgreSQL functions【讨论】:
以上是关于如何在不创建函数的情况下运行 plpgsql?的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用 @Composable 注释的情况下为撰写函数创建扩展?
在 C++ 中,如何在不使用 if 语句的情况下选择运行特定的成员函数?
Visual C++/Cli 中的异步睡眠,如何在不使 GUI 停止的情况下创建一个 X 毫秒来调用函数