Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to COALESCE a timestamp column?

In PostgreSQL 9.3 I have the following table with 2 timestamps:

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
);

The timestamps vip and grand indicate if the users of my game have paid for certain privilleges - until those dates.

When a user connects to my game server, I call the following procedure with OUT parameters:

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;

This does work well, but sometimes delivers NULL values to my game daemon (to a Perl script):

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

I don't need a NULL though (and it prints a warning in my Perl script) - I just need a "true" or "false" values there.

So I have tried:

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

But this gives me error:

# 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

So I wonder what to do here please?

Do I really have to

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;

or is there maybe a nicer way (like maybe "epoch start" or "yesterday")?

UPDATE:

As suggested by Clodoaldo Neto (thanks!) I've tried:

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

but is_vip is NULL when vip is NULL:

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

And when I try either of the following I get syntax error:

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;

How can I SELECT into 2 variables at once here?

like image 576
Alexander Farber Avatar asked Dec 11 '25 19:12

Alexander Farber


1 Answers

If you want a boolean:

coalesce(grand > current_timestamp, false)

If you need 0 or 1:

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

In your updated question you have an extra comma between the select list and the into clause

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

Take it out

coalesce(vip > current_timestamp, false)
into is_grand, is_vip
like image 127
Clodoaldo Neto Avatar answered Dec 15 '25 19:12

Clodoaldo Neto



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!