Zoals ik het kan zien, moet je je rijen op een meer verfijnde manier rangschikken, zodat items die de beste zijn in elke categorie worden opgenomen, ongeacht hun waarden, en items die niet de top zijn, worden opgenomen op basis van hun algehele ranglijsten.
Wat ik ga voorstellen is misschien niet de meest efficiënte oplossing, maar het zou moeten werken en, als niets anders kan, iemand anders inspireren om met iets beters te komen:
WITH ranked1 AS (
SELECT
*,
RankByCategory = DENSE_RANK() OVER (
PARTITION BY CategoryID
ORDER BY Score DESC
)
FROM YourTable
),
ranked2 AS (
SELECT
*,
FinalRank = DENSE_RANK() OVER (
ORDER BY
CASE RankByCategory WHEN 1 THEN 1 ELSE 2 END,
Score DESC
)
FROM ranked1
)
SELECT
EntryID,
CategoryID,
Score
FROM ranked2
WHERE FinalRank <= @top_n
;
De eerste CTE rangschikt rijen per categorie, zodat we kunnen zien welke inzendingen de beste worden in hun respectievelijke categorieën. De volgende stap (tweede CTE) gaat over het verkrijgen van wereldwijde ranglijsten, deze keer waarbij rekening wordt gehouden met het feit of een inzending de beste in zijn categorie is of niet. De categorietopwaarden krijgen een lagere ranking en worden dus zeker meegenomen in de einduitslag. (Je moet er natuurlijk voor zorgen dat het aantal categorieën niet groter is dan het aantal verschillende waarden dat je in de uitvoer wilt ontvangen.)
Hier is een live voorbeeld op SQL Fiddle om mee te spelen.