在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;
答案 0 :(得分:2)
将时间戳与可能为空的内容进行比较时,可以使用<?php
$displayed = [];
// get number of messages from a specific user to the logged in user
$get_mess = mysqli_query ($connect, "SELECT * FROM private_messages WHERE message_to = '$username' AND message_from ='$user'");
$num_msgs = mysqli_num_rows($get_mess);
// getting all the conversations which concern the user logged on.
$con = mysqli_query ($connect, "SELECT * FROM private_messages WHERE message_from='$username' OR message_to='$username'");
while ($get_con = mysqli_fetch_assoc($con)){
$msg_from = $get_con['message_from'];
$msg_to = $get_con['message_to'];
// get other persons firstname
$u_name = mysqli_query($connect, "SELECT * FROM users WHERE username ='$msg_to'");
$get_cu = mysqli_fetch_assoc($u_name);
$got_ufn = $get_cu['first_name'];
$got_uln = $get_cu['last_name'];
if ($msg_to == $username || $msg_from == $username){
if(!in_array($msg_to, $displayed)) {
echo "<li class='list' role='presentation'>
<div class='parent'>
<div class='disp_pic'>
<img class='img-rounded' src='$profile_pic2'/>
</div>
<div class='user_d'>
<a href='messages.php?u=$msg_from'> $got_ufn $got_uln</a>
</div>";
if ($num_msgs == 0){
// dont display badge
}else {
echo "<span id='num_of_msgs_from' class='badge'>";
if ($user == $user){
$num_msgs == 0;
echo "$num_msgs </span>";
}else {
echo " $num_msgs </span>";
}
}
echo"
</div>
</li>";
$displayed[] = $msg_to;
}
}
} // while closed
?>
函数提供“默认”值进行比较。例如,
COALESE
select 1 from pref_users
where id=_from and
vip > COALESCE(current_timestamp, to_timestamp(0));
函数从列表中返回第一个非空值。见docs。 (还有to_timestamp() docs ...)
答案 1 :(得分:1)
可能有更优雅的解决方案,但我认为
SELECT (vip IS NOT NULL) AND (vip > current_timestamp + interval '1 week')
会做这项工作。 我想你的问题与NULL既不是真的也不是假的有关。
您可以在the docs找到更多信息。
答案 2 :(得分:1)
空值在任何比较时返回false为null(因此,其中null&lt;&gt; 1为false且null = 1为false ... null永远不等于或不等于任何东西)。而不是
if (not has_vip) then return
跟着
if (not has_vip) or has_vip is null then return
你正在使用的语法在这里有点独特,我不习惯阅读它...猜测你来自不同于SQL的背景并且还没有遇到过null的乐趣。 Null是SQL中的一个特殊概念,您需要以不同的方式处理。记住它不等于空白或0,也不小于或大于任何数字。
编辑: 我有点困惑:
select vip > current_timestamp + interval '1 week'
into has_vip from pref_users where id=_from;
我相信这相当于:
select vip
into has_vip from pref_users
where id=_from
and vip > current_timestamp + interval '1 week';
我希望无论如何。现在,如果没有找到记录或VIP值为null,则返回null。如果has_vip为null然后返回,你可以去吗?