I have a RatingTable in MySQL:
player_id INT, game_type INT, rating INT
There are 5 different game types (e.g. chess, checks, go, etc.)
Higher rating in game is better
I want to get top 10 player_id with highest TOTAL rating. Total rating = sum of all ratings for all game types.
I can solve it like this:
SELECT player_id, SUM(rating) as TotalRating
FROM RatingTable
GROUP BY player_id
ORDER BY TotalRating DESC
LIMIT 10;
But my concern is that it will take to much memory&cpu if there're 10 million players with 5 different game types. It will sum all ratings for all 10mln players and then sort it. How can I optimize it?
Related
I have a database with names and their scores and I'd like to insert into the table the rank according to the score. My database looks a bit like this:
phpmyadmin database
I would like to make it so when the score is higher than a rank the ranks change in the database. So if there were a player 1 with 500 points and a player 2 with 1500 points, the code would insert the rank into the rank column corresponding with the player's name.
Like this:
Rank
Name
Score
1
Player2
1500
2
Player1
500
Don't store the RANK in the database calculate it on the fly when you read the data using the RANK() function.
SELECT
Player,
Score,
RANK() OVER(ORDER BY Score DESC) AS 'RANK'
FROM
PlayerScore
ORDER BY
Score DESC
If you can have tied scores you can use DENSE_RANK(). This would give you ranks of 1,2,2,3. RANK would just give you 1,2,2,4
I have a MySQL table of companies, each company has a popularity score, (the higher the integer, the more popular the company). I'm wanting to select 10 random companies then order by most popular to least. However, I want to favor companies that have a higher popularity score, but not totally exclude companies with a lower popularity score. So in other words, I'm looking for some kind of tolerance system that favors more popular companies.
This is the solution I've come up with so far:
SELECT c.company FROM (
(
SELECT company, popularity FROM companies
WHERE popularity >= (
SELECT ROUND(AVG(popularity) * 0.8) FROM companies
)
ORDER BY RAND() LIMIT 5
)
UNION
(
SELECT company, popularity FROM companies
WHERE popularity >= (
SELECT ROUND(AVG(popularity) * 0.6) FROM companies
)
AND popularity < (
SELECT ROUND(AVG(popularity) * 0.8) FROM companies
)
ORDER BY RAND() LIMIT 3
)
UNION
(
SELECT company, popularity FROM companies
WHERE popularity < (
SELECT ROUND(AVG(popularity) * 0.6) FROM companies
)
ORDER BY RAND() LIMIT 2
)
) AS c ORDER BY c.popularity DESC;
What I'm doing is combining three different selects.
The first is selecting 5 random companies whose popularity score is
equal to or greater than the top 20% of the average popularity score.
The second is selecting 3 random companies whose popularity score is
equal to or greater than the top 40% of the average popularity score,
but lower than the top 20%.
And finally the third is selecting 2 random companies whose
popularity score is lower than the top 40% of the average popularity
score.
I've simplified the SQL a bit, I'm also selecting logo locations, the company URL and any affiliate codes. The goal is to use the SQL on a website to basically say "here are just some of the brands we stock".
This solution works, but it just seems a bit clunky and over-engineered. Can anybody suggest a more efficient way of including a tolerance system?
I'm trying to make a query and I already searched for an answer on stackof but didn't find one matching my needs.
I have a table named player in which there are two columns, "nickname" and "score".
I use this query to get the top 5 players:
SELECT nickname, score
FROM player
ORDER BY score DESC LIMIT 5;
and I got this as the answer:
nickname - score:
zod - 30
ciao - 20
jiji - 20
mayina - 20
jon - 0.
Now, I'd like to have the rank of a single player, let's say "jiji" and get 3 as a result, because it's the third result in the list.
I tried many queries like
SELECT COUNT(*) AS rank
FROM player
WHERE score >= (SELECT score FROM player WHERE nickname = 'jiji')
but they always return 4 for "jiji" or "ciao", which is the rank of the last player who gets 20 as score in that table.
How can I get to have 3 for "jiji", instead? Thank you very much.
Try this:
SET #rank=0;
SELECT *
FROM (SELECT #rank:=#rank+1, nickname, score
FROM player
ORDER BY score
DESC) AS t
WHERE t.nickname = 'jiji';
Correct comment about this not being stable in case of score ties. To make it stable, we can change the sorting to be based on score and then nickname:
SELECT *
FROM (SELECT #rank:=#rank+1, nickname, score
FROM player
ORDER BY score, nickname
DESC) AS t
WHERE t.nickname = 'jiji';
Using commonly used definitions, the rank for jiji would be:
SELECT count(*) + 1 AS rank
FROM player
WHERE score > (SELECT score FROM player WHERE nickname = 'jiji');
This returns "2", because there are ties when score = 30.
If you want the rank to be stable and different for each row, you need an additional key. An obvious key (in this case) is nickname:
SELECT count(*) AS rank
FROM player p CROSS JOIN
(SELECT score FROM player WHERE nickname = 'jiji') s
WHERE p.score > s.score or
(p.score = s.score and p.nickname <= 'jiji');
How can i store a highscore efficiently in database?
I have a table player_score with two columns player_id (primary key), score (integer value).
Now i want the position of a player in the highscore and i created the following query
SELECT player_score.player_id,
(SELECT COUNT(*) FROM player_score ps WHERE ps.score >= player_score.score) AS position
FROM player_score
WHERE player_score.player_id = 19
I think this is very inefficiently have you any other ideas? It is also conceivable to use elasticsearch or any other technology to store this data efficiently.
You can use the following query to get the exact position of a user in the high scores list:
SELECT COUNT(*)+1 AS pos
FROM (SELECT *
FROM player_score
ORDER BY score DESC) AS ordered_scores, player_score
WHERE player_score.player_id=3 AND player_score.score < ordered_scores.score;
So I have this weekly vote for best players of the game. Users can vote for 3 best players, 1st gets 3 points, 2nd 2p and 3rd 1p. So it would be easy just to count all votes of all games and figure out who is the best. But the number of votes per game can be significantly different.
For example:
Vote1:
1st: 100 of total 500 votes -> 20%
Vote2:
1st: 40 of total 100 votes -> 40%
So I would want to count all votes of all games so that every game is equally important. Basically I think I just need to count percentage of votes per game and sum then together. But how can I achieve this easily?
My table is like this:
id, game_id, player3, player2, player1
Here's one way using UNION ALL to put all your players together (if I'm understanding your question correctly) -- not completely sure of your desired results, so have just left like this for now.
select player_id, sum(points)
from (
select player3 player_id, 3 points
from games
union all
select player2, 2
from games
union all
select player1, 1
from games
) t
group by player_id
SQL Fiddle Demo