MySQL update table only with the highest values of another table

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



MySQL update table only with the highest values of another table



For a game site.

All games are recorded if the player's score is greater than his old score



Table of all players (over 10,000 players)


CREATE TABLE games (
PlayerID INT UNSIGNED,
Date TIMESTAMP(12),
Score BIGINT UNSIGNED DEFAULT 0,
#...other data
);



Once a month, I do an update of the table of records best. And after I erase all games.


best


games



Table of best players (top 50)


CREATE TABLE best (
#...same as games, without final other data
PlayerID INT UNSIGNED,
Date TIMESTAMP(12),
Score BIGINT UNSIGNED DEFAULT 0
);



So I add the 50 best players of the table games in to the table best:


games


best


INSERT INTO best (PlayerID, Date, Score)
SELECT PlayerID, Date, Score FROM games ORDER BY Score DESC LIMIT 50;



And after (and this is where I have a problem) I try to keep in best only the best 50. At this point best contains 100 lines.


best


best



What I have to do:


PlayerID


Score



->


+----------+---------+
| PlayerID | Score |
+----------+---------+
| 25 | 20000 | New
| 25 | 25000 | Old best
| 40 | 10000 | Old best
| 57 | 80000 | New best
| 57 | 45000 | Old
| 80 | 35000 | New best
+----------+---------+



I have to retain in the end only 50 lines (the ones with "best" in my example).

I tried many things, but I have not succeeded in achieve the expected result.



I am using PHP, so if it is possible to do it simply with a intermediare storage in an array, that's fine too.
The speed is not a priority because it is an operation that is done only once a month.





Couldn't you query on the players' table to find best ones instead of creating a new table?
– Phate01
Feb 10 '15 at 14:58





@Phate01 Yes I do that for a month. But at the end of the month I clear the game table. Everything is reset to zero. I just keep track of the top 50 of all time ...
– Croises
Feb 10 '15 at 15:00






Ok so you can merge your selection with the best table using UNION
– Phate01
Feb 10 '15 at 15:02






@Phate01 And in the end replace the entire contents with the result? And erase the last lines to keep only 50. I do not know which way to turn the request with the tests better Scores and PlayerID equality.
– Croises
Feb 10 '15 at 15:09





Umm.. why not truncate best before running the insert?
– ethrbunny
Feb 10 '15 at 15:20




2 Answers
2



The following SQL returns the top 50 scores:


SELECT `PlayerId`, max(`Score`) MaxScore
FROM (
SELECT `PlayerId`, `Date`, `Score` FROM games
UNION
SELECT `PlayerId`, `Date`, `Score` FROM best
) t
GROUP BY `PlayerId`
ORDER BY `MaxScore` DESC
LIMIT 50



You can use the result to overwrite the table best. For this you also need the corresponding Date field, which is missing so far. The next SQL will also return a maxDate field which corresponds to the highscore.


best


Date


maxDate


SELECT t2.`PlayerId`, max(t2.`Date`) maxDate, top.`MaxScore`
FROM
(
SELECT `PlayerId`, max(`Score`) MaxScore
FROM (
SELECT `PlayerId`, `Date`, `Score` FROM games
UNION
SELECT `PlayerId`, `Date`, `Score` FROM best
) t1
GROUP BY `PlayerId`
ORDER BY `MaxScore` DESC
LIMIT 50
) top
LEFT JOIN (
SELECT `PlayerId`, `Date`, `Score` FROM games
UNION
SELECT `PlayerId`, `Date`, `Score` FROM best
) t2 ON t2.`PlayerId` = top.`PlayerId` AND t2.`Score` = top.`MaxScore`
GROUP BY t2.`PlayerId`
ORDER BY top.`MaxScore` DESC



To transfer the new top 50 highscores into the best table you can use a temporary table like tmp_best. Insert the top scores into the empty table tmp_best with (you have to insert your select query from above):


best


tmp_best


tmp_best


INSERT INTO tmp_best (`PlayerId`, `Date`, `Score`)
SELECT ...



After this the best table can be emptied and then you can copy the rows from tmp_best into best.


best


tmp_best


best



Here is an alternative solution, which has simplified SQL. The difference
to the solution above is the using of a temporary table tmp_all at the beginning for the unified data. Before using the following SQL you have to create tmp_all, which can be a copy of the structure of games or best.


tmp_all


tmp_all


games


best


DELETE FROM tmp_all;

INSERT INTO tmp_all
SELECT `PlayerId`, `Date`, `Score` FROM games
UNION
SELECT `PlayerId`, `Date`, `Score` FROM best
;

DELETE FROM best;

INSERT INTO best (`PlayerId`, `Date`, `Score`)
SELECT t2.`PlayerId`, max(t2.`Date`) maxDate, top.`MaxScore`
FROM
(
SELECT `PlayerId`, max(`Score`) MaxScore
FROM tmp_all t1
GROUP BY `PlayerId`
ORDER BY `MaxScore` DESC
LIMIT 50
) top
LEFT JOIN tmp_all t2 ON t2.`PlayerId` = top.`PlayerId` AND t2.`Score` = top.`MaxScore`
GROUP BY t2.`PlayerId`
ORDER BY top.`MaxScore` DESC
;





Thank you. I do not have the ability to immediately test. May I ask how I can overwrite the table best in the same query.
– Croises
Feb 10 '15 at 15:43



best





@Croises I would use a temporary table. After creating a temporary table with the new values you can empty the best table and copy the rows from the temporary table.
– Henrik
Feb 10 '15 at 15:51


best





I have to test. But I think I can use a simpler solution, such as @Phate01because I have only one entry per player. I only records the highest score per player during the month. And in this case, I do not have to use max().But I must get the same result simply with sorts (?)
– Croises
Feb 10 '15 at 16:16


max()





@Croises As soon as you union the selects you can have two entries for one user, from the table best and the table games.
– Henrik
Feb 10 '15 at 16:27


best


games





Yes, that's exactly what I was thinking just now.
– Croises
Feb 10 '15 at 16:31


SELECT PlayerID, Date, Score FROM games ORDER BY Score DESC LIMIT 50
UNION
SELECT PlayerID, Date, Score FROM best



Here you'll get the best 50 players all-time. Then, as suggested by @ethrbunny, erase the best table and populate it again with the above query. You can use a TEMPORARY TABLE



UNION guarantees you that you'll get no duplicated player





Thank you. I can't erase the best table before if you use it in your query ?
– Croises
Feb 10 '15 at 15:45


best





Since I haven't tested it, try first the selection to see if it works. Then you can simply drop it with DROP TABLE and then recreate it with CREATE TABLE
– Phate01
Feb 10 '15 at 15:51



DROP TABLE


CREATE TABLE





@Croises If you empty your table before using it to select your data, there will be no data any more!
– Henrik
Feb 10 '15 at 15:55





This hadn't crossed my mind at all :D
– Phate01
Feb 10 '15 at 15:56





"UNION guarantees you that you'll get no duplicated player" - this is not true.
– Henrik
Feb 10 '15 at 16:27






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard