calculating player statistics from database - mysql

i have the following tables.
i want to fetch all the player statistics record from the given tables, the records of individual player includes.
Player Name
Position
Total Number of games played
Number of goals scored
Total number of assist for goals.
Total Points (total goals + total assist = total points).
after trying i came up with this query
SELECT SQL_CALC_FOUND_ROWS
CONCAT(u.first_name, ' ', u.last_name) as player_name,
p.position,
COUNT(g.id)
FROM
gce_player p
LEFT JOIN
gce_user u ON(u.id = p.user_id)
LEFT JOIN
gce_game_team_lineup gtl ON(gtl.player_id = p.id)
LEFT JOIN
gce_game_team gt ON(gt.id = gtl.game_team_id)
LEFT JOIN
gce_game_goal gg ON(gg.player_id = p.id)
LEFT JOIN
gce_game g ON(g.id = gt.game_id)
GROUP BY p.id
ORDER BY p.id asc
the above query returns me proper record till total number of games played, i am facing issue fetching the proper records after this, ill appreciate any kind of help on this.
here is the link to sqlfiddle if you want to look at the schema, i have added some test data too.
thank you.
UPDATE :
here are few of the rules to remember.
Number of goals scored = total number of goals scored by a player. for example if in gce_game_goal table there are 10 rows which have
the value of player_id as 4 it means the player have scored 10 goals
and i need to fetch this record for individual player, and
likewise if there are 7 rows in which player_id have value of 3 this
means player with id 3 have scored 7 goals and likewise.
Total number of assist for goals = total number of assist given to a goalie by a player (assist is like a pass in football). i need to
calculate total number of assist or pass that was done by a user.
for each goal there will be two assist, and each assist are players
who pass the ball to a golaie. i want to count the number of passes
or assist given by a player. for example if in gce_game_goal
table there are 8 rows or records that have the value of 3 in either
assis1_id or assist2_id column, this means player with id 3 have
scored 8 assist in total
.
kindly let me know if you still have any doubts/question, ill try to improve my question
Thanks

The problem that you are facing is caused by aggregating along multiple different dimensions of the data (say by game and by goal). This results in a cross product for each player.
A fairly general solution is to do aggregations in the from clause, along each dimension. Each variable (or perhaps a few variables) comes from a different aggregation:
select u.last_name, u.first_name, p.position,
pg.goals, pg.assists, (pg.goals + pg.assists) as TotalPoints
from gce_player p join
gce_user u
on p.user_id = u.id left outer join
(select player_id, SUM(goal) as goals, SUM(assist) as assists
from ((select player_id, 1 as goal, 0 as assist
from gce_game_goal
) union all
(select assist1_id, 0 as goal, 1 as assist
from gce_game_goal
) union all
(select assist2_id, 0 as goal, 1 as assist
from gce_game_goal
)
) t
group by player_id
) pg
on pg.player_id = p.id left outer join
(select gtl.player_id, count(*) as NumTeams
from gce_game_team_lineup gtl join
gce_game_team gt
on gtl.id = gt.team_id
) g
on g.player_id = p.id

Try this
SELECT
CONCAT(u.first_name, ' ', u.last_name) as player_name,
count(g.id) as Goals,
(select
count(*)
from
gce_game_goal
where
assist1_id = p.player_id)
+(select
count(*)
from
gce_game_goal
where
assist2_id = p.player_id) as Assists,
count(g.id)
+ (select
count(*)
from
gce_game_goal
where
assist1_id = p.player_id)
+ (select
count(*)
from
gce_game_goal
where
assist2_id = p.player_id) as Total
FROM
gce_player as p
LEFT JOIN
gce_game_goal as g ON p.id = g.player_id
LEFT JOIN
gce_user u ON(u.id =p.user_id)
GROUP BY p.player_id

Related

top 10 scorers by season

How I can get top 10 scorers by seasons.
So it shows last season top 10 scorers...
I've tryed left join into table, but it goes broken showing 2 player and counts all goals to first player.
My sqlfiddle:
http://sqlfiddle.com/#!9/b5d0a78/1
You got it almost right.
You want to group match_goals by player ID (match_player_id), but then you should not select goal_minute or any other per goal data.
After grouping by player, then you can create a column for COUNT(match_player_id) this will give you the number of goals, you can also use this column to order the results.
Your joins and conditions are correct I think.
EDIT
I think your schema needs a few tweaks: check this http://sqlfiddle.com/#!9/f5a75b/2
Basically create direct relations in the match_players and match_goals to the other tables.
I think the query you want looks like this:
SELECT p.*, count(*) as num_goals
FROM match_goals g INNER JOIN
match_players p
ON g.match_player_id = p.id INNER JOIN
matches m
ON m.id = p.match_id
WHERE p.is_deleted = 0 AND
g.is_own_goal = 0 AND
m.seasion_id = <last season id>
GROUP BY p.id
ORDER BY num_goals DESC
LIMIT 10;
Note that the teams table is not needed. The SELECT p.* is allowed because p.id (the GROUP BY key) is unique.

SQL meet conditions based on max value

I have to get the player_id and the game_code of the game the user played the most. For each player list the game_code he played the most (not all games he played)
Rules: player_id is unique, and the player could have played multiple games (I want to find out which game he played the most).
I tried with max but I just got lost in trying out.
Here is the fiddle: http://sqlfiddle.com/#!9/0cf0f/2
I believe you want this
SELECT t.player_id, t.game_code, t.minutes_played
FROM (
SELECT player_id, MAX(minutes_played) as maxi
FROM play_table
WHERE game_code in ('123','124','125','126','129')
GROUP BY player_id
) as m
INNER JOIN play_table as t
ON t.player_id = m.player_id and
t.minutes_played = m.maxi
sqlfiddle demo
The other answer is on the right track, but you need to group by player_id in the subquery, assuming you want all of them:
SELECT m.player_id, pt.game_code, pt.minutes_played
FROM (
SELECT player_id, max(minutes_played) as maxi
FROM play_table
GROUP BY player_id
) as m
INNER JOIN play_table pt
ON m.player_id = pt.player_id
AND pt.minutes_played = m.maxi;

COUNT() rows value in an INNER JOIN

I need to count the amount of games a player has played by counting the number of times his player ID appears on another table, here is the code I've been playing with:
SELECT players.playerID, players.fName, players.lName, matches.playerID, COUNT(matches.playerID) AS 'gamesPlayed'
FROM players
INNER JOIN matches
ON matches.playerID = players.playerID
WHERE players.playerID=matches.playerID
ORDER BY gamesPlayed"
Currently there is 2 players having played 2 matches.
The current code returns 1 player having played 4 matches.
I am trying to get the COUNT(matches.playerID) to return only matches where the players.playerID = matches.playerID.
Any help is much appreciated!
You need to GROUP BY:
SELECT p.playerID, p.fName, p.lName, COUNT(*) AS gamesPlayed
FROM players p INNER JOIN matches m
ON p.playerID = m.playerID
GROUP BY p.playerID, p.fName, p.lName
ORDER BY gamesPlayed
If you want even players who have played zero games, then:
SELECT p.playerID, p.fName, p.lName, COUNT(m.playerID) AS gamesPlayed
FROM players p LEFT JOIN matches m
ON p.playerID = m.playerID
GROUP BY p.playerID, p.fName, p.lName
ORDER BY gamesPlayed
The reason I use COUNT(m.playerID) instead of COUNT(*) in the above is because COUNT(*) will always be at least one in this instance, while COUNT(m.playerID) can be zero if the only matched value is NULL.
At first place: your query lacks GROUP BY, at second - please check what argument COUNT accepts (in this query it's no different from COUNT(*)) – zerkms

MYSQL Toplist by the sum of teammember points

So i would like to make a toplist in mysql.
I have two table, users and teams.
In users I have: id,name,points,teamid
In teams I have: t_id,teamname,leaderid
I would like to make a toplist. The 10 teams with the most points.
I hope it is understandable what I want.
You need to calculate the total sum of points by using the subquery which will give you the top 10 points then join this result with a query which has team information with the sum of points for each team,from this approach if there is tie in scores of 2 teams they will be included in top 10 teams regarding the points
select t2.* from
(select t.*,sum(u.points) allpoints
from teams t
join users u
on(t.t_id= u.teamid)
group by t.t_id
) t2
join
(select sum(points) allpoints
from users
group by teamid
order by allpoints desc
limit 10) tp
on(t2.allpoints = tp.allpoints )
if you don't care for tie scenario you can simply use limit and order by
select t.*,sum(u.points) allpoints
from teams t
join users u
on(t.t_id= u.teamid)
group by t.t_id
order by allpoints desc
limit 10

querying for user's ranking in one-to-many tables

I am trying to write a query to find the score rank of a user's games. I need it to take in a user id and then return that user's relative ranking to other user's scores. There is a user and a game table. The game table has a userId field with a one-to-many relationship.
Sample table:
users:
id freebee
1 10
2 13
games:
userId score
1 15
1 20
2 10
1 15
passing $id 1 into this function should return the value 1, as user 1 currently has the highest score. Likewise, user 2 would return 2.
Currently this is what I have:
SELECT outerU.id, (
SELECT COUNT( * )
FROM users userI, games gameI
WHERE userI.id = gameI.userId
AND userO.id = gameO.userId
AND (
userI.freebee + SUM(gameI.score)
) >= ( userO.freebee + SUM(gameO.score) )
) AS rank
FROM users userO,
games gameO
WHERE id = $id
Which is giving me an "invalid use of group function" error. Any ideas?
SELECT u.id,total_score,
( SELECT COUNT(*) FROM
(SELECT u1.id, (IFNULL(u1.freebee,0)+ IFNULL(SUM(score),0)) as total_score
FROM users u1
LEFT JOIN games g ON (g.userId = u1.id)
GROUP BY u1.id
)x1
WHERE x1.total_score > x.total_score
)+1 as rank,
( SELECT COUNT(DISTINCT total_score) FROM
(SELECT u1.id, (IFNULL(u1.freebee,0)+ IFNULL(SUM(score),0)) as total_score
FROM users u1
LEFT JOIN games g ON (g.userId_Id = u1.id)
GROUP BY u1.id
)x1
WHERE x1.total_score > x.total_score
)+1 as dns_rank
FROM users u
LEFT JOIN
( SELECT u1.id, (IFNULL(u1.freebee,0)+ IFNULL(SUM(score),0)) as total_score
FROM users u1
LEFT JOIN games g ON (g.userId = u1.id)
GROUP BY u1.id
)x ON (x.id = u.id)
rank - (normal rank - e.g. - 1,2,2,4,5), dns_rank - dense rank (1,2,2,3,4). Column total_score - just for debugging...
The query does not like the reference of an outer table in the Sum function SUM(gameO.score) in the correlated subquery. Second, stop using the comma format for joins. Instead use the ANSI syntax of JOIN. For example, in your outer query did you really mean to use a cross join? That is how you wrote and how I represented it in the solution below but I doubt that is what you want.
EDIT
I've adjusted my query given your new information.
Select U.id, U.freebee, GameRanks.Score, GameRanks.Rank
From users As U
Join (
Select G.userid, G.score
, (
Select Count(*)
From Games As G2
Where G2.userid = G.userid
And G2.Score > G.Score
) + 1 As Rank
From Games As G
) As GameRanks
On GameRanks.userid = U.id
Where U.id =1
I'm not a MySQL person, but I believe that the usual way to do ranking in it is using a variable within your SQL statement. Something like the below (untested):
SELECT
SQ.user_id,
#rank:=#rank + 1 AS rank
FROM
(
SELECT
U.user_id,
U.freebee + SUM(COALESCE(G.score, 0)) AS total_score
FROM
Users U
LEFT OUTER JOIN Games G ON
G.user_id = U.user_id
) SQ
ORDER BY
SQ.total_score DESC
You could use that as a subquery to get the rank for a single user, although performance-wise that might not be the best route.
Here is "simplified" version for calculating a rank based only on "games" table. For calculating rank for a specific game only you need to add additional joins.
SELECT COUNT(*) + 1 AS rank
FROM (SELECT userid,
SUM(score) AS total
FROM games
GROUP BY userid
ORDER BY total DESC) AS gamescore
WHERE gamescore.total > (SELECT SUM(score)
FROM games
WHERE userid = 1)
It's based on the idea that ranking == number of players with bigger score + 1
Check this out:
http://rpbouman.blogspot.com/2009/09/mysql-another-ranking-trick.html