Using the LEAD() Function to Get a Value from a Later Row in PostgreSQL

In PostgreSQL the lead() function returns the value from a subsequent row to the current row, specified by the given offset.

The offset specifies how many rows after the current row to get the value from. For example, an offset of 1 gets the value from the next row.

Syntax

The syntax goes like this:

lead ( value [, offset [, default ]] )

The value argument is required.

The offset argument is optional, and its default value is 1.

The optional default argument specifies what to use if there are no rows at the offset (for example, if we’re on the last row and we use an offset of 1 or more).

Example

Here’s an example to demonstrate:

\pset null 'null'
SELECT
    vendorid,
    productname,
    productprice,
    lead( productprice ) OVER ( ORDER BY productprice )
FROM products;

Result:

 vendorid |           productname           | productprice |  lead  
----------+---------------------------------+--------------+--------
     1004 | Bottomless Coffee Mugs (4 Pack) |         9.99 |  10.00
     1003 | Hammock                         |        10.00 |  11.99
     1001 | Long Weight (green)             |        11.99 |  12.45
     1004 | Tea Pot                         |        12.45 |  14.75
     1001 | Long Weight (blue)              |        14.75 |  25.99
     1001 | Left handed screwdriver         |        25.99 |  25.99
     1001 | Right handed screwdriver        |        25.99 |  33.49
     1002 | Sledge Hammer                   |        33.49 |  55.99
     1003 | Straw Dog Box                   |        55.99 | 245.00
     1003 | Chainsaw                        |       245.00 |   null
(10 rows)

We can see that the lead column returns the value from the next row of the productprice column. That’s because I specified productprice as the only argument to lead() and I used the default values for the other arguments (i.e. I didn’t specify any other arguments). The other arguments are optional.

The default offset is 1, and so if we omit that argument it’s assumed to be 1 and we get the next row.

We get null on the last row because there’s no subsequent row for which to take a value from.

By the way, the first line of code above sets the string for null values. Without this, my command line would return an empty string whenever there are null values. I only did that so that it was obvious when we got a null value.

We can also use the lead() function’s optional default argument to change what’s returned in such cases (example later).

Specify an Offset

Here’s an example of specifying an offset:

SELECT
    vendorid,
    productname,
    productprice,
    lead( productprice, 3 ) OVER ( ORDER BY productprice )
FROM products;

Result:

 vendorid |           productname           | productprice |  lead  
----------+---------------------------------+--------------+--------
     1004 | Bottomless Coffee Mugs (4 Pack) |         9.99 |  12.45
     1003 | Hammock                         |        10.00 |  14.75
     1001 | Long Weight (green)             |        11.99 |  25.99
     1004 | Tea Pot                         |        12.45 |  25.99
     1001 | Long Weight (blue)              |        14.75 |  33.49
     1001 | Left handed screwdriver         |        25.99 |  55.99
     1001 | Right handed screwdriver        |        25.99 | 245.00
     1002 | Sledge Hammer                   |        33.49 |   null
     1003 | Straw Dog Box                   |        55.99 |   null
     1003 | Chainsaw                        |       245.00 |   null
(10 rows)

This time the last three rows are null. That’s because I specified an offset of 3, which means that it goes forward three rows to get the value. That means that we won’t get a value once we’re passed the fourth row from the end, due to the fact that there are no more rows for which to get a value from.

Specify a Default Value

Here’s an example of specifying a default value to use for when there’s no value at the given offset:

SELECT
    vendorid,
    productname,
    productprice,
    lead( productprice, 3, 0.00 ) OVER ( ORDER BY productprice )
FROM products;

Result:

 vendorid |           productname           | productprice |  lead  
----------+---------------------------------+--------------+--------
     1004 | Bottomless Coffee Mugs (4 Pack) |         9.99 |  12.45
     1003 | Hammock                         |        10.00 |  14.75
     1001 | Long Weight (green)             |        11.99 |  25.99
     1004 | Tea Pot                         |        12.45 |  25.99
     1001 | Long Weight (blue)              |        14.75 |  33.49
     1001 | Left handed screwdriver         |        25.99 |  55.99
     1001 | Right handed screwdriver        |        25.99 | 245.00
     1002 | Sledge Hammer                   |        33.49 |   0.00
     1003 | Straw Dog Box                   |        55.99 |   0.00
     1003 | Chainsaw                        |       245.00 |   0.00
(10 rows)

Note that I provided a value that’s compatible with the productprice column. This is required.

Here’s what happens if I pass an incompatible value:

SELECT
    vendorid,
    productname,
    productprice,
    lead( productprice, 3, 'No Value' ) OVER ( ORDER BY productprice )
FROM products;

Result:

ERROR:  invalid input syntax for type numeric: "No Value"
LINE 5:     lead( productprice, 3, 'No Value' ) OVER ( ORDER BY prod...
                                   ^