【问题标题】:Multi-event tournament standings (with arbitrary number of entries)多赛事锦标赛积分榜(任意数量的参赛作品)
【发布时间】:2019-10-07 05:20:37
【问题描述】:

假设您有一个多项目比赛,参赛者可以尝试任意次数的任何项目。 (奇怪,我知道。)

如何为每项赛事提取想要的球员的最佳时间, 并为其分配一个位置? (一二三...)

Data example:               Desired output:

Name | Event | Score        Name | Event | Score | Rank
--------------------        ----------------------------
Bob      1      50          Given input: "Bob"
Bob      1     100          Bob      1     100      1   
Bob      2      75          Bob      2      75      3
Bob      3      80          Bob      3      80      2
Bob      3      65      
                            Given input: "Jill"
Jill     2      75          Jill     2      90      1
Jill     2      90          Jill     3      60      3
Jill     3      60
                            Given input: "Chris"
Chris    1      70          Chris    1      70      2
Chris    2      50          Chris    2      85      2
Chris    2      85          Chris    3     100      1
Chris    3     100

这是我上一个问题的基础: Multi-event tournament standings

我觉得更好地理解了这个问题(谢谢!),但我无法弥合与这个版本问题的差距。

我有 SQL 5.x,所以我不能使用 Rank() 之类的东西。这也将处理成千上万的分数。

【问题讨论】:

  • 在 MySQL 8.x 中应该很容易。不过,我不知道 5.x。你有哪一个?
  • 为什么在期望输出中,玩家对“Bob”、“Jill”、“Chris”进行排序。排序重要吗?
  • @TheImpaler 我有 5.x,这就是我如此挣扎的原因。
  • @MaksymMoskvychev 我希望它只返回输入的人的分数。
  • 为什么 Chris 在 12 两个事件中的排名都是 2

标签: mysql ranking


【解决方案1】:

可以使用此查询获得所需的输出:

select
IF(event is NULL, CONCAT('Given input: "', name,'"'), name) as name,
IF(event is NULL, '', event) as event,
IF(event is NULL, '', max(score)) as score,
IF(event is NULL, '', (
  select count(s2.name) + 1
  from (
          select name, max(score) as score
          from scores es
          where es.event = s.event
          group by es.name
          order by score desc
        ) s2
  where s2.score > max(s.score)
)) as `rank`

from scores s
group by name, event with rollup
having name is not NULL
order by name, event;

并输出(如果在 mysql cli 中运行查询):

+----------------------+-------+-------+------+
| name                 | event | score | rank |
+----------------------+-------+-------+------+
| Given input: "Bob"   |       |       |      |
| Bob                  | 1     | 100   | 1    |
| Bob                  | 2     | 75    | 3    |
| Bob                  | 3     | 80    | 2    |
| Given input: "Chris" |       |       |      |
| Chris                | 1     | 70    | 2    |
| Chris                | 2     | 85    | 2    |
| Chris                | 3     | 100   | 1    |
| Given input: "Jill"  |       |       |      |
| Jill                 | 2     | 90    | 1    |
| Jill                 | 3     | 60    | 3    |
+----------------------+-------+-------+------+
11 rows in set, 3 warnings (0.00 sec)

应该适用于任何 Mysql 5。

【讨论】:

  • 我不认为你可以在 5 中使用这样的汇总。
  • @Strawberry 为什么不呢?在这种情况下,它可以完美地创建分隔线,例如“给定输入:“Bob””
  • 我认为您误解了问题的意图。
【解决方案2】:

您可以通过采用max() 的事件聚合来获得每个事件的最高分。要模拟dense_rank(),您可以使用子查询计算高于或等于每个事件当前分数的分数。

对于特定的参赛者(这里是 Bob):

SELECT d1.name,
       d1.event,
       max(d1.score) score,
       (SELECT count(*)
               FROM (SELECT d2.event,
                            max(d2.score) score
                            FROM data d2
                            GROUP BY d2.event,
                                     d2.name) x1
               WHERE x1.score >= max(d1.score)
                     AND x1.event = d1.event) rank
       FROM data d1
       WHERE d1.name = 'Bob'
       GROUP BY d1.event
       ORDER BY d1.event;

同时为所有人:

SELECT d1.name,
       d1.event,
       max(d1.score) score,
       (SELECT count(*)
               FROM (SELECT d2.event,
                            max(d2.score) score
                            FROM data d2
                            GROUP BY d2.event,
                                     d2.name) x1
               WHERE x1.score >= max(d1.score)
                     AND x1.event = d1.event) rank
       FROM data d1
       GROUP BY d1.name,
                d1.event
       ORDER BY d1.name,
                d1.event;

db<>fiddle

【讨论】:

    【解决方案3】:

    例如:

    DROP TABLE IF EXISTS my_table;
    
    CREATE TABLE my_table
    (id SERIAL PRIMARY KEY
    ,name VARCHAR(12) NOT NULL
    ,event INT NOT NULL
    ,score INT NOT NULL
    );
    
    INSERT INTO my_table (name,event,score) VALUES
    ('Bob'  ,1, 50),
    ('Bob'  ,1,100),
    ('Bob'  ,2, 75),
    ('Bob'  ,3, 80),
    ('Bob'  ,3, 65),
    ('Jill' ,2, 75),
    ('Jill' ,2, 90),
    ('Jill' ,3, 60),
    ('Chris',1, 70),
    ('Chris',2, 50),
    ('Chris',2, 85),
    ('Chris',3,100);
    
    SELECT a.*
         , FIND_IN_SET(a.score,b.scores) my_rank
      FROM my_table a -- it's possible that this really needs to be a repeat of the subquery below, so
                      -- ( SELECT m.* FROM my_table m JOIN (SELECT name,event,MAX(score) score FROM my_table 
                      -- GROUP BY name, event) n ON n.name = m.name AND n.event = m.event AND n.score = m.score) AS a
      JOIN
         (
    SELECT x.event
         , GROUP_CONCAT(DISTINCT x.score ORDER BY x.score DESC) scores
      FROM my_table x 
      JOIN 
         ( SELECT name
                , event
                , MAX(score) score 
             FROM my_table 
            GROUP  
               BY name
                , event
          ) y 
         ON y.name = x.name 
        AND y.event = x.event 
        AND y.score = x.score
      GROUP 
         BY x.event
         ) b
        ON b.event = a.event
     WHERE FIND_IN_SET(a.score,b.scores) >0;
    +----+-------+-------+-------+------+
    | id | name  | event | score | rank |
    +----+-------+-------+-------+------+
    |  2 | Bob   |     1 |   100 |    1 |
    |  3 | Bob   |     2 |    75 |    3 |
    |  4 | Bob   |     3 |    80 |    2 |
    |  6 | Jill  |     2 |    75 |    3 |
    |  7 | Jill  |     2 |    90 |    1 |
    |  8 | Jill  |     3 |    60 |    3 |
    |  9 | Chris |     1 |    70 |    2 |
    | 11 | Chris |     2 |    85 |    2 |
    | 12 | Chris |     3 |   100 |    1 |
    +----+-------+-------+-------+------+
    

    【讨论】:

    • ERROR 1064 (42000):您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以了解在 'rank FROM my_table a 附近使用的正确语法
    • @MaksymMoskvychev 是的 - 该请求专门针对旧版本的 mysql。随意调用“排名”任何你喜欢的东西。
    • 这太棒了!但我的猜测是我达到了 GROUP_CONCAT 的限制,因为它没有返回所有必要的排名。
    • @schwooples 是的,这可能会发生。您可以调整该限制,但最好切换回 @ 变量解决方案或 - 最重要的是 - 升级!
    • 我没有资格说,但我想这个话题被广泛讨论
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-21
    • 1970-01-01
    • 1970-01-01
    • 2017-09-01
    • 1970-01-01
    • 2010-12-04
    • 1970-01-01
    相关资源
    最近更新 更多