Ale*_*s G 9 postgresql plpgsql prepared-statement
我在数据库中有一个表:
create table store (
...
n_status integer not null,
t_tag varchar(4)
t_name varchar,
t_description varchar,
dt_modified timestamp not null,
...
);
Run Code Online (Sandbox Code Playgroud)
在我的存储函数中,我需要select多次对该表执行相同的操作:
select * from store
where n_place_id = [different values]
and t_tag is not null
and n_status > 0
and (t_name ~* t_search or t_description ~* t_search)
order by dt_modified desc
limit n_max;
Run Code Online (Sandbox Code Playgroud)
这里,t_search并且n_max是存储函数的参数.我认为为此使用准备好的声明是有意义的,但我遇到了奇怪的问题.这就是我所拥有的:
create or replace function fn_get_data(t_search varchar, n_max integer)
returns setof store as
$body$
declare
resulter store%rowtype;
mid integer;
begin
prepare statement prep_stmt(integer) as
select *
from store
where n_place_id = $1
and (t_name ~* t_search or t_description ~* t_search)
order by dt_modified
limit n_max;
for mid in
(select n_place_id from ... where ...)
loop
for resulter in
execute prep_stmt(mid)
loop
return next resulter;
end loop;
end loop;
end;$body$
language 'plpgsql' volatile;
Run Code Online (Sandbox Code Playgroud)
但是,当我实际运行该功能时
select * from fn_get_data('', 30)
Run Code Online (Sandbox Code Playgroud)
我收到此错误:
ERROR: column "t_search" does not exist
LINE 3: and (t_name ~* t_search or t_description ~* t_search)
^
QUERY: prepare prep_stmt(integer) as
select * from store where n_status > 0 and t_tag is not null and n_museum = $1
and (t_name ~* t_search or t_description ~* t_search)
order by dt_modified desc limit maxres_free
Run Code Online (Sandbox Code Playgroud)
好吧,也许它不喜欢准备好的语句中的外部变量,所以我把它改成了
prepare prep_stmt(integer, varchar, integer) as
select * from store where n_status > 0 and t_tag is not null and n_museum = $1
and (t_name ~* $2 or t_description ~* $2)
order by dt_modified desc limit $3
...
for resulter in
execute prep_stmt(mid, t_search, n_max)
...
Run Code Online (Sandbox Code Playgroud)
这次我得到一个不同的错误:
ERROR: function prep_stmt(integer, character varying, integer) does not exist
LINE 1: SELECT prep_stmt(mid, t_search, n_max)
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
QUERY: SELECT prep_stmt(mid, t_search, n_max)
Run Code Online (Sandbox Code Playgroud)
我在这里错过了什么?
编辑我在顶部添加了相关的表结构.
在我看来,像EXECUTE动态SQL 的PL/PgSQL 胜过EXECUTE准备语句的常规SQL .
码:
create or replace function prep_test() returns void as $$
begin
PREPARE do_something AS SELECT 1;
EXECUTE do_something;
end;
$$ LANGUAGE 'plpgsql';
Run Code Online (Sandbox Code Playgroud)
测试:
regress=# select prep_test(1);
ERROR: column "do_something" does not exist
LINE 1: SELECT do_something
^
QUERY: SELECT do_something
CONTEXT: PL/pgSQL function "prep_test" line 4 at EXECUTE statement
Run Code Online (Sandbox Code Playgroud)
在PL/PgSQL之外它工作正常:
regress=# EXECUTE do_something;
?column?
----------
1
(1 row)
Run Code Online (Sandbox Code Playgroud)
我不确定你是如何在PL/PgSQL中执行准备好的语句的.
出于兴趣,为什么要尝试在PL/PgSQL中使用预处理语句?无论如何,为PL/PgSQL准备和缓存计划,它会自动发生.
有一种方法可以EXECUTE在函数中使用准备好的语句,但就像接受的答案所说的那样,您通常不想在函数中执行此操作,因为该函数已经存储了其计划。
话虽如此,仍然存在需要在函数中使用准备好的语句的用例。我的用例是为不同用户使用多个架构,其中架构包含名称相似的表,并且您希望根据设置的内容使用相同的函数来访问这些表之一search_path。在这种情况下,由于函数存储其计划的方式,在更改后使用相同的函数会search_path导致事情中断。我已经说过这个问题有两种解决方案。第一个是使用EXECUTE '<Your query as a string here>'. 但对于大型查询来说,这可能会变得非常难看,因此使用第二种方法的原因,该方法涉及PREPARE.
因此,在了解“为什么”您想要这样做的背景后,以下是具体的方法:
CREATE OR REPLACE FUNCTION prep_test()
RETURNS void AS $$
BEGIN
PREPARE do_something AS SELECT 1;
EXECUTE 'EXECUTE do_something;';
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
尽管添加一些保护措施以防止其损坏可能符合您的最大利益。就像是:
CREATE OR REPLACE FUNCTION prep_test()
RETURNS void AS $$
BEGIN
IF (SELECT count(*) FROM pg_prepared_statements WHERE name ilike 'do_something') > 0 THEN
DEALLOCATE do_something;
END IF;
PREPARE do_something AS SELECT 1;
EXECUTE 'EXECUTE do_something;';
DEALLOCATE do_something;
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
再说一次,那些认为自己想要这样做的人通常可能不应该这样做,但对于那些需要这样做的情况,这就是你这样做的方式。
| 归档时间: |
|
| 查看次数: |
13290 次 |
| 最近记录: |