I’m using keyset pagination to paginate in a table. Table looks like this:
+-------------------------+
| ID | Name | private_key |
+-------------------------+
| 1 | John | null |
| 2 | James| abc123 |
| 3 | Jane | null |
| 4 | Dave | def456 |
| 5 | Will | null |
| ... |
+-------------------------+
I’m using the ID field for the keyset pagination.
I fetch 50 records per time. After every fetch, I get the highest ID in the result set. When I fetch the next 50 results, I fetch the first 50 results AFTER this ID. An example:
SELECT
id,
name,
private_key
FROM
users
WHERE
id > [last_id_fetched]
LIMIT
50
This works perfectly. The problem is, if I use an ORDER statement, the ORDER statement is only applied to the 50 results that are fetched, not the total result set.
I have about 2,000 records, and about 500 of them have a private_key. I want to paginate with keyset pagination on the ID, but I want to fetch all the users where the private_key field is not null first.
How can I achieve this in postgres?
2
Answers
To achieve keyset pagination in PostgreSQL while ensuring that rows with a non-null
private_key
are fetched first, you can use a combination of subqueries and a custom sorting strategy. Here’s how you can do it:In the first query, you fetch the first 50 rows where
private_key
is not null, sorted byprivate_key
and thenid
. After fetching these results, note the lastprivate_key
andid
.In the second query, you fetch the next 50 rows where
private_key
is null and use a combination of sorting byprivate_key
and thenid
. TheWHERE
clause ensures that you continue fetching results after the lastprivate_key
andid
values obtained in the first query.This way, you will paginate using keyset pagination on the
ID
, while ensuring that rows with non-nullprivate_key
values are fetched first.I think, you can use OFFSET and FETCH FIRST for your pagination.
It’s very simple to use:
Or, whithout variables, if we need to populate second page with 5 rows on the each page:
Some exaple for playing: https://dbfiddle.uk/zplwAj9A