Как получить 3 первых места каждой игры из таблицы результатов в MySQL? - PullRequest
1 голос
/ 21 марта 2009

У меня есть следующая таблица:

CREATE TABLE `score` (  
    `score_id` int(10) unsigned NOT NULL auto_increment,  
    `user_id` int(10) unsigned NOT NULL,  
    `game_id` int(10) unsigned NOT NULL,  
    `thescore` bigint(20) unsigned NOT NULL,  
    `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP,  
    PRIMARY KEY  (`score_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;  

Это таблица оценок, в которой хранятся user_id и game_id, а также оценка каждой игры. Есть трофеи за первые 3 места каждой игры. У меня есть user_id, и я хотел бы проверить, получил ли этот конкретный пользователь какие-либо трофеи из любой из игр.

Можно ли как-нибудь создать этот запрос, не создавая временную таблицу?

Ответы [ 4 ]

1 голос
/ 21 марта 2009
SELECT s1.*
FROM score s1 LEFT OUTER JOIN score s2 
 ON (s1.game_id = s2.game_id AND s1.thescore < s2.thescore)
GROUP BY s1.score_id
HAVING COUNT(*) < 3;

Этот запрос возвращает строки для всех выигрышных игр. Хотя галстуки включены; если счет 10,16,16,16,18, то четыре победителя: 16,16,16,18. Я не уверен, как вы справляетесь с этим. Вам нужен какой-то способ разрешения связей в условии соединения.

Например, если связи разрешены победой в более ранней игре, вы можете изменить запрос следующим образом:

SELECT s1.*
FROM score s1 LEFT OUTER JOIN score s2 
 ON (s1.game_id = s2.game_id AND (s1.thescore < s2.thescore
     OR s1.thescore = s2.thescore AND s1.score_id < s2.score_id))
GROUP BY s1.score_id
HAVING COUNT(*) < 3;

Вы также можете использовать столбец timestamp для разрешения связей, если вы можете полагаться на то, что UNIQUE.

Однако MySQL в любом случае стремится создать временную таблицу для этого типа запроса. Вот вывод EXPLAIN для этого запроса:

+----+-------------+-------+------+---------------+------+---------+------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                           |
+----+-------------+-------+------+---------------+------+---------+------+------+---------------------------------+
|  1 | SIMPLE      | s1    | ALL  | NULL          | NULL | NULL    | NULL |    9 | Using temporary; Using filesort | 
|  1 | SIMPLE      | s2    | ALL  | PRIMARY       | NULL | NULL    | NULL |    9 |                                 | 
+----+-------------+-------+------+---------------+------+---------+------+------+---------------------------------+
1 голос
/ 21 марта 2009

Более ясный способ сделать это и semesested.

SELECT DISTINCT user_id
FROM
(
    select s.user_id, s.game_id, s.thescore,
    (SELECT count(1)
    from scores
    where game_id = s.game_id
        AND thescore > s.thescore  
    ) AS acount FROM scores s
) AS a

ГДЕ СЧЕТ <3 </p>

1 голос
/ 21 марта 2009
SELECT game_id, user_id
FROM score score1  
WHERE (SELECT COUNT(*) FROM score score2  
       WHERE score1.game_id = score2.game_id AND score2.thescore > score1.thescore) < 3   
ORDER BY game_id ASC, thescore DESC;
0 голосов
/ 21 марта 2009

Не проверял, но должен работать нормально:

SELECT
  *,
  @position := @position + 1 AS position
FROM
  score
  JOIN (SELECT @position := 0) p
WHERE
  user_id = <INSERT_USER_ID>
  AND game_id = <INSERT_GAME_ID>
ORDER BY
  the_score

Здесь вы можете проверить поле position , чтобы увидеть, находится ли оно между 1 и 3.

...