Re: first_value/last_value

From: Matija Lesar <matija(dot)lesar(at)gmail(dot)com>
To: Tom Smith <tomsmith1989sk(at)gmail(dot)com>
Cc: Melvin Davidson <melvin6925(at)gmail(dot)com>, Adam Brusselback <adambrusselback(at)gmail(dot)com>, PostgreSQL General <pgsql-general(at)postgresql(dot)org>
Subject: Re: first_value/last_value
Date: 2016-05-19 08:23:44
Message-ID: CAPx3hmPoCzhghz6LCeZcJHmas1QuJfj0safXHZ4ktySCQO93Cg@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

On 19 May 2016 at 05:04, Tom Smith <tomsmith1989sk(at)gmail(dot)com> wrote:

> It would really save all the troubles for many people if postgresql has a
> built-in first/last function along with sum/avg.
> There is already a C extension and a wiki sample and implemented for
> window function.
> I am curious why these two functions were not added along their window
> implementation counter part,
> for completness and consistency
>
>
> On Wed, May 18, 2016 at 10:42 PM, Melvin Davidson <melvin6925(at)gmail(dot)com>
> wrote:
>
>>
>>
>> On Wed, May 18, 2016 at 10:36 PM, Adam Brusselback <
>> adambrusselback(at)gmail(dot)com> wrote:
>>
>>> Here is an example that works in a single query. Since you have two
>>> different orders you want the data back in, you need to use subqueries to
>>> get the proper data back, but it works, and is very fast.
>>>
>>> CREATE TEMPORARY TABLE foo AS
>>> SELECT generate_series as bar
>>> FROM generate_series(1, 1000000);
>>>
>>> CREATE INDEX idx_foo_bar ON foo (bar);
>>>
>>>
>>> SELECT *
>>> FROM (
>>> SELECT bar
>>> FROM foo
>>> ORDER BY bar asc
>>> LIMIT 1
>>> ) x
>>> UNION ALL
>>> SELECT *
>>> FROM (
>>> SELECT bar
>>> FROM foo
>>> ORDER BY bar desc
>>> LIMIT 1
>>> ) y;
>>>
>>> DROP TABLE foo;
>>>
>>
>> Seems to me SELECT min(<column>), max(<column>) FROM deja.vu ; would
>> also work.
>>
>>
>> --
>> *Melvin Davidson*
>> I reserve the right to fantasize. Whether or not you
>> wish to share my fantasy is entirely up to you.
>>
>
>
You can always create your aggregate function for this.

Here is example for getting non null first and last value:

CREATE OR REPLACE FUNCTION firstval_sfunc(anyelement, anyelement)
returns anyelement
language sql
as $BODY$
SELECT CASE WHEN $1 is NULL THEN $2 ELSE $1 END;
$BODY$;

CREATE AGGREGATE myfirstval(anyelement) (
SFUNC = firstval_sfunc,
STYPE = anyelement
);

CREATE OR REPLACE FUNCTION lastval_sfunc(anyelement, anyelement)
returns anyelement
language sql
as $BODY$
SELECT CASE WHEN $2 is NULL THEN $1 ELSE $2 END;
$BODY$;

CREATE AGGREGATE mylastval(anyelement) (
SFUNC = lastval_sfunc,
STYPE = anyelement
);

Outputs:

select myfirstval(b), mylastval(b) from
unnest(array[3,2,null,12,-1]::int[]) b;
myfirstval | mylastval
------------+-----------
3 | -1

select myfirstval(b order by b), mylastval(b order by b) from
unnest(array[3,2,null,12,-1]::int[]) b;
myfirstval | mylastval
------------+-----------
-1 | 12

select myfirstval(b), mylastval(b) from generate_series(10,20000) as b;
myfirstval | mylastval
------------+-----------
10 | 20000

select myfirstval(b), mylastval(b) from
unnest(array['c','b','t','x']::text[]) b;
myfirstval | mylastval
------------+-----------
c | x

Bye,
Matija Lesar

In response to

Browse pgsql-general by date

  From Date Subject
Next Message Alexey Bashtanov 2016-05-19 11:10:49 Re: first_value/last_value
Previous Message Achilleas Mantzios 2016-05-19 08:10:17 Re: How to view creation date and time of a relation