I recently came across an issue where I was retrieving data for a UI and dealing with potential dupes. for my purposes I used CTEs and row_number function to solve my particular issue.
A CTE is essentially a kind of temporary table or a named result set off of a physical table (sort of like an in-line view).
With this function, you can number rows in your result set. Even better, you can PARTITION BY to split your result set up into groups. I might not want to see 1-10 as my row numbers, I might want to see 1-5 and 1-5 based on some column that I decide to partition the data by. Note, this is a horizontal partition of rows.