Window Functions:
This is what window functions are made for https://www.postgresql.org/docs/current/static/tutorial-window.html
See the db<>fiddle
SELECT
s_id, v_id, w_cost, av_id
FROM
(SELECT
s_id,
v_id,
av_id,
COALESCE(w_cost, r_cost) as w_cost, -- A
MAX(COALESCE(w_cost, r_cost)) OVER (PARTITION BY v_id) as max_w_cost -- B
FROM testdata) s
WHERE
max_w_cost = w_cost -- C
A: COALESCE
gives the first not NULL
value in the list. So if w_cost
is NULL
, r_cost
will be taken.
B: The window function MAX()
gives the max value in the partition of v_id
. The max function ueses the same COALESCE
clause as in (A)
C: The WHERE
clause filters the row where max equals the current value of w_cost
.
If there are more rows with the same MAX
value in my example you get all of them. If you just want one of them then you can add a column to the partition to make the window more precise. Or you can order by something and just take the first one or you take a more or less random one by DISTINCT ON
.
DISTINCT ON:
With DISTINCT ON
you can filter the distinct row for special columns (whereas the normal DISTINCT
looks at all columns). Because a result set without any ORDER BY
clause can be very random, it should be sorted by v_id and the final cost (greatest first (DESC
); calculated with the COALESCE
function as stated above). Then the DISTINCT
takes the first row.
db<>fiddle
SELECT DISTINCT ON (v_id) -- C
s_id, v_id, cost as w_cost, av_id
FROM
(SELECT
s_id,
v_id,
av_id,
COALESCE(w_cost, r_cost) as cost -- A
FROM testdata
ORDER BY v_id, cost DESC) s -- B
A: COALESCE
as mentioned in the window function section.
B: Ordering to get the wanted row first.
C: DISTINCT ON
filters for every distinct v_id
the first row.