Show MAX value with a join - mysql

I'm struggling a little with a query I'm trying to build. For a game I want to display the top 10 of scores.
My table looks like this:
player = id, playername, username
score = id, track, car, bestscore, totalscore, player_id (foreign key to player.id)
For the top10 I want to show the playername, the total score, the car and the track.
The current query I have is:
SELECT p.playername, MAX(s.totalscore) totalscore, s.car, s.track
FROM player p
INNER JOIN score s on p.id = s.player_id
GROUP BY p.playername
ORDER BY MAX(s.totalscore) DESC
LIMIT 10
This seems to work fine, except for one problem. If a user has a score of 50 on track 1 with car 1, and then puts a score of 60 on track 1 with car 2, I see car 1 on the query. It does not seem to get the according car of the top score if this user.
I hope it makes sense what I just told.
Thanks in advance!
EDIT:
SELECT p.playername, MAX(s.totalscore) as totalscore, s.car, s.track
FROM (SELECT * FROM score ORDER BY totalscore DESC) s
INNER JOIN player p ON s.player_id = p.id
GROUP BY p.playername
ORDER BY MAX(s.totalscore) DESC
LIMIT 10
This query seems to do the trick. I've been trying around and the result-set is exactly what I mean. Is it any good though? I'm not good at SQL and just because it works doesn't always mean it's good, does it?

When you have a non-aggregated field as part of an aggregated query that isn't in your group by, and has a many to one relationship with the relation on which you are grouping, MySQL gives no guarantee what it will return.
This query would throw an error in another RDBMS. If you care about the top score by (person,car) tuple, just add it to the group by. However, if you want each player to have a max score, regardless of what car was used, you'll need a subquery or a self join.
One way to do it:
SELECT p.playername, s1.totalscore , s1.car, s1.track
FROM player p
INNER JOIN
score s1 on p.id = s1.player_id
WHERE s1.totalscore = ( SELECT MAX(totalscore) FROM score s2 WHERE s2.player_id=s1.player_id)
ORDER BY s1.totalscore DESC
LIMIT 10

You use "Group By" on playername so the other columns will group in "what mysql desides" manner. If you want to get the cars you should add - group by car.
SELECT p.playername, MAX(s.totalscore) totalscore, s.car, s.track
FROM player p
INNER JOIN score s on p.id = s.player_id
GROUP BY p.playername, s.car //added car
ORDER BY s.totalscore DESC
LIMIT 10

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.

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

MYSQL - how to average returned votes from inner joined table results

I'm very much a beginner, please bear with me.
I'm trying to get the ID number from one table to point to the same number in another table, which holds a name value (ie rating.id 1 = names.id 1 and names.name "bread"), which I seem to have managed. Then I want to display the average rating next to the name, ie take all rating.rate values (range from 1-5) and average the rating, and display it next to the product, then order desc. such as :
name-------average rating
Coffee-----4.3
Bread------3.2
Cheese-----2.9
etc
So far it gives me all the product names, but shows the product name as many times as it has ratings, then ranks desc. Not much use. This is what I have :
SELECT rating.rate, names.name FROM rating INNER JOIN names ON rating.id = names.id ORDER BY rating.rate DESC LIMIT 0, 25 GROUP BY names.name
Thank you for your help!
Your example does not appear to be using the AVG function at all? How about the below?
SELECT AVG(rating.rate) as avg_rating, names.name
FROM rating
JOIN names
ON rating.id = names.id
GROUP BY names.name
ORDER BY avg_rating DESC
LIMIT 0, 25
This will average out the ratings per name because of the GROUP BY. The result of the AVG is put in to avg_rating and used in the ORDER BY.

Count rows with bigger average

Each student has some scores (and each score has student_id column).
I want to calculate student average, compare his average with other student, and find his position in his class.
Is it possible to find his position based on his average with 1 query? (may contains subqueries or joins)
I can sort all students by their average by this query:
SELECT s.*
FROM
scores s LEFT JOIN lessons lesson
ON lesson.id = s.lesson_id
WHERE lesson.display = 1
GROUP BY s.student_id
ORDER BY AVG(s.score) DESC
but it needs processing with PHP array_search function. (I think using MySQL functions is better, in this situation)
select student_id, AVG(scores) as 'average' from lessons as l, scores as s
where lessons.id = s.lesson_id and lesson.display = 1
GROUP BY s.student_id order by average desc`
Try this query
sample http://sqlfiddle.com/#!2/4fb8d/1
Hope this helps
select s.id, AVG(l.scores) as average from lessons as l, student as s
where l.id = s.lessonid and l.display = 1
GROUP BY s.id order by average desc
can solve your problem
Check this link
Thanks to Meherzad's sql query
I think you are looking for something like this:
SELECT COUNT(DISTINCT average)
FROM (
SELECT AVG(score) as average
FROM scores INNER JOIN lessons
ON scores.lesson_id = lessons.id
WHERE display=1
GROUP BY student_id
) sub_scores
WHERE average >= (SELECT AVG(score)
FROM scores INNER JOIN lessons
ON scores.lesson_id = lessons.id
WHERE display=1
AND student_id=1)
In the subquery sub_scores I'm calculating all averages of all students, in the outer query I'm calculating the number of distinct averages bigger than the average of student 1.
This will return the position of student 1.
Depending on what you are after, you might want to remove DISTINCT clause.
See this fiddle.
You need to use a user defined variable over the result set.
Try this:
SELECT *, (#rank := if(#rank is null, 1, #rank + 1)) as rank
FROM (SELECT s.*
FROM scores s
LEFT JOIN lessons lesson ON lesson.id = s.lesson_id
WHERE lesson.display = 1
GROUP BY s.student_id
ORDER BY AVG(s.score) DESC
) x

Left join, how to specify 1 result from the right?

This one is fairly specific, so I'm hoping for a quick fix.
I have a single result in my leaderboard table for each team. In my teams table, I have several results for each team (one result per game to enable team development history).
I want to show each team in the leaderboard once, and have teamID replaced by strName. Problem is, my left join is giving me one record for each team result; I just want a single record.
SELECT * , a.strName AS teamName
FROM bb_leaderboards l
LEFT JOIN bb_teams a ON ( l.teamID = a.ID )
WHERE l.season =8
AND l.division =1
ORDER BY l.division DESC , points DESC , wins DESC , l.TDdiff DESC
LIMIT 0 , 30
What do I need to do to this to get a 1:1 output?
You could do a SELECT DISTINCT instead, but you'll have to narrow down your select a bit. So:
SELECT DISTINCT l.*, a.strName AS teamName
...
That should filter out the duplicates.