MSSQL选择前10名获奖成绩,其中包括每个类别领带和至少一个(MSSQL Select Top 1

2019-09-21 08:54发布

我得到了一些帮助寻找顶部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-埃里克森]: 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从ResultSet下降,因为它们是最低的得分,并且包括在第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

请原谅,如果我重复自己,我只是想讲清楚明白;)

我很欣赏的帮助!

Answer 1:

正如我可以看到它,你需要在一个更复杂的方式进行排名你行,让那些在每个类别中的最高者的条目,而不管他们的价值观,和条目是不是包含在上面的人包括根据他们的整体排名。

我什么建议可能不是最有效的解决方案,但它应该工作,如果没有别的可以,可能会激发别人拿出更好的东西:

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小提琴活生生的例子一起玩。



文章来源: MSSQL Select Top 10 winning scores, including Ties and at least one from each category