mysql ranking on sum and best score - mysql

i have a table with this structure:
score_id | user_id | category | subcategory | score
1 | 1 | game | 0 | 100
2 | 1 | game | 0 | 200
3 | 1 | quiz | 0 | 2000
4 | 1 | quiz | 1 | 1000
5 | 1 | game | 0 | 10
6 | 1 | game | 1 | 10
7 | 1 | game | 2 | 100
8 | 1 | game | 1 | 500
9 | 2 | game | 0 | 600
and i need different query mysql:
1) ranking of all team grouped by user_id sum of all best result beetween all records of user for category and subcategory
expected result
user_id | total_score | ranking
1 | 3310 | 1
2 | 600 | 2
where
3310 = (200 + 10 + 100+1000+2000)
200 is the best result of game 0,
10 is the best result of game 1,
100 is the best result of game 2,
2000 is the best result of quiz 0
1000 is the best result of quiz 1
600 = (600)
600 is the best result of game 0,
SOLUTION by #Strawberry (thank you)
SELECT a.*
, #i:=#i+1 rank
FROM
( SELECT user_id
, SUM(subtotal) total
FROM
( SELECT user_id
, category
, subcategory
, MAX(score) subtotal
FROM my_table
GROUP
BY user_id
, category
, subcategory
) x
GROUP
BY user_id
) a
JOIN
( SELECT #i:=0) vars
ORDER
BY total DESC;
2) ranking of all team grouped by user_id sum of all best result beetween all records of user for category and subcategory for only game or quiz
expected result game
user_id | total_score | ranking
2 | 600 | 1
1 | 310 | 2
where
600 = (600)
600 is the best result of game 0,
310 = (200 + 10 + 100)
200 is the best result of game 0,
10 is the best result of game 1,
100 is the best result of game 2,
expected result quiz
user_id | total_score | ranking
1 | 3000 | 1
2 | 0 | 2
where
3000 = (200 + 10 + 100)
2000 is the best result of quiz 0
1000 is the best result of quiz 1
0= (0)
(user_id= 2 don't play quiz)
BASED ON SOLUTION by #Strawberry (thank you)
SELECT a.*
, #i:=#i+1 rank
FROM
( SELECT user_id
, SUM(subtotal) total
FROM
( SELECT user_id
, category
, subcategory
, MAX(score) subtotal
FROM my_table
WHERE category = 'game' // or 'quiz
GROUP
BY user_id
, category
, subcategory
) x
GROUP
BY user_id
) a
JOIN
( SELECT #i:=0) vars
ORDER
BY total DESC;
3) ranking of all team grouped by user_id sum of all best result beetween all records of user for category and subcategory for only game or quiz with specific subcategory
expected result game 0
user_id | total_score | ranking
2 | 600 | 1
1 | 310 | 2
where
600 = (600)
600 is the best result of game 0,
200 = (200 )
200 is the best result of game 0,
BASED ON SOLUTION by #Strawberry (thank you)
SELECT a.*
, #i:=#i+1 rank
FROM
( SELECT user_id
, SUM(subtotal) total
FROM
( SELECT user_id
, category
, subcategory
, MAX(score) subtotal
FROM my_table
WHERE category = 'game'
AND subcategory = '0'
GROUP
BY user_id
, category
, subcategory
) x
GROUP
BY user_id
) a
JOIN
( SELECT #i:=0) vars
ORDER
BY total DESC;
4) get total score of single user (ex user_id=1 ) for query 1
5) get ranking of single user (ex user_id=1 ) for query 1
6) get total score of single user (ex user_id=1 ) for query 2
7) get ranking of single user (ex user_id=1 ) for query 2
8) get total score of single user (ex user_id=1 ) for query 3
9) get ranking of single user (ex user_id=1 ) for query 3
thank you!

Here's the first one. Using this, show us your best efforts for the remainder...
SELECT a.*
, #i:=#i+1 rank
FROM
( SELECT user_id
, SUM(subtotal) total
FROM
( SELECT user_id
, category
, subcategory
, MAX(score) subtotal
FROM my_table
GROUP
BY user_id
, category
, subcategory
) x
GROUP
BY user_id
) a
JOIN
( SELECT #i:=0) vars
ORDER
BY total DESC;
Note that this solution doesn't account for ties.

Related

Max() value from subquery with SUM() & multiple rows

I try to write a mysql query that display max value of a sub query but I don't. I have this primary query that works fine. This query select total points scored by each team for a specific game :
SELECT team_id, SUM(points) as totalpointsscored, game_id
FROM BOXSCORES
WHERE season="1920" and categorie=2
GROUP BY team_id, game_id
Output is like this :
team_id | value (points scored) | game_id
ASM | 98 | 9117338
ASM | 104 | 9117335
ASM | 75 | 9117324
LEM | 128 | 9117380
LEM | 97 | 9117316
STR | 95 | 9117334
STR | 102 | 9117177
STR | 88 | 9117469
I'd like to select now the max value for each team to know in what game a team scored the most. So, the output would be :
ASM | 104 | 9117335
LEM | 128 | 9117380
STR | 102 | 9117177
I try with group by and having but it doesn't work. team_id & value is ok but the game_id is always the first row & not the game_id attach to the value. Could you help me to find the best solution?
In MySQL 8.0, you can use window functions:
select *
from (
select
team_id,
sum(points) as total_points_scored,
game_id,
rank() over(partition by team_id order by sum(points) desc) rn
from boxscores
where season = '1920' and categorie = 2
group by team_id, game_id
) t
where rn = 1
In earlier versions, one solution is:
select
team_id,
sum(points) as total_points_scored,
game_id
from boxscores b
where season = '1920' and categorie = 2
group by team_id, game_id
having sum(points) = (
select sum(points)
from boxscore b1
where b1.season = b.season and b1.categorie = b.categorie and b1.team_id = b.team_id
group by game_id
order by sum(points) desc
limit 1
)
I fixed it.
I just add season & categorie in first query like this :
select
team_id,
sum(points) as total_points_scored,
game_id, season, categorie
from BOXSCORES b
where season= '1920' and categorie = 2
group by team_id, game_id
having sum(points) = (
select sum(points)
from BOXSCORES b1
where b1.season= b.season and b1.categorie = b.categorie and b1.team_id= b.team_id
group by game_id
order by sum(points) desc
limit 1
)

Overall Score Based on Top Three Score

I have a table with this data
+------+-----+————-----+
|Props |Score|Type |
+------+-----+-------- +
|1.EY | 30|Core
|2.FG | 29|Core
|2.YUE | 29|Core
|3.VB. | 28|Elective
|4.RX. | 67|Elective
|5.XE. | 89|Elective
|6.TF. | 60|Elective
|7.HK | 76|Elective
|8.ER | 58|Elective
I want to calculate the overall score by adding all Core scores plus any of the three best Elective scores. I cant seem to find my way around it.
Expected Results is 320: 3 Core Score + 3 best Elective
i.e(30+29+29)+(89+76+67)
Use UNION ALL for the 2 cases of scores and then sum over the returned scores:
select sum(t.score) totalscore
from (
select score from tablename
where type = 'Core'
union all
select t.score from (
select score from tablename
where type = 'Elective'
order by score desc
limit 3
) t
) t
See the demo.
Result:
| totalscore |
| ---------- |
| 320 |
You could rank the records by type within type partitions in an inner query and do a conditional sum in the outer query, like:
SELECT
SUM(CASE
WHEN type = 'Core' THEN score
WHEN type = 'Elective' AND rn <= 3 THEN score
ELSE 0
END) res
FROM (
SELECT
t.*,
ROW_NUMBER() OVER(PARTITION BY type ORDER BY score DESC) rn
FROM mytable t
) x
Demo on DB Fiddle with your sample data:
| res |
| --- |
| 320 |

Creating a SQL query to sum and divide

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;

retrieve value of maximum occurrence in a table

I am in a very complicated problem. Let me explain you first what I am doing right now:
I have a table name feedback in which I am storing grades against course id. The table looks like this:
+-------+-------+-------+-------+-----------+--------------
| id | cid | grade |g_point| workload | easiness
+-------+-------+-------+-------+-----------+--------------
| 1 | 10 | A+ | 1 | 5 | 4
| 2 | 10 | A+ | 1 | 2 | 4
| 3 | 10 | B | 3 | 3 | 3
| 4 | 11 | B+ | 2 | 2 | 3
| 5 | 11 | A+ | 1 | 5 | 4
| 6 | 12 | B | 3 | 3 | 3
| 7 | 11 | B+ | 2 | 7 | 8
| 8 | 11 | A+ | 1 | 1 | 2
g_point has just specific values for the grades, thus I can use these values to show the user courses sorted by grades.
Okay, now first my task is to print out the grade of each course. The grade can be calculated by the maximum occurrence against each course. For example from this table we can see the result of cid = 10 will be A+, because it is present two times there. This is simple. I have already implemented this query which I will write here in the end.
The main problem is when we talk about the course cid = 11 which has two different grades. Now in that situation client asks me to take the average of workload and easiness of both these courses and whichever course has the greater average should be shown. The average would be computed like this:
all workload values of the grade against course
+ all easiness values of the grade against course
/ 2
From this example cid = 11 has four entries,have equal number of grades against a course
B+ grade average
avgworkload(2 + 7)/2=x
avgeasiness(3 + 8)/2 = y
answer x+y/2 = 10
A+ grade average
avgworkload(5 + 1)/2=x
avgeasiness(4 + 2)/2 = y
answer x+y/2 = 3
so the grade should be B+.
This is the query which I am running to get the max occurrence grade
SELECT
f3.coursecodeID cid,
f3.grade_point p,
f3.grade g
FROM (
SELECT
coursecodeID,
MAX(mode_qty) mode_qty
FROM (
SELECT
coursecodeID,
COUNT(grade_point) mode_qty
FROM feedback
GROUP BY
coursecodeID, grade_point
) f1
GROUP BY coursecodeID
) f2
INNER JOIN (
SELECT
coursecodeID,
grade_point,
grade,
COUNT(grade_point) mode_qty
FROM feedback
GROUP BY
coursecodeID, grade_point
) f3
ON
f2.coursecodeID = f3.coursecodeID AND
f2.mode_qty = f3.mode_qty
GROUP BY f3.coursecodeID
ORDER BY f3.grade_point
Here is SQL Fiddle.
I added a table Courses with the list of all course IDs, to make the main idea of the query easier to see. Most likely you have it in the real database. If not, you can generate it on the fly from feedback by grouping by cid.
For each cid we need to find the grade. Group feedback by cid, grade to get a list of all grades for the cid. We need to pick only one grade for a cid, so we use LIMIT 1. To determine which grade to pick we order them. First, by occurrence - simple COUNT. Second, by the average score. Finally, if there are several grades than have same occurrence and same average score, then pick the grade with the smallest g_point. You can adjust the rules by tweaking the ORDER BY clause.
SELECT
courses.cid
,(
SELECT feedback.grade
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS CourseGrade
FROM courses
ORDER BY courses.cid
result set
cid CourseGrade
10 A+
11 B+
12 B
UPDATE
MySQL doesn't have lateral joins, so one possible way to get the second column g_point is to repeat the correlated sub-query. SQL Fiddle
SELECT
courses.cid
,(
SELECT feedback.grade
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS CourseGrade
,(
SELECT feedback.g_point
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS CourseGPoint
FROM courses
ORDER BY CourseGPoint
result set
cid CourseGrade CourseGPoint
10 A+ 1
11 B+ 2
12 B 3
Update 2 Added average score into ORDER BY SQL Fiddle
SELECT
courses.cid
,(
SELECT feedback.grade
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS CourseGrade
,(
SELECT feedback.g_point
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS CourseGPoint
,(
SELECT (AVG(workload) + AVG(easiness))/2
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS AvgScore
FROM courses
ORDER BY CourseGPoint, AvgScore DESC
result
cid CourseGrade CourseGPoint AvgScore
10 A+ 1 3.75
11 B+ 2 5
12 B 3 3
If I understood well you need an inner select to find the average, and a second outer select to find the maximum values of the average
select cid, grade, max(average)/2 from (
select cid, grade, avg(workload + easiness) as average
from feedback
group by cid, grade
) x group by cid, grade
This solution has been tested on your data usign sql fiddle at this link
If you change the previous query to
select cid, max(average)/2 from (
select cid, grade, avg(workload + easiness) as average
from feedback
group by cid, grade
) x group by cid
You will find the max average for each cid.
As mentioned in the comments you have to choose wich strategy use if you have more grades that meets the max average. For example if you have
+-------+-------+-------+-------+-----------+--------------
| id | cid | grade |g_point| workload | easiness
+-------+-------+-------+-------+-----------+--------------
| 1 | 10 | A+ | 1 | 5 | 4
| 2 | 10 | A+ | 1 | 2 | 4
| 3 | 10 | B | 3 | 3 | 3
| 4 | 11 | B+ | 2 | 2 | 3
| 5 | 11 | A+ | 1 | 5 | 4
| 9 | 11 | C | 1 | 3 | 6
You will have grades A+ and C soddisfing the maximum average 4.5

MAX() and SUM() in one query

I have this table
dept | amount | price
1 | 2 | 20
3 | 2 | 50
4 | 3 | 10
2 | 5 | 20
1 | 1 | 15
4 | 1 | 30
4 | 6 | 5
2 | 7 | 7
1 | 1 | 24
2 | 5 | 12
dept is de department number
amount is how many of a product is sold.
price is how much the price of the product is
How can I found the dept, that has got the most money from selling their products.
I have this:
SELECT dept, SUM( amount * price ) AS total
FROM table
GROUP BY dept
I need it to return the dept with the highest total.
I can't use MAX( SUM( amount * price ) ), so how do I do this?
Oh yeah. It's a school assignment and I may not use LIMIT or ORDER BY
Without using LIMIT you can try using HAVING:
SELECT dept,SUM(amount * price) AS total
FROM tab1
GROUP BY dept
HAVING SUM(amount * price) = (
SELECT MAX(total)
FROM (
SELECT SUM(amount * price) AS total
FROM tab1
GROUP BY dept
) a
)
sqlfiddle demo
If you do not want to use ORDER and LIMIT. This is a solution ( Tested)
SELECT dept, SUM( amount * price ) AS total
FROM table
GROUP BY dept
HAVING SUM( amount * price ) = ( SELECT MAX(A.total)
FROM
(
SELECT dept, SUM( amount * price ) AS total
FROM table
GROUP BY dept
) A
)
This will give you the department with the highest total:
select top 1 dept, sum(amount * price)
from table
group by dept
order by sum(amount * price) desc
You can sort by the total descending and take the first entry
SELECT dept, SUM( amount * price ) AS total
FROM table
GROUP BY dept
order by total desc
limit 1