My table contains information this way:
Player_ID | isWinner
where PlayerID is the ID of the player, and isWinner is a boolean (0 for lose, 1 for win).
Same Player_ID can be in multiple rows.
My goal is to make a query to get ALL the information from this table ordered by the players, from the highest win rate (%) to the lowest.
Data example:
(Player_ID | isWinner)
1 | 1
1 | 1
1 | 1
2 | 0
2 | 0
2 | 1
3 | 0
3 | 0
3 | 0
The query will order this data this way:
1 | 100% -- > player ID 1 has the highest win rate
2 | 33% -- > player ID 2 has the 2nd win rate
3 | 0% -- > player ID 3 has the lowest win rate
I probably have to group by player_id and somehow calculate the SUM of isWinner of each player, then divide it by the numebr of records.
Any ideas?
You can use avg() to find the average of total wins for each player, then multiple by 100 to give the percentage
select
player_id as pid,
avg(is_winner) * 100 as win_rate,
(
SELECT
count(player_id)
FROM
`34617596`
WHERE
is_winner = 1
AND player_id = pid
) AS total_wins
FROM
`34617596`
group by pid
order by win_rate desc
See fiddle: http://sqlfiddle.com/#!9/10f797/1
This query will return the average for each player:
select player_id, avg(isWinner) as avg_is_winner
from players
group by player_id
then you can join your table with this subquery:
select players.*
from
players inner join (
select player_id, avg(isWinner) as avg_is_winner
from players
group by player_id
) c on players.player_id = c.player_id
order by
avg_is_winner desc,
isWinner desc
Please see a fiddle here.
Related
I've got a leaderboard in a pvp shooter game where I want to display the top 20 players ordered by their kill / death ratio (total kills divided by their total deaths)
I have a kills table that tracks kills and looks something like:
| killer_id | killed_id | date |
| patrick | jim | 2021-03-01 |
| greyson | jim | 2021-03-02|
| jim | patrick | 2021-03-03|
I can get the total kills by doing something like:
SELECT COUNT(*) as total_kills
FROM kills
GROUP BY killer_id
ORDER BY total_kills DESC
LIMIT 20
And I can get the total deaths by doing something like:
SELECT COUNT(*) as total_deaths
FROM kills
GROUP BY killed_id
ORDER BY total_deaths DESC
LIMIT 20
However, I can't seem to group the query together so that I'm returning a list of the best ratios. It would look like:
| player_id | kill_death_ratio (total kills / total deaths) |
| patrick | 2.1 |
| jim | 1.0 |
| greyson | .9 |
Is this even possible in a single query?
Use this query:
SELECT killer_id player_id FROM kills UNION SELECT killed_id FROM kills
to get all the players in the table.
Then join it with LEFT joins to your queries:
SELECT p.player_id,
COALESCE(t1.total_kills, 0) / t2.total_deaths kill_death_ratio
FROM (SELECT killer_id player_id FROM kills UNION SELECT killed_id FROM kills) p
LEFT JOIN (
SELECT killer_id, COUNT(*) total_kills
FROM kills
GROUP BY killer_id
) t1 ON t1.killer_id = p.player_id LEFT JOIN (
SELECT killed_id, COUNT(*) total_deaths
FROM kills
GROUP BY killed_id
) t2 ON t2.killed_id = p.player_id
Or, without your queries:
SELECT player_id, SUM(killer) / SUM(killed) kill_death_ratio
FROM (
SELECT killer_id player_id, 1 killer, 0 killed
FROM kills
UNION ALL
SELECT killed_id, 0, 1
FROM kills
) t
GROUP BY player_id
See the demo.
Results (for your sample data):
player_id
kill_death_ratio
jim
0.5
patrick
1.0
greyson
null
Notice that you will get null for players that were never killed.
This is my table:
+--------+-------+--------+--------+
| player | points| score1 | score2 |
+--------+-------+--------+--------+
| 1 | 12 | 9 | 1 |
| 2 | 12 | 14 | 2 |
| 3 | 10 | 12 | 3 |
| 4 | 9 | 10 | 4 |
| 5 | 8 | 10 | 4 |
+--------+-------+--------+--------+
To get the second highest value, I used this query:
SELECT player,points FROM players
WHERE points= (SELECT DISTINCT(points) FROM players as p1
WHERE (SELECT COUNT(DISTINCT(points))=2 FROM players as p2
WHERE p1.points<= p2.points)) ORDER BY player
It works perfect. But now I want to get is with two conditions:
Condition1: points DESC
Condition2: (score1-score2) DESC
This query works fine to get the player with the second highest value (Checking points and score1):
SELECT player,points FROM players
WHERE points= (SELECT DISTINCT(points) FROM players as p1
WHERE (SELECT COUNT(DISTINCT(points))=2 FROM players as p2
WHERE p1.points<= p2.points))
AND
WHERE score1= (SELECT DISTINCT(score1) FROM players as p1
WHERE (SELECT COUNT(DISTINCT(score1))=2 FROM players as p2
WHERE p1.score1<= p2.score1))
ORDER BY player
How can I get the player with the second highest value using two conditions (points DESC AND (score1-score2) DESC)?
This query will do what you want. It JOINs players to itself, looking for all players in the second table who would rank higher than the player in the first table. In this case ranking is based first on points, then in case of equal points on the difference between score1 and score2. The second ranked player is the one who has one player with higher rank than they do:
SELECT p1.*
FROM players p1
JOIN players p2 ON p2.points > p1.points
OR p2.points = p1.points AND (p2.score1 - p2.score2) > (p1.score1 - p1.score2)
GROUP BY p1.player
HAVING COUNT(p2.player) = 1
Output:
player points score1 score2
1 12 9 1
You can also write your original query in a similar fashion, using p2.player < p1.player as a condition to separate players with equal points (simulating the effect of your ORDER BY player):
SELECT p1.*
FROM players p1
JOIN players p2 ON p2.points > p1.points
OR p2.points = p1.points AND p2.player < p1.player
GROUP BY p1.player
HAVING COUNT(p2.player) = 1
Output:
player points score1 score2
2 12 14 2
Demo on dbfiddle
In my table "game_info" I have
ID | player_1 | player_2 | score
--------------------------------
1 | John | Rick | 100
2 | Joe | John | 80
3 | Bob | Rick | 210
I want to sum total score for every player no matter they are player_1 or player_2 and order by score.
What I expect is:
Name | Score
------------
Rick | 310
Bob | 210
John | 180
Joe | 80
I have tried to JOIN and UNION, but I can't get it right.
Is there any way to do this in sql or i have to redesign my table?
Thank You!
You can do this with union all and group by:
select player, sum(score)
from ((select player1 as player, score from game_info
) union all
(select player2 as player, score from game_info
)
) p
group by player
order by sum(score) desc;
SELECT player, SUM(score)
FROM
(SELECT player_1 AS player, score
FROM t
UNION ALL
SELECT player_2 as player, score
FROM t) sub
GROUP BY player
You have to union the player 1 results with the player 2 results, so that you have one result with just player and score. Of course, the scores will be listed twice in this view, one for each player. In my query, the result is called sub. Based on sub, you can group by player and sum their scores.
I have this table:
Username | score | gameid
SimJoo | 14 | 1
SimJoo | 20 | 1
SimJoo | 23 | 2
Master | 32 | 1
Master | 25 | 2
Master | 9 | 2
For every player, I need the sum of the highest score of the player at every gameid divided by the highest score gotten for that gameid. This, for any number of different players, scores and gameids.
The result of above example table would be:
Username | total score
Master | 2.000
SimJoo | 1.545
For clarity:
The calculation for the player master is (32/32)+(25/25) =2.000
The calculation for the player SimJoo is (20/32)+(23/25) = 1.545
SELECT Username, SUM((SELECT MAX(score) WHERE Username=? AND gameid=?)/(SELECT MAX(Score) WHERE gameid=?)) AS total_score
GROUP BY Username
ORDER BY total_score DESC
The first subquery returns max score of user per game. The second one - max for games
select Username, sum(umax/gmax)
from
(select Username, gameid, max(score) umax
from t
group by Username, gameid
) u
left join
(select gameid, max(score) gmax
from t
group by gameid
) g
on u.gameid = g.gameid
group by Username
example on sqlfiddle
From what you describe, this requires two aggregations and a join:
select t.username, sum(t.score / g.maxscore)
from t join
(select gameid, max(score) as maxscore
from t
group by gameid
) g
on t.gameid = g.gameid
group by t.username;
How can I get corresponding columns from a max query in mysql? I want find out how many wins a player has. I will find that out by doing a count of the number of games that player has won. The will be done by selecting the max value per game and resulting player_id. However I am not sure how to get the corresponding player_id.
I have
id | game_id | player_id | score
1 | 1 | 1 | 254
2 | 1 | 2 | 194
3 | 2 | 1 | 432
4 | 2 | 2 | 298
This query should get what you need:
SELECT
player_id, game_id, score
FROM
(
SELECT game_id,MAX(score) AS MaxScore
FROM games
GROUP BY game_id
) AS Winners
JOIN games
ON (games.game_id = Winners.game_id AND games.score = Winners.MaxScore)
It assumes that a tie is a win for both players.
SQLFiddle
If you want to get just the player and their number of wins, you can use this query:
SELECT
player_id, COUNT(*) AS wins
FROM
(
SELECT game_id,MAX(score) AS MaxScore
FROM games
GROUP BY game_id
) AS Winners
JOIN games
ON (games.game_id = Winners.game_id AND games.score = Winners.MaxScore)
WHERE player_id = {player_id}
GROUP BY player_id
Just replace {player_id} with the player you're looking for and wins is their number of wins or ties.