MYSQL GROUP BY MAX score - mysql

I have a table called scores which contains columns
How do I select which id_team is top scorer per game
i m trying with this, but that's not correct result
SELECT MAX( score ) , id_team
FROM scores
GROUP BY `id_game`
LIMIT 0 , 30

You can use a self join to find out the right team id for game a which has max score
SELECT s.*
FROM scores s
JOIN (
SELECT MAX(score) score, id_game
FROM scores
GROUP BY id_game ) ss USING(score ,id_game )
LIMIT 0 , 30

select A.id_game, A.id_team as winning_team
from scores A,
(
select max(score) as max, id_game
from scores
group by id_game
)B
where A.id_game = B.id_game
and A.score = B.max

Related

SQL query, how to improve?

I did a task to write an SQL query and I wonder if I can improve it somehow.
Description:
Let's say we have a db on some online service
Let's create tables, and insert some data
create table players (
player_id integer not null unique,
group_id integer not null
);
create table matches (
match_id integer not null unique,
first_player integer not null,
second_player integer not null,
first_score integer not null,
second_score integer not null
);
insert into players values(20, 2);
insert into players values(30, 1);
insert into players values(40, 3);
insert into players values(45, 1);
insert into players values(50, 2);
insert into players values(65, 1);
insert into matches values(1, 30, 45, 10, 12);
insert into matches values(2, 20, 50, 5, 5);
insert into matches values(13, 65, 45, 10, 10);
insert into matches values(5, 30, 65, 3, 15);
insert into matches values(42, 45, 65, 8, 4);
The output of the query should be:
group_id | winner_id
--------------------
1 | 45
2 | 20
3 | 40
So, we should output the winner (player id) of each group. Winner is the player, who got max amount of points in matches.
If user is alone in the group - he's a winner automatically, in case players have equal amount of points - the winner is the one, who has lower id value.
Output should be ordered by group_id field
My solution:
SELECT
results.group_id,
results.winner_id
FROM
(
SELECT
summed.group_id,
summed.player_id AS winner_id,
MAX(summed.sum) AS total_score
FROM
(
SELECT
mapped.player_id,
mapped.group_id,
SUM(mapped.points) AS sum
FROM
(
SELECT
p.player_id,
p.group_id,
CASE WHEN p.player_id = m.first_player THEN m.first_score WHEN p.player_id = m.second_player THEN m.second_score ELSE 0 END AS points
FROM
players AS p
LEFT JOIN matches AS m ON p.player_id = m.first_player
OR p.player_id = m.second_player
) AS mapped
GROUP BY
mapped.player_id
) as summed
GROUP BY
summed.group_id
ORDER BY
summed.group_id
) AS results;
It works, but I'm 99% sure it can be cleaner. Will be thankful for any suggestions
First, use UNION ALL to extract from matches 2 columns: player_id and score for all players and their scores.
Then aggregate to get each player's total score.
Finally do a LEFT join of players to the resultset you obtained, use GROUP_CONCAT() to collect all players of each group in descending order respective to their total score and with SUBSTRING_INDEX() pick the 1st player:
SELECT p.group_id,
SUBSTRING_INDEX(GROUP_CONCAT(p.player_id ORDER BY t.score DESC, p.player_id), ',', 1) winner_id
FROM players p
LEFT JOIN (
SELECT player_id, SUM(score) score
FROM (
SELECT first_player player_id, first_score score FROM matches
UNION ALL
SELECT second_player, second_score FROM matches
) t
GROUP BY player_id
) t ON t.player_id = p.player_id
GROUP BY p.group_id;
See the demo.
Note that, by doing a LEFT join, you get in the results all groups, even the ones that do not have any players that participated in any match (just like your sample data), in which case the winner is an arbitrary player (just like your expected results).
You can unpivot the matches table and sum the points per player (which is I think what you want):
select p.player_id, p.group_id, sum(score) as sum_score
from ((select first_player as player_id, first_score as score
from matches
) union all
(select second_player as player_id, second_score as score
from matches
)
) mp
players p
using (player_id)
group by p.player_id, p.group_id;
Next, you can introduce a window function to get the top:
select player_id, group_id, sum_score
from (select p.player_id, p.group_id, sum(score) as sum_score,
row_number() over (partition by p.group_id order by sum(score) desc p.player_id asc) as seqnum
from ((select first_player as player_id, first_score as score
from matches
) union all
(select second_player as player_id, second_score as score
from matches
)
) mp
players p
using (player_id)
group by p.player_id, p.group_id
) pg
where seqnum = 1;
If you actually want the maximum score over all the matches rather than the sum(), then use max() instead of sum().
Here's another way:
WITH match_records AS (
SELECT match_id,first_player players, first_score scores FROM matches UNION ALL
SELECT match_id,second_player, second_score FROM matches
)
SELECT group_id, player_id
FROM
(SELECT group_id, player_id, players, SUM(scores) ts,
ROW_NUMBER() OVER (PARTITION BY group_id ORDER BY SUM(scores) DESC) pos
FROM players p LEFT JOIN match_records mr ON mr.players=p.player_id
GROUP BY group_id, player_id, players) fp
WHERE pos=1
ORDER BY group_id;
It's basically the same idea as others (to un-pivot the matches table) but with a slightly different operation.
Demo fiddle

Wrong output in MYSQL

I have a question as follows:
The total score of a hacker is the sum of their maximum scores for all of the challenges. Write a query to print the hacker_id, name, and total score of the hackers ordered by the descending score.
If more than one hacker achieved the same total score, then sort the result by ascending hacker_id.
Exclude all hackers with a total score of 0 from your result.
The 2 tables are given as follows:
table: Hackers
========================================
hacker_id: Integer (ID of the hacker)
name: String (Name of the hacker)
========================================
table: Submissions
===================================================
submission_id: Integer (ID of the submission)
hacker_id: Integer (ID of the hacker)
challenge_id: Integer (ID of the challenge)
score: Integer (score of the submission)
===================================================
The MYSQL query I've written is as follows:-
select
a.hacker_id,
a.name,
a.total
from(
select
h.hacker_id,
h.name,
sum(case when s.hacker_id=h.hacker_id then s.score else 0 end) as total
from
hackers h,
submissions s
group by
h.hacker_id,
h.name
) as a
where
a.total>0
order by
a.total desc,
a.hacker_id asc;
I'm getting wrong output for this though that output satisfies all the rules of order & ommission of 0 scorers as required. I'm very confused as to what the error is. Someone please help!!!
Something like:
select h.hacker_id, h.name, sum(s.score) as total
from hackers h
join submissions s using (hacker_id)
group by h.hacker_id
order by sum(s.score) desc, h.name
having sum(s.score) > 0
The basic idea is that to start with we join hackers and submissions tables together, and then sum the score and use the group by clause to get a new total for each hacker. Then add the order by. Then finally the HAVING is what filters out anyone with a zero score.
I don't have your data set to test with but hopefully this is close enough that it will help you along the way!
The total score of a hacker is the sum of their maximum scores for all of the challenges.
First, you need to find the maximum score a hacker, for each challenge:
SELECT hacker_id
, challenge_id
, MAX(score) AS max_score
FROM Submissions
GROUP BY hacker_id
, challenge_id
Then you need to sum that for each hacker:
SELECT hacker_id
, SUM(max_score) AS total_score
FROM ( SELECT hacker_id
, challenge_id
, MAX(score) AS max_score
FROM Submissions
GROUP BY hacker_id
, challenge_id
) ms
GROUP BY hacker_id
Finally you apply the rest:
Exclude all hackers with a total score of 0 from your result.
Print the hacker_id, name, and total score
Ordered by the descending score, then by ascending hacker_id.
SELECT hacker_id
, ( SELECT name
FROM Hackers h
WHERE h.hacker_id = ms.hacker_id
) AS name
, SUM(max_score) AS total_score
FROM ( SELECT hacker_id
, challenge_id
, MAX(score) AS max_score
FROM Submissions
GROUP BY hacker_id
, challenge_id
) ms
GROUP BY hacker_id
HAVING SUM(max_score) <> 0
ORDER BY total_score DESC
, hacker_id

SQL SCORE RANKING

I'm working with score ranking on my app for all user score. My problem is I don't know how to return one row for each stud_num.
My query:
SELECT * FROM score WHERE assess_type = 'professional' ORDER BY total_score DESC.
Result:
As you can see I have 3 stud_num and I only want one row per stud_num and the highest score of it.
You can use correlated query like this:
SELECT * FROM score t
WHERE t.assess_type = 'professional'
AND t.total_score = (select max(s.total_score)
from score s
where t.stud_num = s.stud_num)
group by stud_num
The option given by #sagi is good:
SELECT * FROM score t
WHERE t.assess_type = 'professional'
AND t.total_score = (select max(s.total_score)
from score s
where t.stud_num = s.stud_num)
group by stud_num
Another option would be to use an inner join and group by together.
The resulting query would become:
select * from score a
inner join (
SELECT stud_num, max(total_score) tscore FROM `score` group by stud_num) b
on a.stud_num = b.stud_num and total_score= tscore
group by a.stud_num
try it out at sqlfiddle
Use the MAX and GROUP BY functions like this:
SELECT score_id, stud_num, assess_type, total_item, MAX(total_score), average, date_taken
FROM score
WHERE assess_type = 'professional'
GROUP BY stud_num
ORDER BY 5 DESC
Here's my the ans:
SELECT score_id, stud_num, assess_type, total_item, MAX( total_score )
FROM score
WHERE assess_type = 'professional'
GROUP BY stud_num, total_item
ORDER BY MAX( total_score ) DESC

How to get rank and max score where each user has many scores in Mysql?

I have a Score table that hold user_id,score in MySql . each user has many scores . I want to get best rank of each user ?
I check a lot of solution but all of them work for table that each user has single score .
I tried this but sometimes user by min score got higher rank :
SET #rank= 0;;
SELECT Users.username, score, rank
FROM (
SELECT * , #rank := #rank +1 AS rank
FROM Scores
JOIN (
SELECT userid AS user_id2, MAX( score ) AS max_score
FROM Scores
GROUP BY user_id2
ORDER BY max_score DESC
) AS max_score_table ON max_score = Scores.score
AND Scores.userid = user_id2
) derived_table
join Users On (Users.id=derived_table.user_id2)
ORDER BY rank
LIMIT 0, 100

MAX (SUM(votes)) | get only winners

I want to get only winners in mysql table.
SELECT mayor_id, local_unit_id, Value FROM
(SELECT mayor_id, local_unit_id, SUM( `votes` ) AS 'Value'
FROM mayorresults
GROUP BY `mayor_id`) AS t1
ORDER BY `t1`.`local_unit_id` ASC
Idea is to Sum votes first then get only largest number, in this case the winner.
With this query I can get all, but not just the winners.
I want MAX(SUM(votes)) to get, but It doesn't work like this.
EDIT: I want to get winners for each localunit
eg.
local_unit_id mayor_id votes
1 25 8562
2 534 18562
Update, after the explanations:
SELECT grp.local_unit_id, grp.mayor_id, grp.Value
FROM
( SELECT local_unit_id, mayor_id, SUM( votes ) AS Value
FROM mayorresults
GROUP BY local_unit_id, mayor_id
) AS grp
JOIN
( SELECT local_unit_id, MAX(Value) AS Value
FROM
( SELECT local_unit_id, mayor_id, SUM( votes ) AS Value
FROM mayorresults
GROUP BY local_unit_id, mayor_id
) AS grp
GROUP BY local_unit_id
) AS grp2
ON grp2.local_unit_id = grp.local_unit_id
AND grp2.Value = grp.Value
ORDER BY local_unit ASC
Have you tried:
SELECT mayor_id, local_unit_id, MAX(Value) FROM
(SELECT mayor_id, local_unit_id, SUM( `votes` ) AS 'Value'
FROM mayorresults
GROUP BY `mayor_id`) AS t1
ORDER BY `t1`.`local_unit_id` ASC
You can't have the max value of a sum. You can have the max sum of a subquery.