Xorthax now knows how to get the first value in a group. But what if he wants the value at the end?
That's what LAST_VALUE() does - but it requires one important detail.
LAST_VALUE() returns the last value in a sequence of rows.
LAST_VALUE(column) OVER (
PARTITION BY column
ORDER BY column
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
)
This works because:
PARTITION BY defines the groupORDER BY defines the sequence| CustomerID | OrderDate | Amount |
|---|---|---|
| A | 2024-01-01 | 100 |
| A | 2024-01-05 | 150 |
| B | 2024-01-02 | 200 |
| B | 2024-01-06 | 50 |
SELECT CustomerID, OrderDate, Amount,
LAST_VALUE(Amount) OVER (
PARTITION BY CustomerID
ORDER BY OrderDate
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS LastAmount
FROM Orders;
Result:
| CustomerID | OrderDate | Amount | LastAmount |
|---|---|---|---|
| A | 2024-01-01 | 100 | 150 |
| A | 2024-01-05 | 150 | 150 |
| B | 2024-01-02 | 200 | 50 |
| B | 2024-01-06 | 50 | 50 |
Each row now shows the last value within its customer group.
PARTITION BY CustomerID creates a group for each customer.
ORDER BY OrderDate defines the sequence within each group.
The window frame includes all rows in the group, so LAST_VALUE() can see the true last row.
Important: If you leave out the window frame, SQL only looks at rows up to the current row.
That means LAST_VALUE() will return the current row's valueโnot the actual last value in the group.
For each order, show the totalamount from the last order based on orderdate.
| Column | Type |
|---|---|
| orderid | bigint |
| customerid | bigint |
| orderdate | timestamp without time zone |
| totalamount | double precision |
| status | text |
| Column |
|---|
| orderid |
| orderdate |
| totalamount |
| last_amount |
FIRST_VALUE() and LAST_VALUE() give you the edges of a sequence.
Next, you'll learn how to get a value from any position.