tags:

views:

80

answers:

4

hi I have the following table:

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;

That's a score table the stores the user_id and game_id and score of each game. there are trophies for the first 3 places of each game. I have a user_id and I would like to check if that specific user got any trophies from any of the games.

Can I somehow create this query without creating a temporary table ?

+1  A: 
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;
finnw
i would like to get the first 3 places of each game. this query will provide the first 3 places of the all table.
ufk
I think someone just edited it to address that problem.
David Grayson
A: 

Didn´t test it, but should work fine:

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

There you can check the position field to see if it´s between 1 and 3.

Seb
That won't work, because the @position variable is only calculated for rows that are in your result set, and since you have "WHERE user_id=...", only that user's scores will be in your result set, and the position column will only tell you the position of the user's scores in that list.
David Grayson
+1  A: 

A clearer way to do it, and semitested.

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

WHERE acount < 3

le dorfier
The asker said "I have a user_id and I would like to check...", so I think he really wants a list of games and trophies for that user. But it looks like you're supplying him a list of user_ids.
David Grayson
+1  A: 
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;

This query returns the rows for all winning games. Although ties are included; if the scores are 10,16,16,16,18 then there are four winners: 16,16,16,18. I'm not sure how you handle that. You need some way to resolve ties in the join condition.

For example, if ties are resolved by the earlier game winning, then you could modify the query this way:

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;

You could also use the timestamp column to resolve ties, if you can depend on it being UNIQUE.

However, MySQL tends to create a temporary table for this kind of query anyway. Here's the output of EXPLAIN for this query:

+----+-------------+-------+------+---------------+------+---------+------+------+---------------------------------+
| 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 |                                 | 
+----+-------------+-------+------+---------------+------+---------+------+------+---------------------------------+
Bill Karwin
Yeah, this looks good. You just need to add "WHERE s1.user_id='blah'" because the asker already has a specific user_id he wants, and also that would probably make the query a lot faster for large data sets.
David Grayson