【问题标题】:How to COALESCE a timestamp column?如何合并时间戳列?
【发布时间】:2014-08-10 07:09:38
【问题描述】:

在 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 表明我的游戏用户是否已经支付了某些特权 - 直到这些日期。

当用户连接到我的游戏服务器时,我使用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;

或者有没有更好的方法(比如“epoch start”或“yesterday”)?

更新:

按照 Clodoaldo Neto 的建议(谢谢!)我试过了:

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

但是当vip 为NULL 时is_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 个变量?

【问题讨论】:

  • 在编辑的第一个版本中,删除第三行末尾“into”之前的逗号。
  • 哦,对了,愚蠢的我(在 vi-editor 中复制了上面的行)。但是两个变量之间的逗号呢?两种方式都在“psql”提示符下被接受,但提供不同的结果......

标签: postgresql timestamp postgresql-9.3


【解决方案1】:

如果你想要一个布尔值:

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

【讨论】:

  • 这是有效的,因为current_timestamp 不能为空。如果将盛大与可能为空的事物进行比较,您会怎么做。你想coalesce(date1,0) > coalesce(date2,0)
  • 只要至少其中一个操作数为空,结果将为空,如select null > null。所以答案仍然适用。
  • +1 谢谢,但您能检查一下更新后的问题吗?我想不出一次选择 2 个变量的正确语法...
  • 其实不太一样。为了说明回到我的例子,如果你想要coalesce(date1,0) > coalesce(date2,0),这可以转换为case when date1 is not null and date 2 is null then true when date1 is null then false else date1 > date2 end另一方面colaesce(date1 > date2, false)将是case when date1 is null or date2 is null then false else date1 > date2 end。如果我们想避免 case 语句,有没有比做日期差异更简单的方法。
  • @AlexanderFarber 更新了语法修复。始终发布确切的错误消息。
猜你喜欢
  • 1970-01-01
  • 2015-03-19
  • 1970-01-01
  • 1970-01-01
  • 2011-10-22
  • 1970-01-01
  • 2016-02-01
  • 1970-01-01
  • 2013-01-26
相关资源
最近更新 更多