Top n
With rank()
you get at least 3 rows (fewer if fewer exist). If there are ties among the top 3 ranks, more rows may be returned. See:
If you want exactly 3 rows per location (fewer if fewer exist), you have to break ties. One way is to use row_number()
instead of rank()
.
SELECT *
FROM (
SELECT id, location
, row_number() OVER (PARTITION BY location ORDER BY followers DESC) AS rn
FROM id_follower_location
) r
WHERE rn <= 3
ORDER BY location, rn;
You may want to add ORDER BY
to the outer query to guarantee sorted output.
If there are more than three valid candidates, you get an arbitrary pick from ties - unless you add more ORDER BY
items in the OVER
clause to break ties.
Top 1
As for your query to get the top 1 row: there is a much simpler and faster way in PostgreSQL:
SELECT DISTINCT ON (location)
id, location -- add additional columns freely
FROM id_follower_location
ORDER BY location, followers DESC;
Details for this query technique in this closely related answer: