Comme je peux le voir, vous devez classer vos lignes d'une manière plus sophistiquée, de sorte que les entrées qui sont les premières dans chaque catégorie soient incluses quelles que soient leurs valeurs, et les entrées qui ne sont pas les premières sont incluses en fonction de leur global classements.
Ce que je suis sur le point de suggérer n'est peut-être pas la solution la plus efficace, mais cela devrait fonctionner et, si rien d'autre ne peut le faire, cela pourrait inspirer quelqu'un d'autre à proposer quelque chose de mieux :
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
;
Le premier CTE classe les rangées par catégories, nous permettant ainsi de découvrir quelles entrées deviennent les meilleures dans leurs catégories respectives. La prochaine étape (deuxième CTE) consiste à obtenir des classements mondiaux, cette fois en tenant compte du fait qu'une entrée est la meilleure de sa catégorie ou non. Les valeurs les plus élevées de la catégorie reçoivent des classements inférieurs et sont donc assurées d'être incluses dans les résultats finaux. (Bien sûr, vous devez vous assurer que le nombre de catégories n'est pas supérieur au nombre de valeurs distinctes que vous souhaitez recevoir dans la sortie.)
Voici un exemple en direct sur SQL Fiddle jouer avec.