I have a table like this:
id | name | salary
------------------
1 | guy1 | 1000
2 | guy2 | 750
3 | guy3 | 400
4 | guy4 | 1000
5 | guy5 | 925
6 | guy6 | 900
I need to take the highest salaries (in this case 2 * 1000) and the lowest (in this case 1 * 400), and return the difference between highest and lowest calculated like this:
1000 * 2 - 400 * 1 = 1600
difference
----------
1600
I tried to filter the table where salaries are highest and lowest but failed.
If the table is empty the result should be 0.
Postgres 13 adds the WITH TIES
clause to include all peers of the nth row:
If you have an index on salary
, this will be as fast as it gets. Much faster than involving window functions:
SELECT COALESCE(sum(salary), 0) AS diff
FROM (
( -- parentheses required
SELECT salary
FROM tbl
ORDER BY salary DESC
FETCH FIRST 1 ROWS WITH TIES
)
UNION ALL
(
SELECT salary * -1
FROM tbl
ORDER BY salary
FETCH FIRST 1 ROWS WITH TIES
)
) sub;
db<>fiddle here
Postgres can take the first and last values from an index on (salary)
directly. Quasi-instantaneous result, no matter how big the table might be.
COALESCE()
to get 0
instead of NULL
when the table is empty.
Why the extra parentheses? The manual:
(
ORDER BY
andLIMIT
can be attached to a subexpression if it is enclosed in parentheses. Without parentheses, these clauses will be taken to apply to the result of theUNION
, not to its right-hand input expression.)
See:
This is assuming salary
is NOT NULL
, else append NULLS LAST
to the descending order. See: