Ale*_*ber 12 postgresql plpgsql functions postgresql-9.3
我有一个用 Perl 编写的非分叉游戏守护进程,它使用 acync 查询将玩家统计数据写入 PostgreSQL 9.3 数据库。但是当我需要从数据库中读取某些内容时(例如玩家是否被禁止或玩家是否具有 VIP 身份),那么我使用同步查询。
这会使游戏停止一小会,直到从数据库中读取该值。
我无法重写我的游戏守护程序以使用异步查询来读取值(我尝试过,但它需要进行太多更改),所以我的问题是:将几个不相关的查询组合在一起是否有意义(我需要在新玩家连接) 到 1 个过程,如何同时将多个值返回到我的 Perl 程序?
我当前的查询都以玩家 ID 作为参数并返回 1 个值:
-- Has the player been banned?
select true from pref_ban where id=?
-- What is the reputation of this player?
select
count(nullif(nice, false)) -
count(nullif(nice, true)) as rep
from pref_rep where id=?
-- Is he or she a special VIP player?
select vip > now() as vip from pref_users where id=?
-- How many games has the player played to the end?
select completed from pref_match where id=?
Run Code Online (Sandbox Code Playgroud)
为了结合上述查询,我可能需要一个这样的过程:
create or replace function get_user_info(_id varchar) returns XXX as $BODY$
declare
is_banned boolean;
reputation integer;
is_vip boolean;
completed_games integer;
begin
select 1 into is_banned from pref_ban where id=_id;
select
count(nullif(nice, false)) -
count(nullif(nice, true))
into reputation
from pref_rep where id=_id;
select vip > now() into is_vip from pref_users where id=_id;
select completed into completed_games from pref_match where id=_id;
return XXX; /* How to return 4 values here? */
end;
$BODY$ language plpgsql;
Run Code Online (Sandbox Code Playgroud)
请帮我正确申报上述程序。
poz*_*ozs 18
使用OUT
参数与@klin 的答案基本相同,但不创建用户定义的类型。只需将声明块中的所有变量作为OUT
参数移动到参数列表中:
create or replace function get_user_info(
IN _id varchar,
OUT is_banned boolean,
OUT reputation integer,
OUT is_vip boolean,
OUT completed_games integer
)
-- no returns clause necessary, output structure controlled by OUT parameters
-- returns XXX
as $BODY$
begin
select true into is_banned from pref_ban where id=_id;
select
count(nullif(nice, false)) -
count(nullif(nice, true))
into reputation
from pref_rep where id=_id;
select vip > now() into is_vip from pref_users where id=_id;
select completed into completed_games from pref_match where id=_id;
-- no return statement necessary, output values already stored in OUT parameters
-- return XXX;
end
$BODY$ language plpgsql;
Run Code Online (Sandbox Code Playgroud)
这将返回一条记录(正好是一条),因此您可以选择其值作为普通记录:
-- this will return all properties (columns) from your function:
select * from get_user_info();
-- these will return one property (column) from your function:
select is_banned from get_user_info();
select (get_user_info()).is_banned;
Run Code Online (Sandbox Code Playgroud)
您应该定义一个复合类型。您可以将其用作函数的返回类型和函数内的记录变量。
例子:
create type user_type as (
is_banned boolean,
reputation integer,
is_vip boolean,
completed_games integer);
create or replace function check_user_type ()
returns user_type language plpgsql as $$
declare
rec user_type;
begin
select true into rec.is_banned;
select 100 into rec.reputation;
select false into rec.is_vip;
select 22 into rec.completed_games;
-- you can do the same in a little bit nicer way:
-- select true, 100, false, 22 into rec
return rec;
end $$;
select * from check_user_type();
Run Code Online (Sandbox Code Playgroud)
在我看来,就性能和应用程序逻辑而言,使用这样的函数是非常合理的。
如果您想从函数中返回一组行,用户定义的复合类型非常有用。然后你应该将函数的返回类型定义为setof composite-type
并使用return next
或return query.
例子:
create or replace function check_set_of_user_type ()
returns setof user_type language plpgsql as $$
declare
rec user_type;
begin
for rec in
select i/2*2 = i, i, i < 3, i+ 20
from generate_series(1, 4) i
loop
return next rec;
end loop;
return query
select true, 100+ i, true, 100+ i
from generate_series(1, 2) i;
end $$;
select * from check_set_of_user_type();
is_banned | reputation | is_vip | completed_games
-----------+------------+--------+-----------------
f | 1 | t | 21
t | 2 | t | 22
f | 3 | f | 23
t | 4 | f | 24
t | 101 | t | 101
t | 102 | t | 102
Run Code Online (Sandbox Code Playgroud)