Window Functions: last_value(ORDER BY … ASC) same as last_value(ORDER BY … DESC)

The problem with LAST_VALUE() is that the default rules for windowing clauses remove the values that you really want. This is a very subtle problem and is true in all databases that support this functionality.

This comes from an Oracle blog:

Whilst we are on the topic of windowing clauses, the implicit and
unchangeable window clause for the FIRST and LAST functions is ROWS
BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING, in other words
all rows in our partition. For FIRST_VALUE and LAST_VALUE the default
but changeable windowing clause is ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW, in other words we exclude rows after the current one.
Dropping rows off the bottom of a list makes no difference when we are
looking for the first row in the list (FIRST_VALUE) but it does make a
difference when we are looking for the last row in the list
(LAST_VALUE) so you will usually need either to specify ROWS BETWEEN
UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING explicitly when using
LAST_VALUE or just use FIRST_VALUE and reverse the sort order.

Hence, just use FIRST_VALUE(). This does what you want:

with test (id, session_ID, value) as (
      (VALUES (0, 2, 100),
              (1, 2, 120),
              (2, 2, 140),
              (3, 1, 900),
              (4, 1, 800),
              (5, 1, 500)
      )
     )
select id,
       first_value(value) over (partition by session_ID order by id) as first_value_window,
       first_value(value) over (partition by session_ID order by id desc) as first_value_window_desc
from test
order by id

Leave a Comment