Warm tip: This article is reproduced from serverfault.com, please click

Calculate difference of multiple highest and lowest column values

发布于 2020-11-28 11:17:50

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.

Questioner
Mike Ehrmantraut
Viewed
11
Erwin Brandstetter 2020-11-28 21:20:52

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 and LIMIT 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 the UNION, not to its right-hand input expression.)

See:

This is assuming salary is NOT NULL, else append NULLS LAST to the descending order. See: