В 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 истек, это будет .
Я пытаюсь создать процедуру 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 имеет 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;