在 PostgreSQL 8.4.9 我有一个小游戏,用户可以在其中购买 VIP(“非常重要的人”)身份:
# \d pref_users;
Table "public.pref_users"
Column | Type | Modifiers
------------+-----------------------------+---------------
id | character varying(32) | not null
vip | timestamp without time zone |
如果从未购买过 vip,它将为NULL。
如果 vip 已过期,它将是< CURRENT_TIMESTAMP。
我正在尝试创建 PL/pgSQL 过程,允许具有足够 vip 状态的用户将一周的时间作为“礼物”赠送给其他用户:
create or replace function pref_move_week(_from varchar,
_to varchar) returns void as $BODY$
declare
has_vip boolean;
begin
select vip > current_timestamp + interval '1 week'
into has_vip from pref_users where id=_from;
if (not has_vip) then
return;
end if;
update pref_users set vip = current_timestamp - interval '1 week' where id=_from;
update pref_users set vip = current_timestamp + interval '1 week' where id=_to;
end;
$BODY$ language plpgsql;
不幸的是,如果提供用户的 vip 为 NULL,则此过程无法正常工作:
# update pref_users set vip=null where id='DE16290';
UPDATE 1
# select id,vip from pref_users where id in ('DE16290', 'DE1');
id | vip
---------+----------------------------
DE1 | 2012-01-05 17:35:17.772043
DE16290 |
(2 rows)
# select pref_move_week('DE16290', 'DE1');
pref_move_week
----------------
(1 row)
# select id,vip from pref_users where id in ('DE16290', 'DE1');
id | vip
---------+----------------------------
DE1 | 2012-01-05 17:43:11.589922
DE16290 | 2011-12-22 17:43:11.589922
(2 rows)
即上面的IF语句似乎不起作用并且失败了。
另外我想知道这里是否需要has_vip变量?
以及如何确保主键_from和_to确实存在于pref_users表中,或者这已经被处理(因为其中一个UPDATE语句将“抛出异常”并且事务将被回滚)?
更新:
感谢您的所有回复,我也有一个使用技巧:
if (not coalesce(has_vip, false)) then
return;
end if;
但是现在我有一个新问题:
# select id,vip from pref_users where id in ('DE16290', 'DE1');
id | vip
---------+----------------------------
DE1 | 2012-01-05 17:43:11.589922
DE16290 |
(2 rows)
(即 DE1 直到 5 月才有 vip,应该可以给 DE16290 一周的时间,但是):
# select pref_move_week('DE1', 'DE16290');
pref_move_week
----------------
(1 row)
# select id,vip from pref_users where id in ('DE16290', 'DE1');
id | vip
---------+----------------------------
DE1 | 2012-01-05 17:43:11.589922
DE16290 |
(2 rows)
(出于某种原因,什么都没有改变?)
更新 2:最终解决方案 -
create or replace function pref_move_week(_from varchar,
_to varchar) returns void as $BODY$
begin
select 1 from pref_users
where id=_from and
vip > current_timestamp + interval '1 week';
if not found then
return;
end if;
update pref_users set
vip = vip - interval '1 week'
where id=_from;
update pref_users set
vip = greatest(vip, current_timestamp) + interval '1 week'
where id=_to;
end;
$BODY$ language plpgsql;