如何在此方案中按顺序排序和分组?

时间:2017-01-15 13:34:16

标签: sql sql-server

我需要根据DESC的TotalUsers选择TOP 3 Sports并将它们分组为Individual Sports。

我到目前为止所做的是

SELECT *
FROM (
    SELECT R.Sports, R.RoomID ,R.Name,
     COUNT(C.ChatUserLogId) AS TotalUsers,
     ROW_NUMBER()
      OVER (PARTITION BY R.SPORTS ORDER BY R.SPORTS DESC ) AS Rank
    FROM Room R JOIN ChatUserLog C
    ON R.RoomID = C.RoomId
    GROUP BY 
     R.RoomID,
     R.Name,
     R.Sports                
    ) rs WHERE Rank  IN (1, 2, 3)   
ORDER BY Sports, TotalUsers DESC

以下是SQL的输出

Sports                                             RoomID      Name                                                                                                 TotalUsers  Rank
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Aerobics                                           6670        Aerobic vs. Anaerobic Exercise: Which is Best to Burn more Fat?                                      17          1
Aerobics                                           7922        Is it okay to be fat if you’re fit?                                                                  13          2
Aerobics                                           6669        What is the best time of the day to do an aerobic work out?                                          7           3
Archery                                            7924        Who were the best archers in history?                                                                8           1
Archery                                            7925        Should I get into shooting or archery?                                                               7           2
Archery                                            7926        What advantages, if any, do arrows have over bullets?                                                6           3
Badminton                                          6678        Which is more challenging, physically and mentally: badminton or tennis?                             9           1
Badminton                                          6677        Who is your favorite - Lee chong wei or Lin dan?                                                     8           2
Badminton                                          6794        Which single athlete most changed the sport?                                                         7           3
Billiards                                          6691        How to get great at billiards?                                                                       34          1
Billiards                                          6692        Why is Efren Reyes the greatest billiards and pool player of all time?                               31          2
Boxing                                             6697        Mike Tyson: The greatest heavyweight of all time?                                                    13          1
Boxing                                             6700        Who is considered the greatest boxer of all time? Why?                                               13          2
Boxing                                             6699        What is the greatest, most exciting boxing fight of all-time?                                        12          3

但我的查询并没有解决我的要求。我需要输出如下所示。以下输出选择TotalUsers并按运动对它们进行分组。

Sports      TotalUsers
-----------------------
Billiards   34
Billiards   31
Aerobics    17
Aerobics    13
Aerobics    7
Boxing      13
Boxing      13
Boxing      12

感谢任何帮助。

3 个答案:

答案 0 :(得分:1)

从所需数据的描述中,您似乎只想从子查询中选择两列:

SELECT rs.Sports, rs.TotalUsers
FROM (SELECT R.Sports, R.RoomID ,R.Name,
             COUNT(C.ChatUserLogId) AS TotalUsers,
             ROW_NUMBER() OVER (PARTITION BY R.SPORTS ORDER BY R.SPORTS DESC ) AS Rank
      FROM Room R JOIN
           ChatUserLog C
           ON R.RoomID = C.RoomId
      GROUP BY R.RoomID, R.Name,  R.Sports                
      ) rs
WHERE Rank IN (1, 2, 3)   
ORDER BY Sports, TotalUsers DESC;

唯一的变化是外部查询选择了你想要的两列。

答案 1 :(得分:1)

您的代码看起来非常接近,但似乎有三个问题。

Over子句

您的OVER子句中出现错误:

 ROW_NUMBER() OVER(PARTITION BY R.SPORTS ORDER BY R.SPORTS DESC)

PARTITION BY语句在重新启动每个分区的排名时是正确的。但是,在每个分区中,您按分区标准排序,这是不确定的(对于分区中的每个值,R.SPORTS必须相等,因此ORDER BY将不起作用)。相反,您想要的是按总用户排序。声明是:

 ROW_NUMBER() OVER(PARTITION BY R.SPORTS ORDER BY COUNT(C.CHATUSERLOGID) DESC)

(如果您希望具有相同数量的用户的房间具有相同的排名,您也可以使用RANK()代替ROW_NUMBER。)

最终查询排序

问题表明您正在寻求按如下方式订购结果集:

  • 首先,运动;运动应该由该类别中最大的房间订购
  • 其次,每项运动的前三个房间按大小降序排列

第一个标准要求内部选择语句中有一个新列:对于每个房间,该运动的任何房间的用户数最多?这可以写成:

MAX(COUNT(C.CHATUSERLOGID)) OVER (PARTITION BY R.SPORTS) MaxSportsUsers

如果此列可用,您可以按MaxSportsUsers降序排序,然后按Rank升序。

限制前3项运动:出现问题

问题解决方案表明您只想要排名前三的运动,按其顶级会议室中的用户数量排名。因此,您需要对表单进行排名:

RANK() OVER (PARTITION BY CATEGORY ORDER BY MAX(COUNT(USERID)) OVER (PARTITION BY CATEGORY)) CategoryTop

但是 SQL Server不支持此,并且尝试它会引发错误"窗口函数不能在另一个窗口函数或聚合的上下文中使用"。

有一些替代方案。作为一个,请注意,如果我们针对内部查询(rs)运行SELECT TOP 3 SPORT, MAX(TotalUsers) MaxUsers FROM RS ORDER BY 2 DESC,则查询将产生前三个运动和最高用户数。将这些记录加入体育赛事的RS将限制最终输出到前三项运动。

此方法要求从内部联接引用RS。为此,必须将嵌套查询(SELECT * FROM (SELECT...) rs)转换为公用表表达式(WITH RS AS (SELECT...) SELECT * FROM RS)。这允许查询WITH RS AS (SELECT...) SELECT * FROM RS JOIN (SELECT... FROM RS) R2...

形式

一旦查询采用CTE格式,我们就可以加入CTE查询,即INNER JOIN (SELECT TOP 3 SPORT, MAX(TOTALUSERS) MaxSportsUsers FROM RS GROUP BY SPORT ORDER BY 2 DESC) RS2 ON RS2.SPORT = RS.SPORT),保持ORDER BY子句相同。内部联接将最终数据集限制为前3项运动。

MaxSportsUsers列移动到内部联接,可以从RS(以前是内部查询)中删除它。

最终查询

结合上述内容,我们得到最终查询:

WITH RS AS
(
SELECT R.Sports, R.RoomID ,R.Name,
             COUNT(C.ChatUserLogId) AS TotalUsers,
             ROW_NUMBER() OVER (PARTITION BY R.SPORTS ORDER BY COUNT(C.ChatUserLogId) DESC ) AS Rank
      FROM Room R
      JOIN ChatUserLog C ON R.RoomID = C.RoomId
      GROUP BY R.RoomID, R.Name,  R.Sports
)
SELECT rs.Sports, rs.TotalUsers
FROM rs
INNER JOIN (
    SELECT TOP 3 SPORTS, MAX(TOTALUSERS) MaxSportsUsers FROM RS GROUP BY SPORTS ORDER BY 2 DESC
) RS2 ON RS2.SPORTS = RS.SPORTS
WHERE Rank IN (1, 2, 3)   
ORDER BY MaxSportsUsers DESC, RANK;

答案 2 :(得分:0)

如果你想要前三名,那就先获得前三名。这样的事情:

with top3Sports as (
select top 3 sports, count(chatUserLogId) users
from room r join chatUserLog c on r.roomId = c.roomId
group by sports 
order by count(chatUserLogId) desc
)

select the fields you need
from top3Sports join other tables etc

这比你尝试的方法简单得多。但请记住,无论你采取什么方法,关系都会让你感到困惑。