Get rows with maximum sum of 3 columns - Mysql - mysql

I am stuck with some query logic. I have a table called student. Table have the marks of the student of each semester. There is n number of semesters. I need to get the name and id of students with highest maximum mark(mark1+mark2+mark3) in each semester.
This is my table structure
|id| name | mark1| mark2| mark3| sem|
|1 | Harry| 8 | 9 | 9 | 1 |
|2 | John | 10 | 8 | 10 | 1 |
|3 | Derek| 4 | 5 | 8 | 1 |
|4 | Dona | 8 | 9 | 5 | 1 |
|5 | Ammy | 9 | 9 | 9 | 2 |
|6 | Kate | 10 | 7 | 10 | 2 |
|7 | Aby | 3 | 5 | 4 | 2 |
|8 | Eliza| 5 | 9 | 5 | 2 |
Needed output
|id| name | mark1| mark2| mark3| sem| maxmark|
|2 | John | 10 | 8 | 10 | 1 | 28 |
|5 | Ammy | 9 | 9 | 9 | 2 | 27 |
|6 | Kate | 10 | 7 | 10 | 2 | 27 |
MY ATTEMPT TO GET maxmark
SELECT *, (MAX(`mark1` + `mark2` + `mark3`)) AS maxmark
FROM `stud`
GROUP BY `studid`

This query will give you the results you want. It JOINs the student table to a table filled with maximum marks for each semester, only showing students who achieved the maximum mark for that semester (s2.maxmark = s1.mark1+s1.mark2+s1.mark3).
SELECT s1.*, s2.maxmark
FROM student s1
JOIN (SELECT sem, MAX(mark1 + mark2 + mark3) AS maxmark
FROM student
GROUP BY sem) s2
ON s2.sem = s1.sem AND s2.maxmark = s1.mark1+s1.mark2+s1.mark3
Output:
id name mark1 mark2 mark3 sem maxmark
2 John 10 8 10 1 28
5 Ammy 9 9 9 2 27
6 Kate 10 7 10 2 27
SQLFiddle Demo

You have to group by sem to get the maximum marks for each sem in a sub query, once you have the max mark for each sem you could use a IN on a subquery like this,
SELECT *, mark1+mark2+mark3 AS maxmark
from student
where (sem, mark1 + mark2 + mark3) in (
SELECT sem, MAX(mark1 + mark2 + mark3) AS maxmark
FROM student
GROUP BY sem )
output
|id| name | mark1| mark2| mark3| sem| maxmark|
|2 | John | 10 | 8 | 10 | 1 | 28 |
|5 | Ammy | 9 | 9 | 9 | 2 | 27 |
|6 | Kate | 10 | 7 | 10 | 2 | 27 |
you could learn more about in from internet, https://www.techonthenet.com/mysql/in.php
good luck, hope this helped.

Related

Get Percentages of Tables with Group by

I am working on a prediction game for a local league.
A Match is defined by its SPIELTAG (playday) and its MATCH_NR.
A prediction has a Match and a result (ERGA, ERGB)
I have a Table like in this fiddle https://www.db-fiddle.com/f/o4NXPFfzod39LpMaTzqz3r/0
I got the output to count each result per gameday and per match.
| SPIELTAG | MATCH_NR | ERGA | ERGB | AMOUNT |
| -------- | -------- | ---- | ---- | ------ |
| 4 | 1 | 7 | 1 | 1 |
| 4 | 1 | 7 | 2 | 2 |
| 4 | 1 | 7 | 3 | 5 |
| 4 | 1 | 7 | 4 | 1 |
| 4 | 2 | 1 | 7 | 1 |
| 4 | 2 | 2 | 7 | 6 |
| 4 | 2 | 3 | 7 | 3 |
What i am trying to achieve is, next to the amount column something like
| SPIELTAG | MATCH_NR | ERGA | ERGB | AMOUNT | PERC |
| -------- | -------- | ---- | ---- | ------ | ---- |
| 4 | 1 | 7 | 1 | 1 | 11.1%| => 1 / 9
| 4 | 1 | 7 | 2 | 2 | 22.2%| => 2 / 9
| 4 | 1 | 7 | 3 | 5 | 55.5%| => 5 / 9
| 4 | 1 | 7 | 4 | 1 | 11.1%| => 1 / 9
| 4 | 2 | 1 | 7 | 1 | 11.1%| => 1 / 9
| 4 | 2 | 2 | 7 | 5 | 55.5%| => 5 / 9
| 4 | 2 | 3 | 7 | 3 | 33.3%| => 3 / 9
Where PERC is the percentage of picks per playday SPIELTAG. Basically how often is the Result, the tuple of (ERGA, ERGB) predicted for each match SPIELTAG, MATCH_NR.
I found a post where i can get the percentage over all picks but not restricted on the gameday,match tuple.
An Example:
Match 1 (Spieltag 4, Match 1) has 9 Predictions.
1x: 7-1
2x: 7-2
5x: 7-3
1x: 7-4
__
9x -> ALL_COUNTS_PER_MATCH
So PERC should be something like 'AMOUNT' / ALL_COUNTS_PER_MATCH.
I think you need another group by:
SELECT `t`.`SPIELTAG` AS `SPIELTAG`,
`t`.`MATCH_NR` AS `MATCH_NR`,
`t`.`TEAM_A` AS `ERGA`,
`t`.`TEAM_B` AS `ERGB`,
count(0) AS `AMOUNT`,
COUNT(0) / MAX(A.TOTAL_AMOUNT) -- MIN would also work
FROM `TIPPSPIEL_TIPP` `t`
JOIN (
-- Calculate the row count by each different spieltag & match_nr combination
SELECT `t`.`SPIELTAG`,
`t`.`MATCH_NR`,
count(0) AS `TOTAL_AMOUNT`
FROM `TIPPSPIEL_TIPP` `t`
GROUP BY `t`.`SPIELTAG`, `t`.`MATCH_NR`
) A USING (SPIELTAG, MATCH_NR)
GROUP BY `t`.`SPIELTAG`, `t`.`MATCH_NR`, `t`.`TEAM_A`, `t`.`TEAM_B`
;
https://www.db-fiddle.com/f/o4NXPFfzod39LpMaTzqz3r/3
Check this, but will work in Mysql 8, not lower versions
https://www.db-fiddle.com/f/o4NXPFfzod39LpMaTzqz3r/4
SELECT DISTINCT `t`.`SPIELTAG` AS `SPIELTAG`,
`t`.`MATCH_NR` AS `MATCH_NR`,
`t`.`TEAM_A` AS `ERGA`,
`t`.`TEAM_B` AS `ERGB`,
COUNT(0) OVER (PARTITION BY `t`.`SPIELTAG`,
`t`.`MATCH_NR`,
`t`.`TEAM_A`,
`t`.`TEAM_B`) AS AMOUNT,
COUNT(0) OVER (PARTITION BY `t`.`SPIELTAG`,
`t`.`MATCH_NR`,
`t`.`TEAM_A`,
`t`.`TEAM_B`) / COUNT(CONCAT(SPIELTAG, MATCH_NR)) OVER (PARTITION BY `t`.`SPIELTAG`,
`t`.`MATCH_NR`) AS match_count
FROM `TIPPSPIEL_TIPP` `t`

Convert MySQL table from vertical to horizontal based on id column

I have a table like below
id | main_id | image
1 | 10 | 52343.jpg
2 | 10 | 52344.jpg
3 | 10 | 52345.jpg
4 | 11 | 52346.jpg
5 | 11 | 52347.jpg
6 | 11 | 52348.jpg
7 | 11 | 52349.jpg
8 | 12 | 52350.jpg
9 | 12 | 52351.jpg
i want output like this :
id | main_id | image1
1 | 10 | 52343.jpg, 52344.jpg, 52345.jpg
2 | 11 | 52346.jpg, 52347.jpg, 52348.jpg, 52349.jpg
3 | 12 | 52350.jpg, 52351.jpg
Just all images with same main_id to be in one row.
use group_concat()
select main_id,group_concat(image)
from tablename
group by main_id

subtract two column from different table and group by id and id

after two week search i couldn't write this query please help me
NOTE
TABLE 1 sum(quantity_box) group by id_p and id_w
TABLE 2 sum(quantity_box) group by id_p and id_w
then
TABLE1.sum(quantity_box)- TABLE2.sum(quantity_box) where id_p = id_p and id_w = id_w
table 1 ) wherehouseproduct_add id = id_w
id | name
10 | warehouse1
20 | warehouse2
table2) wherehouse_products
id | id_w |id_p |quantity_box
1 | 10 | 2 | 10
2 | 10 | 2 | 50
3 | 20 | 3 | 100
4 | 20 | 1 | 20
5 | 20 | 1 | 10
6 | 10 | 1 | 10
7 | 10 | 3 | 10
table3) wherehouse_products_sell
id | id_w |id_p |quantity_box
1 | 10 | 2 | 50
2 | 20 | 3 | 30
3 | 20 | 1 | 20
table4) products
id_p | product_name
1 | snack
2 | watebottle
3 | headphone
i want to output like
id_w | id_p | product_name| total_quantity_box
10 | 1 | snack |10
10 | 2 | watebottle |10
10 | 3 | headphone |10
20 | 1 | snack |10
20 | 2 | watebottle |10
20 | 3 | headphone |70
Calculate each type of sum individually in sub selects and join them as per your criteria then do your calculations in outer select
select wp.id_w,
wp.id_p,
wp.quantity - wps.quantity total_quantity_box
from
(select id_w,id_p,sum(quantity_box) quantity from wherehouse_products group by id_w,id_p) wp
join
(select id_w,id_p,sum(quantity_box) quantity from wherehouse_products_sell group by id_w,id_p) wps
using(id_w,id_p)
DEMO

Pulling latest values using distinct and max

I have a table that looks like this if I 'select *'
+----+--------+------+------------+
| id | name | task | day |
+----+--------+------+------------+
| 1 | Rodney | 2 | 2016-05-05 |
| 2 | Rodney | 2 | 2016-05-08 |
| 3 | Rodney | 8 | 2016-05-08 |
| 4 | Scott | 2 | 2016-05-05 |
| 5 | Scott | 8 | 2016-05-05 |
| 6 | Frank | 2 | 2016-05-05 |
| 7 | Frank | 2 | 2016-05-08 |
+----+--------+------+------------+
What I'm trying to achive is a query that will get the last entered 'task' for each person. So, in this case I would want back:
2 | Rodney | 2 | 2016-05-08
3 | Rodney | 8 | 2016-05-08
4 | Scott | 2 | 2016-05-05
5 | Scott | 8 | 2016-05-05
7 | Frank | 2 | 2016-05-08
I'm pretty sure I need to use distinct against name & task and max for the most recent entry. Just not sure how to structure the two of them together to get the result.
select distinct name, task from test;
Gets me close...
+--------+------+
| name | task |
+--------+------+
| Rodney | 2 |
| Rodney | 8 |
| Scott | 2 |
| Scott | 8 |
| Frank | 2 |
+--------+------+
But no date...My SQL is limited. Any help would be appreciated.
Aggregate your rows so as to get the latest day per name. Then access the table again to get the records matching thse days:
select *
from test
where (name, day) in
(
select name, max(day)
from test
group by name
);
Another way is to select the records for which not exists a later record for the same name:
select *
from test
where not exists
(
select *
from test later
where later.name = test.name
and later.day > test.day
);

Select rows with alternate ordered field from another table

Given a *students_exam_rooms* table:
+------------+---------+---------+
| student_id | room_id | seat_no |
+------------+---------+---------+
| 1 | 30 | 1001 |
| 2 | 30 | 1002 |
| 3 | 31 | 2001 |
| 4 | 32 | 2002 |
| 5 | 33 | 3001 |
| 6 | 33 | 3002 |
| 7 | 34 | 4001 |
| 8 | 34 | 4002 |
+------------+---------+---------+
And *students_tbl*:
+------------+-------------+------+
| student_id | studen_name | year |
+------------+-------------+------+
| 1 | Eric | 1 |
| 2 | Mustafa | 1 |
| 3 | Michael | 2 |
| 4 | Andy | 2 |
| 5 | Rafael | 3 |
| 6 | Mark | 3 |
| 7 | Jack | 4 |
| 8 | peter | 4 |
+------------+-------------+------+
How can I select from *students_exam_rooms* ordering by *students_tbl.year* but with one after one like this:
+--------------+------+
| student_name | year |
+--------------+------+
| Eric | 1 |
| Michael | 2 |
| Rafael | 3 |
| Jack | 4 |
| Mustafa | 1 |
| Andy | 2 |
| Mark | 3 |
| Peter | 4 |
+--------------+------+
I'm assuming that you want to order by the "occurrence-count" of the year then the year, e.g. all the first-occurrences of all years first, sorted by year, then all second-occurrences of all years also sorted by year, and so on. That would be a perfect case for emulating other RDBMS' analytic / windowing functions:
select *
from (
select
s.studen_name,
s.year,
ser.*,
(
select 1 + count(*)
from students_tbl s2
where s.year = s2.year
and s.student_id > s2.student_id
) rank
from students_tbl s
JOIN students_exam_rooms ser
ON s.student_id = ser.student_id
) i_dont_really_want_to_name_this
order by rank, year
Here it is against a slightly tweaked version of JW's fiddle: http://www.sqlfiddle.com/#!2/27c91/1
Emulating Analytic (AKA Ranking) Functions with MySQL is a good article that gives more background and explanation.
try any of these below:
SELECT a.studen_name, a.year
FROM students_tbl a
INNER JOIN students_exam_rooms b
ON a.student_id = b.student_id
ORDER BY REVERSE(b.seat_no),
a.year
SQLFiddle Demo
by using Modulo
SELECT a.studen_name, a.year
FROM students_tbl a
INNER JOIN students_exam_rooms b
ON a.student_id = b.student_id
ORDER BY CASE WHEN MOD(b.seat_no, 2) <> 0 THEN 0 ELSE 1 END,
a.year
SQLFiddle Demo
Looks to me like you're trying to sort first by seat and then by year. Looking at your students_exam_rooms table, it looks like you started with a simple seat number and prepended year * 1000. So, if we omit the year, it looks like this:
> select * from fixed_students_exam_rooms;
+------------+---------+---------+
| student_id | room_id | seat_no |
+------------+---------+---------+
| 1 | 30 | 1 |
| 2 | 30 | 2 |
| 3 | 31 | 1 |
| 4 | 32 | 2 |
| 5 | 33 | 1 |
| 6 | 33 | 2 |
| 7 | 34 | 1 |
| 8 | 34 | 2 |
+------------+---------+---------+
And if you had that table, your query is simple:
select
student_name, year
from
modified_student_exame_rooms
left join students_tbl using (student_id)
order by
seat_no, year
;
Using the table as you currently have it, it's only slightly more complicated, assuming the "core seat number" doesn't excede 999.
select
student_name, year
from
modified_student_exame_rooms
left join students_tbl using (student_id)
order by
convert(substr(seat_no, 2), unsigned),
year
;