2014-06-19 44 views
0

在PostgreSQL 9.3我有以下表2個時間戳:如何合併時間戳列?

create table pref_users (
     id varchar(32) primary key, 
     first_name varchar(64) not null, 
     last_name varchar(64), 
     female boolean, 
     avatar varchar(128), 
     city varchar(64), 
     mobile varchar(64), 
     login timestamp default current_timestamp, 
     logout timestamp, 
     last_ip inet, 
     vip timestamp,  /* XXX can be NULL */ 
     grand timestamp,  /* XXX can be NULL */ 
     mail varchar(256), 
     green integer, 
     red integer, 
     medals integer not null default 0 
); 

時間戳vipgrand表示如果遊戲的用戶已經支付了一定的privilleges - 直到這些日期。

當用戶連接到我的遊戲服務器,我打電話與OUT參數以下過程:

create or replace function pref_get_user_info(
    IN _id varchar, 
    OUT is_banned boolean, 
    OUT is_grand boolean, 
    OUT is_vip boolean, 
    OUT rep integer 
) as $BODY$ 
     begin 
      is_banned := exists(select 1 from pref_ban where id=_id); 

      if is_banned then 
       return; 
      end if; 

      select 
       grand > current_timestamp, 
       vip > current_timestamp, 
      into is_grand is_vip 
      from pref_users where id=_id; 

      if is_grand or is_vip then 
       return; 
      end if; 

      select 
       count(nullif(nice, false)) - 
       count(nullif(nice, true)) 
      into rep 
      from pref_rep where id=_id; 
     end; 
$BODY$ language plpgsql; 

這確實工作得很好,但有時提供NULL值到我的遊戲後臺程序(Perl腳本):

# select * from pref_get_user_info('OK674418426646'); 
is_banned | is_grand | is_vip | rep 
-----------+----------+--------+----- 
f   |   |  | 126 
(1 row) 

我並不需要一個NULL雖然(和它打印警告我的Perl腳本) - 我只是需要一個「真」或「假」值存在。

所以我曾嘗試:

select 
    coalesce(grand, 0) > current_timestamp, 
    coalesce(vip, 0) > current_timestamp, 
into is_grand is_vip 
from pref_users where id=_id; 

但是這給了我錯誤:

# select * from pref_get_user_info('OK674418426646'); 
ERROR: COALESCE types timestamp without time zone and integer cannot be matched 
LINE 2:       coalesce(grand, 0) > current_timesta... 
               ^
QUERY: select 
         coalesce(grand, 0) > current_timestamp, 
         coalesce(vip, 0) > current_timestamp, 
            is_vip 
        from pref_users where id=_id 
CONTEXT: PL/pgSQL function pref_get_user_info(character varying) line 9 at SQL statement 

所以我想在這裏做什麼嗎?

難道我真的要

select 
    coalesce(grand, current_timestamp - interval '1 day') > current_timestamp, 
    coalesce(vip, current_timestamp - interval '1 day') > current_timestamp, 
into is_grand is_vip 
from pref_users where id=_id; 

或有可能是更好的方式(譬如「時代的開始」或「昨天」)?

UPDATE:

正如Clodo阿爾內託建議我已經試過(謝謝!):

select 
coalesce(grand > current_timestamp, false), 
coalesce(vip > current_timestamp, false), 
into is_grand is_vip 
from pref_users where id=_id; 

is_vip爲NULL時vip爲NULL:

# select * from pref_get_user_info('OK674418426646'); 
is_banned | is_grand | is_vip | rep 
-----------+----------+--------+----- 
f   | t  |  | 
(1 row) 

而且當我嘗試以下任我得到語法錯誤:

select 
coalesce(grand > current_timestamp, false), 
coalesce(vip > current_timestamp, false), 
into is_grand, is_vip 
from pref_users where id=_id; 

select 
coalesce(grand > current_timestamp, false), 
coalesce(vip > current_timestamp, false), 
into (is_grand, is_vip) 
from pref_users where id=_id; 

怎麼能在這裏一次我SELECT到2個變量?

+1

在第一個版本作爲編輯,刪除之前的逗號「到」在第三行的端部。 –

+0

哦,對,我很愚蠢(在vi編輯器中複製上面的行)。但是,這兩個變量之間的逗號呢?這兩種方法都可以在「psql」提示符下被接受,但是會產生不同的結果... –

回答

4

如果你想有一個布爾值:

coalesce(grand > current_timestamp, false) 

如果需要0或1:

coalesce((grand > current_timestamp)::integer, 0) 

在更新後的問題,你有選擇列表和into子句之間的額外的逗號

coalesce(vip > current_timestamp, false), 
into is_grand, is_vip 

拿出來

coalesce(vip > current_timestamp, false) 
into is_grand, is_vip 
+1

這是有效的,因爲'current_timestamp'不能爲空。如果盛大被比作可能爲空的東西,你會怎麼做?你想'coalesce(date1,0)> coalesce(date2,0)' –

+1

只要__at至少___其中一個操作數爲空,結果將爲null,如'select null> null'。所以答案仍然適用。 –

+0

+1謝謝,但你能否請檢查更新的問題?我無法確定一次選擇2個變量的正確語法... –