多项赛事积分榜(参赛人数任意)

时间:2019-05-20 20:23:57

标签: mysql ranking

假设您有一个多项目比赛,其中竞争对手可以任意次数尝试任何事件。 (很奇怪,我知道。)

如何为每个赛事争取出理想的球员最佳时间, 并分配一个位置? (1st 2nd 3rd ...)

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()之类的东西。这也将使成千上万的分数变差。

3 个答案:

答案 0 :(得分:0)

此查询可实现所需的输出:

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上工作。

答案 1 :(得分:0)

通过采用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

答案 2 :(得分:0)

例如:

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 |
+----+-------+-------+-------+------+