The first query fails if any row has quantity IS NULL
(as Gordon demonstrates).
The second query only fails if all rows have quantity IS NULL
. So it should be usable in most cases. (And it's faster.)
Postgres 13 or newer
Use the standard SQL clause WITH TIES
:
SELECT id
FROM product
ORDER BY quantity DESC NULLS LAST
FETCH FIRST 1 ROWS WITH TIES;
db<>fiddle here
Works with any amount of NULL
values.
The manual:
SQL:2008 introduced a different syntax to achieve the same result,
which PostgreSQL also supports. It is:
OFFSET start { ROW | ROWS }
FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } { ONLY | WITH TIES }
In this syntax, the start
or count
value is required by the standard
to be a literal constant, a parameter, or a variable name; as a
PostgreSQL extension, other expressions are allowed, but will
generally need to be enclosed in parentheses to avoid ambiguity. If
count
is omitted in a FETCH
clause, it defaults to 1. The WITH TIES
option is used to return any additional rows that tie for the last
place in the result set according to the ORDER BY
clause; ORDER BY
is
mandatory in this case. ROW
and ROWS
as well as FIRST
and NEXT
are
noise words that don't influence the effects of these clauses.
Notably, WITH TIES
cannot be used with the (non-standard) short syntax LIMIT n
.
It's the fastest possible solution. Faster than either of your current queries. More important for performance: have an index on (quantity)
. Or a more specialized covering index to allow index-only scans (a bit faster, yet):
CREATE INDEX ON product (quantity DESC NULLS LAST) INCLUDE (id);
See:
We need NULLS LAST
to keep NULL
values last in descending order. See:
Postgres 12 or older
A NULL-safe query:
SELECT id, quantity
FROM product
WHERE quantity IS NOT DISTINCT FROM (SELECT MAX(quantity) FROM product);
Or, probably faster:
SELECT id, quantity
FROM (
SELECT *, rank() OVER (ORDER BY quantity DESC NULLS LAST) AS rnk
FROM product
) sub
WHERE rnk = 1;
See:
Faster alternatives for big tables: