Турнирная таблица нескольких событий (с произвольным количеством заявок) - PullRequest
1 голос
/ 20 мая 2019

Предположим, у вас есть соревнование, состоящее из нескольких событий, где участники могут попробовать любое событие произвольное количество раз. (странно, я знаю.)

Как вытащить лучшее время желаемого игрока для каждого события, и назначить это место? (1-й, 2-й, 3-й ...)

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

Это сборка моего предыдущего вопроса: Турнирная таблица нескольких турниров

Я чувствую, что понимаю эту проблему намного лучше (спасибо!), Но я не могу преодолеть разрыв с этой версией проблемы.

У меня SQL 5.x, поэтому я не могу использовать такие вещи, как Rank (). Это также принесет много тысяч очков.

Ответы [ 3 ]

0 голосов
/ 21 мая 2019

Вы можете получить наивысший балл за событие путем агрегации по событию, взяв max().Для имитации dense_rank() вы можете использовать подзапрос, подсчитывающий баллы, превышающие или равные текущему баллу за событие.

Для конкретного участника (здесь Боб), который составляет:

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;

дБ <> скрипка

0 голосов
/ 21 мая 2019

Например:

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 |
+----+-------+-------+-------+------+
0 голосов
/ 21 мая 2019

Требуемый вывод можно получить с помощью этого запроса:

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.

...