MySQL: Total count of points based on weekly vote - mysql

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

Related

How do i combine 3 queries into 1

I have 2 tables:
Battles
--battleId(primary)--gameId(foreign)--endTime
BattleParticipants
--battleParticipantId(primary)--userId(foreign)--someNumerical--score--battleId(foreign)
Given userId, i want to get only ended battle data for each battle user participated in with additional player rank information and total number of player participated in battle information.Ended battle means battles only with endTime smaller than current_time
returned battle data should include:
battleId:
endTime:
gameId:
score:
someNumerical:
rankOfPlayerInBattle:
totalNumberOfPlayersParticipatedInBattle:
for each battle player participated.
With below query i can get battleId,endTime,gameId,score,someNumerical as i want:
SELECT b.battleId,b.endTime,b.gameId,bp.score,bp.someNumerical FROM battles b JOIN battleparticipants bp ON b.battleId=bp.battleId WHERE bp.userId="someuserid" AND b.endTime<CURRENT_TIMESTAMP
Given battleId and userId this query returns me rank of user in that battle:
SET #i=0;
SELECT battleId, userId,score, #i:=#i+1 AS myRank
FROM battleparticipants WHERE battleId="asd1234" AND userId="someuserid"
ORDER BY score DESC
Given battleId this query gives me total number of players participated in that battle:
SELECT COUNT(*) FROM battleparticipants WHERE battleId="asd1234"
So given those seperated queries how do i retrieve data i want in one query ? (i dont really need to use above queries i just gave them as example since they get datas i want seperately)
i cant add fiddle because for some reason create code is throwing error. for now i add pictures of tables and data:
Battles table:
BattleParticipants table:
Below query wrong result:
SELECT b.battleId,b.endTime,b.gameId,bp.score,bp.someNumerical , RANK()OVER(PARITITON BY b.battleId, bp.userId order by score desc) rankOfPlayerInBattle , BP_C.CNT totalNumberOfPlayersParticipatedInBattle
FROM battles b
JOIN battleparticipants bp ON b.battleId=bp.battleId
JOIN (SELECT battleId , COUNT(*) CNT FROM battleparticipants GROUP BY battleId) BP_C ON BP_C.battleId=bp.battleId
WHERE bp.userId="someuserid" AND b.endTime<CURRENT_TIMESTAMP
You can use above SQL.

How do you SUM values based on a MIN date?

Working on an exercise for school trying to calculate the number of points scored by a basketball player ONLY during their first game.
So if I have a table that reports lots of games (Separate rows for 1st and 2nd half) that looks like this:
Game Date Player Half Points
1990-01-01 Mike 1 10
1990-01-01 Mike 2 10
1990-01-03 Mike 1 5
1990-01-03 Ben 2 8
1990-01-05 Kelly 1 4
1990-01-05 Kelly 2 4
1990-01-07 Kelly 1 10
And I want it to end up like this:
Game Date Player Points
1990-01-01 Mike 20
1990-01-03 Ben 8
1990-01-05 Kelly 8
How would I do this?
I have been trying to use the code:
SELECT min(game_Date), player, sum(points);
But it keeps counting points for ALL games, not just points scored during the 1st game, of which there can be one record for the first half and one record for the second.
First you need to find the players' first games, like this
select player, min(game_date) as firstGameDate
from yourtable
group by player
and then get the points in that game by joining to the table again
select yourtable.player, firstgame.firstGameDate, sum(points) as firstGamePoints
from yourtable
inner join
(
select player, min(game_date) as firstGameDate
from yourtable
group by player
) firstgame
on yourtable.player = firstgame.player
and yourtable.game_date = firstgame.firstgameDate
group by yourtable.player, firstgame.firstgameDate
Some varieties of SQL allow you to use ranking functions which could eliminate the need to join to the table itself, but this will work in all varieties.
You have to use your logic. First you have to only grab the first game for each player (inner query). Then from there, you count the points
SELECT t.game_date, t.player, SUM(t.points)
FROM some_table t
JOIN (
SELECT player, MIN(game_date) AS min_date
FROM some_table
GROUP BY player
) a ON a.plyer = t.player AND a.min_date = t.game_date
GROUP BY t.player, t.game_date
Sub query approach of getting the result is given below
Filter the results only getting Player's first games.
Select min(Game_Date),Player from
basketball group by Player;
Use the results from first query to find each player's sum of scores in first game.
Select Game_Date, Player,sum(points) as first_play_points from
basketball where (Game_date,Player) in (Select min(Game_Date),Player
from basketball group by Player) group by Game_Date, Player;
Working fiddle can be found here

MySQL rating table optimization

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?

Sum values across multiple tables

I'm having trouble trying to sum a field GROUPED BY a common user ID from TWO DIFFERENT tables.
To give you a little more info... I am trying to track player performances by date (i.e.: most points scored on ALL Nov. 14's). The database is split, one table for regular season games and one table for playoffs. So, for example, a player may have played a regular season game on May 3, 2001....but a playoff game on May 3, 2005.
So, I'm trying to build a view with the sums of every player on all dates.
What I have for a single table:
SELECT PlayerId,sum(Points) as TOT_PTS
FROM RS_games
WHERE DAY(Date)=$cur_day
AND MONTH(Date)=$cur_month
GROUP BY PlayerId
...but I can't figure how I could sum the values of each player across two tables without creating a third view as a "stepping stone".
Any ideas?
If you want the results by (DAY-MONTH) you can do:
SELECT playerID,
CONCAT (DAY(DATE), '-', MONTH(DATE)) AS DAY_MONTH,
SUM(points) AS Total_Points
FROM (
SELECT playerID, DATE, points
FROM rs_games
UNION ALL
SELECT playerID, DATE, points
FROM po_games
) a
GROUP BY 1, 2
sqlfiddle demo
This way, you would end up with a result with every playerId,dd-mm, and the sum of points that were scored in that specific day across the years.
Just to lay out what I was saying:
select
ALL_players.PlayerID as PlayerID
COALESCE(reg.Points, 0) + COALESCE(po.Points, 0) as Points
from
ALL_players
left join
(select PlayerID, DATE(Date) as Date, sum(Points) as Points
from RS_games
WHERE DAY(Date)=$cur_day AND MONTH(Date)=$cur_month
group by PlayerID) as reg
on reg.PlayerID = ALL_players.PlayerID
left join
(select PlayerID, DATE(Date) as Date, sum(Points) as Points
from PO_games group by DATE(Date), PlayerID
WHERE DAY(Date)=$cur_day AND MONTH(Date)=$cur_month
group by PlayerID) as po
on po.PlayerID = ALL_players.PlayerID
EDIT: Looking again at requirements this will need either a full outer join or some adjustment... adjusting (should be working now)

Multiple counts and math operator in MySQL

I have two tables, one contains the results of a game (which game played and number of games won), the second lists how many selections they have gotten right for a given game (i.e % correct).
I need to make a single query to calculate the percentage of times a user has won for each game. Each user may have played a different number of games.
I've tried to do this using COUNT, but if I group the count function to determine the number of times a user has player I can then not get the total number of times the user has won. See fiddle..
http://sqlfiddle.com/#!2/defc3/1
UPDATE result, games_played
SET result.precentage_correct =
(
**SELECT (COUNT(gp.user_id)/COUNT(gp.user_id)*100)**
FROM games_played as gp
WHERE result.user_id = gp.user_id
AND gp.winner != 'n'
AND gp.game = 1
GROUP BY gp.user_id
)
WHERE games_played.user_id = result.user_id
So, somehow I need to have two different COUNT functions with a math operator
You could simply combine two queries, one that selects only winning records, and another that selects all queries. Once you have these two counts, you can select from them to calculate the ratio.
SELECT user_id, 100*SUM(n_win)/SUM(n_total) AS pct_win FROM
(SELECT user_id, COUNT(user_id) AS n_win,
NULL AS n_total
FROM games_played
WHERE winner != 'n'
AND game = 1
GROUP BY user_id
UNION SELECT user_id, NULL AS n_win,
COUNT(user_id) AS n_total
FROM games_played
WHERE game = 1
GROUP BY user_id
) AS counts
GROUP BY counts.user_id;
Note that to combine the queries, one field of either n_win or n_total will be NULL in each subquery. The query will yield:
USER_ID PCT_WIN
1 50
2 66.6667
3 50
4 100
The union of the two subqueries will have two records for each user, one record for which n_win is known, the other record will have the value for n_total. For the first two users, it would look like
USER_ID N_WIN N_TOTAL
1 1 NULL
2 2 NULL
1 NULL 2
2 NULL 3
The outer query selects from that union the user_id and n_win / n_total grouped by user_id, thus yielding 50.0% and 66.6%. I am using SUM because it allows me to collect the non-NULL value for each column for each user.