5

使用以下语句,我在查找前 10 名得分(包括并列条目)时得到了一些帮助

select T.EntryID, T.CategoryID, T.Score
from (
   select EntryID, CategoryID, Score,
          dense_rank() over(order by Score) as rn
   from YourTable
 ) T
where T.rn <= 10

(感谢 [mikael-eriksson]:https ://stackoverflow.com/users/569436/mikael-eriksson )

[问题]:MSSQL 选择前 10 名但包含重复值的列这是示例数据:

EntryID CategoryID  Score
3036    1           85
3159    1           85
3039    1           84
3146    1           83
3225    1           82
3045    1           82
3047    1           80
3048    1           80
3049    1           80
3193    1           80
3098    1           80
3025    1           72
3082    1           70
3167    1           70
3122    1           67
3220    1           65
3080    1           65
3168    1           64
______________________
Total Entries >= 18

要求前 10 名(或任何可能的前 100 名)中的每个类别至少有一个条目,在这种情况下,有 3 个类别。

现在我需要做的就是在前 10 名中每个类别至少包含一个条目。即,如果所有前 10 名分数都来自类别 1,并且有 3 个类别,我需要从类别 1 中删除 2 个最低分数并且包括第 2 类和第 3 类的最高分条目。

正如您从结果中看到的,所有条目都来自类别 1,所以我需要从结果集中删除 EntryID 的 3220、3080 和 3168,因为它们是得分最低的,并包括类别 2 中得分最高的条目以及最高得分在类别 3 中评分条目,因此结果如下所示:

EntryID CategoryID  Score
3036    1           85
3159    1           85
3039    1           84
3146    1           83
3225    1           82
3045    1           82
3047    1           80
3048    1           80
3049    1           80
3193    1           80
3098    1           80
3025    1           72
3082    1           70
3167    1           70
3122    1           67
3019    3           60
3800    2           54
______________________
Total Entries >= 17

下面的场景也是如此,让我们看一下前 5 名而不是前 10 名,以使其看起来更容易一些,正如您在此示例中看到的那样,前 5 名分数不包括类别 2 中的条目

EntryID CategoryID  Score
3036    1           85
3159    1           85
3039    1           84
3146    1           83
3225    1           82
3045    1           82
3019    3           60
______________________
Total Entries >= 7

在这种情况下,条目 3225 和 3045 需要删除,因为它们是得分最低的条目(需要包括 3047,因为即使它是得分最低的条目,我需要结果中所有类别的条目)并且我需要包括得分最高的条目来自类别 2 的条目,我希望是这样的:

EntryID CategoryID  Score
3036    1           85
3159    1           85
3039    1           84
3146    1           83
3019    3           60
3800    2           54
______________________
Total Entries >= 6

然后可能存在可能没有进入特定类别的情况,例如没有类别 2 条目,因此结果应该仍然具有前 5 名,就像上面前 5 名的原始结果集一样(包括在下面作为参考)

EntryID CategoryID  Score
3036    1           85
3159    1           85
3039    1           84
3146    1           83
3225    1           82
3045    1           82
3019    3           60
______________________
Total Entries >= 7

如果我在重复自己,请原谅,我只是想清楚地理解;)

我真的很感激帮助!

4

1 回答 1

8

正如我所看到的,您需要以更复杂的方式对行进行排名,以便包括每个类别中排名靠前的条目,而不管它们的值如何,而不是排名靠前的条目则根据它们的整体被包括在内排名。

我要建议的可能不是最有效的解决方案,但它应该有效,如果没有其他办法,可能会激发其他人想出更好的东西:

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
;

第一个 CTE 是按类别对行进行排名,从而让我们找出哪些条目成为各自类别中的顶级条目。下一步(第二个 CTE)是关于获得全球排名,这一次要考虑一个条目是否是其类别中的第一名。类别最高值的排名较低,因此确保包含在最终结果中。(当然,您需要确保类别的数量不大于您希望在输出中接收的不同值的数量。)

这是SQL Fiddle上的一个活生生的例子。

于 2012-08-19T10:11:54.827 回答