Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PostgreSQL bug in window function on partition?

I have a table t that has the following data:

    name    | n
------------+---
 school     | 4
 hotel      | 2
 restaurant | 6
 school     | 3
 school     | 5
 hotel      | 1

When I run the following query, the result is somewhat odd.

select name, n,
       first_value(n) over (partition by name order by n desc),
       last_value(n) over (partition by name order by  n)
from t;

    name    | n | first_value | last_value
------------+---+-------------+------------
 hotel      | 1 |           2 |          1
 hotel      | 2 |           2 |          2
 restaurant | 6 |           6 |          6
 school     | 3 |           5 |          3
 school     | 4 |           5 |          4
 school     | 5 |           5 |          5
(6 rows)

Although first_value works as I expected, last_value works strange. I think the values of last_value column should be the same as first_value's because the first_value is order by n descending.

Is this a PostgreSQL's bug or am I missed something?

The version of PostgreSQL is:

postgres=# select version();
                                                              version
-----------------------------------------------------------------------------------------------------------------------------------
 PostgreSQL 9.4.1 on x86_64-apple-darwin14.1.0, compiled by Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn), 64-bit
(1 row)
like image 527
ntalbs Avatar asked May 07 '15 04:05

ntalbs


1 Answers

No, this is not a bug. The first_value() and last_value() functions work on the window frame, not the partition. The window frame, as per the documentation, defaults to the start of the partition to the current row if no frame_clause is specified. That is just what you need for first_value() but for last_value() you should add range between unbounded preceding and unbounded following to your WINDOW definition to look beyond the current row:

select name, n,
       first_value(n) over (partition by name order by n desc),
       last_value(n) over (partition by name order by n
         range between unbounded preceding and unbounded following)
from t;

Note also that this has nothing to do with ordering of the rows in the partition. The ordering produces the partition in a certain order (not surprisingly) and the frame-based functions then work on the window frame without knowing or caring about any ordering of the rows.

like image 101
Patrick Avatar answered Nov 10 '22 12:11

Patrick