How to SUM duplicate values based on certain conditions - mysql

I have a data like this,
Name |Exam_ID|Score
------+-------+------
Matt |12 | 87
Matt |12 | 85
Andy |10 | 89
Lisa |11 | 32
Lisa |11 | 68
Andy |11 | 38
Matt |10 | 70
Lisa |10 | 87
I want to SUM those score, but only those with different name and exam_id. If there's more than one same exam_id on same name, it will took the highest score. The end result I want like this:
Name |Score
------+------
Matt | 157
Andy | 127
Lisa | 155
Matt got 3 scores (87, 85, 70). But since 87 and 85 using same exam_id, I need to only take the highest score and SUM it with different score that got different exam_id which make his total score are 87+70 = 157
I've been trying using MAX, but I can't get it like that
SELECT Name, MAX(Exam_ID), SUM(Score) from RESULT
group by NAME;

You need two levels of aggregation:
select name, sum(max_score)
from (select name, exam_id, max(score) as max_score
from result
group by name, exam_id
) ne
group by name;

You'll need to exploit the structured part of structured query language, and make a two-level query
SELECT Name, SUM(Score) AS Score
FROM (
SELECT Name, Exam_ID, MAX(Score) AS Score
FROM Result
GROUP BY Name
) BestScoresPerExam
GROUP BY Name
The inner query gets the best score for each exam. The outer one sums the scores.

try this...
select name, exam_id, sum(Score) as max_score from result group by name, exam_id

Related

How to make MYSQL GROUP_CONCAT result distinct and ordered by number occurrences

so i have a table that looks like the following
tool_id | tool_user
hammer adam
hammer adam
hammer sandra
screwdriver sandra
So i am trying to select the tools ordered by number of usages (record occurrences) and also concat all the users in a field, the tricky part is to count and sort the users by number of occurences as well
So far, i was able to get the tools by usages and order them but i am not sure how to sort the users by number of occurrences.
The expected result of the select statment is:
tool users
hammer adam,sandra
screwdriver sandra
Current the SQL statement looks like following:
SELECT tool_id, GROUP_CONCAT(tool_user SEPARATOR ",") AS tool_users, COUNT(*) AS count FROM tools_table GROUP BY tool_id ORDER BY count DESC LIMIT 5
First do a query to reduce the rows to one per tool and user:
select tool_id, tool_user, count(*) as count from tools_table group by tool_id, tool_user;
+-------------+-----------+-------+
| tool_id | tool_user | count |
+-------------+-----------+-------+
| hammer | adam | 2 |
| hammer | sandra | 1 |
| screwdriver | sandra | 1 |
+-------------+-----------+-------+
Then you can wrap that query in another query to do the group-concat:
select tool_id, group_concat(tool_user order by count desc) as users from (
select tool_id, tool_user, count(*) as count from tools_table group by tool_id, tool_user
) as t
group by tool_id;
+-------------+-------------+
| tool_id | users |
+-------------+-------------+
| hammer | adam,sandra |
| screwdriver | sandra |
+-------------+-------------+
Simply add an Distinct
SELECT
tool_id, GROUP_CONCAT(DISTINCT tool_user SEPARATOR ",") AS tool_users
FROM tools_table
GROUP BY tool_id
ORDER BY COUNT(DISTINCT tool_user) DESC LIMIT 5
Gives You
tool_id tool_users
hammer adam,sandra
screwdriver sandra
Example https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=972b29cff86121dc497d1827fbc3f1ab

Query Count Mysql returns 0

I have a question about Query using "Count" function.
I have a table : Student(id,name,age,sex)
I use sql query as:
Select name, age, count(id) as NumberOf
from Student
where sex = 'Boy'
group by age, name
And My DB:
1 | John | 12 | Boy |
2 | Mary | 13 | Girl |
3 | Alice | 15 | Girl |
I want to find a number of student is the same as age as well as boy.But it returns Null. I want it to return 0. How should? Thanks
I suppose you want this :
select name, age, sum(if(sex='Boy',1,0)) as NumberOf
from student
group by age, name;
name age NumberOf
John 12 1
Mary 13 0
Alice 15 0
P.S. deliberately I put sum due to probability of existence of duplicated record for name and age.
You can do this without if :
select name, age, sum(sex='Boy') as NumberOf
from student
group by age, name;

MySQL search value in two columns and sum third column

In my table "game_info" I have
ID | player_1 | player_2 | score
--------------------------------
1 | John | Rick | 100
2 | Joe | John | 80
3 | Bob | Rick | 210
I want to sum total score for every player no matter they are player_1 or player_2 and order by score.
What I expect is:
Name | Score
------------
Rick | 310
Bob | 210
John | 180
Joe | 80
I have tried to JOIN and UNION, but I can't get it right.
Is there any way to do this in sql or i have to redesign my table?
Thank You!
You can do this with union all and group by:
select player, sum(score)
from ((select player1 as player, score from game_info
) union all
(select player2 as player, score from game_info
)
) p
group by player
order by sum(score) desc;
SELECT player, SUM(score)
FROM
(SELECT player_1 AS player, score
FROM t
UNION ALL
SELECT player_2 as player, score
FROM t) sub
GROUP BY player
You have to union the player 1 results with the player 2 results, so that you have one result with just player and score. Of course, the scores will be listed twice in this view, one for each player. In my query, the result is called sub. Based on sub, you can group by player and sum their scores.

Select every other row as male/female from mysql table

I've got a table containing persons gender-coded as 0 and 1. I need to select every other row as male/female. I thought I could manage this somehow by using modulo and the gender-codes 0 and 1, but I haven't managed to figure it out yet...
The result I'm looking for would look like this:
+-----+--------+-------+
| row | gender | name |
+-----+--------+-------+
| 1 | female | Lisa |
| 2 | male | Greg |
| 3 | female | Mary |
| 4 | male | John |
| 5 | female | Jenny |
+-----+--------+-------+
etc.
The alternative is to do it in PHP by merging 2 separate arrays, but I would really like it as a SQL query...
Any suggestions are appreciated!
Do two subqueries to select male and female. Use ranking function to have them enumerated.
Males:
1 | Peter
2 | John
3 | Chris
Females:
1 | Marry
2 | Christina
3 | Kate
Then multiplay ranking result by x10 and add 5 for females. So you have this:
Males:
10 | Peter
20 | John
30 | Chris
Females:
15 | Marry
25 | Christina
35 | Kate
Then do the UNION ALL and sort by new sort order/new ID.
Together it should like this (pseudo code)
SELECT
Name
FROM
(subquery for Males: RANK() AS sortOrd, Name)
UNION ALL
(subquery for Females: RANK()+1 AS SortOrd, Name)
ORDER BY SortOrd
Result should be like this:
Males and Females:
10 | Peter
15 | Marry
20 | John
25 | Christina
30 | Chris
35 | Kate
Found Emulate Row_Number() and modified a bit for your case.
set #rownum := 0;
set #pg := -1;
select p.name,
p.gender
from
(
select name,
gender,
#rownum := if(#pg = gender, #rownum+1, 1) as rn,
#pg := gender as pg
from persons
order by gender
) as p
order by p.rn, p.gender
Try on SQL Fiddle
Note: From 9.4. User-Defined Variables
As a general rule, you should never assign a value to a user variable
and read the value within the same statement. You might get the
results you expect, but this is not guaranteed.
I will leave it up to you do decide if you can use this. I don't use MySQL so I can't really tell you if you should be concerned or not.
Similar to Mikael's solution but without the need to order the resultset multiple times -
SELECT *
FROM (
SELECT people.*,
IF(gender=0, #mr:=#mr+1, #fr:=#fr+1) AS rank
FROM people, (SELECT #mr:=0, #fr:=0) initvars
) tmp
ORDER BY rank ASC, gender ASC;
To avoid having to order both the inner and outer selects I have used separate counters (#mr - male rank, #fr - female rank) in the inner select.
I've got a table containing persons gender-coded as 0 and 1
Then why would you make assumptions on the order of rows in the result set? Seems to me transforming the 0/1 into 'male'/'female' is far more robust:
select name, case gender when 0 then 'male' else 'female' end
from Person
SELECT alias.*, ROW_NUMBER() OVER (PARTITION BY GENDER ORDER BY GENDER) rnk
FROM TABLE_NAME
ORDER BY rnk, GENDER DESC

MySQL - working out the AVG for a subset of MAX values

I have a table with columns 'Date, Name, Score'.
I wish to get the MAX(Score) for rows which share a common value (for e.g. the same date or even name), before averaging them to give me a figure, for example:
---- Date -----| -- Name -- | Score
2010-10-10 | John Smith | 86
2010-06-05 | Tedi Jones | 71
2010-10-10 | John Smith | 52
2010-06-05 | Tedi Jones | 68
2010-08-08 | Joe Bloggs | 79
2010-10-10 | John Smith | 46
So doing a MAX(Score) on the above would give me 86. However, what I'd like is the following:
MAX(Score) to give me the values 86 (MAX for date 10-10), 79 (MAX for date 08-08) and 71 (MAX for date 06-05) which I can then average to get 78.67. I'm hoping this is possible without having to resort to temp tables?
All replies are appreciated, thank you.
Total average of daily maximal values:
SELECT AVG(dailyMax) AS avgOfDailyMax
FROM (SELECT Date, MAX(Score) AS dailyMax FROM MyTable GROUP BY Date) as DailyMaxTable
and daily maximal values:
SELECT Date, MAX(Score) AS dailyMax
FROM MyTable
GROUP BY Date
select Date, max(Score) as MaxScore
from MyTable
group by Date
If you want the Name as well, do
select m.Date, m.Name, m.Score
from (
select Date, max(Score) as MaxScore
from MyTable
group by Date
) mm
inner join MyTable on mm.Date = m.Date
and mm.MaxScore = m.Score