LIMIT 1
after ORDER BY
is just fine to get a single winner:
SELECT a.id, count(*) AS num
FROM (
SELECT requester_id AS id FROM requestaccepted
UNION ALL
SELECT accepter_id AS id FROM requestaccepted
) a
GROUP BY a.id
ORDER BY num DESC
LIMIT 1;
You get an arbitrary pick if there are multiple winners. You might add additional ORDER BY
expressions to get a deterministic pick.
If you must avoid LIMIT
/ FETCH FIRST
(really?) the window function row_number()
is a (more expensive!) alternative:
SELECT id, num
FROM (
SELECT a.id, count(*) AS num
, row_number() OVER (ORDER BY count(*) DESC) AS rn
FROM (
SELECT requester_id AS id FROM requestaccepted
UNION ALL
SELECT accepter_id AS id FROM requestaccepted
) a
GROUP BY a.id
) sub
WHERE rn = 1;
To get all IDs that tie for the win, just add WITH TIES
. Must use standard SQL syntax FETCH FIRST 1 ROWS
instead of the Postgres shortcut LIMIT 1
to add the clause.
SELECT a.id, count(*) AS num
FROM (
SELECT requester_id AS id FROM requestaccepted
UNION ALL
SELECT accepter_id AS id FROM requestaccepted
) a
GROUP BY a.id
ORDER BY count(*) DESC
FETCH FIRST 1 ROWS WITH TIES;
No additional ORDER BY
expressions, that would resolve ties.
If you must avoid LIMIT
/ FETCH FIRST
(really?) the window function rank()
is a (more expensive!) alternative:
SELECT id, num
FROM (
SELECT a.id, count(*) AS num
, rank() OVER (ORDER BY count(*) DESC) AS rnk
FROM (
SELECT requester_id AS id FROM requestaccepted
UNION ALL
SELECT accepter_id AS id FROM requestaccepted
) a
GROUP BY a.id
) sub
WHERE rnk = 1
ORDER BY id; -- optional
db<>fiddle here - with extended test case to show a tie
See: