Add total of 3 rows for specific id - mysql

I have three tables:
Students
-------------------------------------------------------------
studentId first last gender weight
-------------------------------------------------------------
1 John Doe m 185
2 John Doe2 m 130
3 John Doe3 m 250
Lifts
-------------------
liftId name
-------------------
1 Bench Press
2 Power Clean
3 Parallel Squat
4 Deadlift
5 Shoulder Press
StudentLifts
------------------------------------------------
studentLiftId studentId liftId weight
------------------------------------------------
1 1 1 185
2 2 3 130
3 3 1 190
4 1 2 120
5 2 1 155
6 3 2 145
7 1 1 135
8 1 1 205
9 2 3 200
10 1 3 150
11 2 2 110
12 3 3 250
I would like to have four top lists:
Bench Press
Parallel Squat
Power Clean
Total of the above 3
I can successfully grab a top list for each specific lift using the following query:
SELECT s.studentId, s.first, s.last, s.gender, s.weight, l.name, sl.weight
FROM Students s
LEFT JOIN (
SELECT *
FROM StudentLifts
ORDER BY weight DESC
) sl ON sl.studentId = s.studentId
LEFT JOIN Lifts l ON l.liftId = sl.liftId
WHERE l.name = 'Bench Press'
AND s.gender = 'm'
AND s.weight > 170
GROUP BY s.studentId
ORDER BY sl.weight DESC
However, I am stuck on how to add the highest total of each lift for each student. How can I first find the highest total for each student in each lift, and then add them up to get a total of all three lifts?
Edit
The result set that I am looking for would be something like:
-------------------------------------------------
studentId first last weight
-------------------------------------------------
3 John Doe3 585
1 John Doe 475
2 John Doe2 465
I also forgot to mention that I would actually like two lists, one for students above 170 and one for students below 170.

SELECT -- join student a total weight to the student table
A.studentId,
A.first,
A.last,
C.totalWeight
FROM
Student A,
(
SELECT -- for each studet add the max weights
sum(B.maxWeight) as totalWeight,
B.studentID
FROM (
SELECT -- for each (student,lift) select the max weight
max(weight) as maxWeight,
studentId,
liftID
FROM
StudentLifts
GROUP BY
studentId,
liftID
) B
GROUP BY
studentId
) C
WHERE
A.studentID = C.studentId
-- AND A.weight >= 170
-- AND A.weight < 170
-- pick one here to generate on of the two lists.

Related

multiple selects with different where conditions and limits

I have a high scores table that is slightly more complicated because scores are tracked in rounds (round 1, round 2, round 3, etc.). Sample table:
scoreID
roundID
userID
score
1
1
2
25
2
1
3
12
3
1
4
14
4
1
5
6
5
2
2
39
6
2
3
23
7
2
4
13
8
2
5
26
There can be many more rounds, and many more users.
I would like to pull the top 3 user scores from each round. My select statement at the moment looks like this:
select `scores`.`score`, `users`.`username`, `scores`.`roundID`
FROM `scores`
INNER JOIN `users` on `users`.`user_id` = `scores`.`userID`
ORDER BY `scores`.`score` DESC LIMIT 3;
However, this returns a result like so:
score
username
roundID
39
joey
2
26
bubba
2
25
george
1
when what I want is the top 3 scores per round:
score
username
roundID
25
george
1
14
bubba
1
12
joey
1
39
george
2
26
homey
2
23
joey
2
How do I select the top 3 scores in each round so my result mirrors the table immediately above?
You would do this like:
select score, username, roundID
from (
select
score, userID, roundID,
rank() over (partition by roundID order by score desc) score_rank
from score
) ranked_scores
inner join users on users.user_id = ranked_scores.userID
where score_rank <= 3
order by roundID, score, username

SQL JOIN two tables & second table only gets latest entry & with 2 ids

I have 2 tables.
MARKET TABLE
ID main_key sub_key name created_at
------------------------------------------------------
1 1 1 bottle 1606636000
2 2 1 flask 1606642546
3 2 2 flask 1606650045
4 3 1 can 1606650445
5 3 2 can 1606651546
6 4 1 glass 1606652545
MARKET_UPDATES TABLE
ID main_key sub_key price update
------------------------------------------------------
1 1 1 100 1606665555
2 2 1 120 1606665555
3 2 2 150 1606665555
4 3 1 500 1606665555
5 3 2 550 1606665555
6 4 1 25 1606665555
7 1 1 110 1606665666
8 2 1 135 1606665666
9 2 2 145 1606665666
10 3 1 490 1606665666
11 3 2 440 1606665666
12 4 1 29 1606665666
I've tried this.
SELECT *
FROM market m
JOIN (
SELECT MAX(id) max_id, fk_main_key
FROM market_update
GROUP BY fk_main_key, sub_key
) m_max ON (m_max.fk_main_key = m.main_key)
JOIN market_update mu ON (mu.id = m_max.max_id)
But it multiples it a lot of times and I end up with a lot of the same lines. I think it multiples main_key amount and sub_key amount.
I am trying to JOIN MARKET_UPDATES into MARKET so I can get the latest prices from MARKET_UPDATES, but my issue is that I have 2 id's that I have to check on, main_key & sub_key.
So I have to merge the MARKET table with id(7-12) in MARKET_UPDATES.
here is one way based on your query :
SELECT *
FROM market m
JOIN (
SELECT MAX(id) max_id , fk_main_key, sub_key
FROM market_update
GROUP BY fk_main_key, sub_key
) m_max
ON (m_max.fk_main_key = m.main_key
and m_max.sub_key = m.sub_key)
JOIN market_update mu ON (mu.id = m_max.max_id)
and here is another way using window function RANK() :
SELECT *
FROM market m
JOIN (
SELECT id
, fk_main_key
, sub_key
, rank() over (partition by fk_main_key, sub_key order by id desc ) rnk
FROM market_updat
) mu
ON mu.fk_main_key = m.main_key
and mu.sub_key = m.sub_key
and rnk = 1

MYSQL Stuck Generating temp table (massive query)

I have 4 tables (1 to many):
Dont say anything about that "email" relation. It is how my developer boss built it years ago.
EMPLOYEES (+-50 results)
------------------------------------------------
id name
1 EmpName 1
2 EmpName 2
CUSTOMERS (+50k results)
------------------------------------------------
id name email employee_assigned
1 John john#doe.com 12
2 Donald donald#duck.com 6
INTERESTS_CATEGORIES (+650k results)
------------------------------------------------
id customer_email category_id
1 john#doe.com 97
2 john#doe.com 13
3 donald#duck.com 56
4 donald#duck.com 126
5 donald#duck.com 45
INTERESTS_PRODUCTS (+650k results)
------------------------------------------------
id customer_email product_id
1 john#doe.com 78
2 john#doe.com 23
3 donald#duck.com 19
4 donald#duck.com 56
5 donald#duck.com 45
So I need to filter the customers by their assigned employee and their interests.
And here is the query:
SELECT
*
FROM
(
SELECT
customers.id AS 'id',
customers.name AS 'first_name',
customers.email,
employees.id AS 'employee_id'
FROM
customers,
employees
WHERE
employees.id = 2
AND
customers.employee_assigned = employees.id
) AS myCustomers
LEFT JOIN interests_categories
ON interests_categories.customer_email = myCustomers.email
LEFT JOIN interests_products
ON interests_categories.customer_email = myCustomers.email
WHERE
(
interests_categories.category_id = 20
OR
interests_categories.category_id = 21
)
GROUP BY myCustomers.email
So, the problem:
If the employee has a low number of assigned customers (like 3) query
is successfull.
If the employee has a medium-high number of assigned customers (over 100) query stucks.
I execute SHOW PROCESSLIST and it is stucked "Generating temp table".
Anyone has idea? :(
Thank you.
Check the indexes on your tables and try this:
SELECT
c.id AS 'id',
c.name AS 'first_name',
c.email,
e.id AS 'employee_id'
ic.*,
ip.*
FROM customers c
JOIN employees e
ON c.employee_assigned = e.id
LEFT JOIN interests_categories ic
ON ic.customer_email = c.email
LEFT JOIN interests_products ip
ON ic.customer_email = c.email
WHERE
(
ic.category_id IN (20,21)
AND e.id = 2
)
GROUP BY myCustomers.email
Incidentally, a less dumb design might look like as follows. If it was me, I'd start with this, and provide properly representative CREATE and INSERT statements accordingly. Also, I'm curious about where category_id comes from - because that's potentially an area for further optimization.
EMPLOYEES
------------------------------------------------
employee_id name
6 EmpName 1
12 EmpName 2
CUSTOMERS
------------------------------------------------
customer_id name email employee_assigned
1 John john#doe.com 12
2 Donald donald#duck.com 6
INTERESTS_CATEGORIES
------------------------------------------------
customer_id category_id
1 97
1 13
2 56
2 126
2 45
INTERESTS_PRODUCTS
------------------------------------------------
customer_id product_id
1 78
1 23
2 19
2 56
2 45

table joins with multiple group_concat

I have a problem regarding joining tables with group_concat. Here are the details.
table_orders:
item_cd order_id descs quantity status seq_no
1 100 coca-cola 2 A 232
2 100 pizza 1 A 233
3 101 cheeseburger 5 A 234
4 102 pepsi 4 A 235
4
table_instructions:
item_cd instruction
3 more cheese
3 less vegetable
cancelled_item_table:
quantity seq_no
1 234
1 234
1 235
Now what I want to achieve is like this:
item_cd descs quantity instructions cancelled_item
1 coca-cola 2 - -
2 pizza 1 - -
3 cheeseburger 2 more cheese, less vegetable 1,1
4 pepsi 4 - 1
This is my current query:
SELECT
ord.item_cd,
ord.order_id,
ord.descs,
ord.quantity,
GROUP_CONCAT(x.quantity) as cancelled,
GROUP_CONCAT(i.instruction) as instruct
FROM table_orders ord
LEFT JOIN cancelled_item_table x ON ord.seq_no = x.seq_no
LEFT JOIN table_instructions i ON ord.item_cd = i.item_cd
WHERE ord.status = 'A'
GROUP BY ord.order_id
and here is the output:
item_cd descs quantity instructions cancelled_item
1 coca-cola 2 - 1
2 pizza 1 - 1
3 cheeseburger 2 more cheese, more cheese,
less vegetable, less vegetable 1,1,1,1
4 pepsi 4 - 1
If you notice, cheeseburger has 2 cancelled item and 2 instruction, but the output is 4, looks like it's multiplying.
Since the join with cancelled_item_table multiplies rows, you have to join to an already grouped subquery, like this:
SELECT
ord.item_cd,
ord.order_id,
ord.descs,
ord.quantity - coalesce(x.tot,0) as quantity,
GROUP_CONCAT(i.instruction) as instruct,
x.cancelled
FROM
table_orders ord LEFT JOIN table_instructions i
ON ord.item_cd = i.item_cd LEFT JOIN
(select seq_no, count(*) as tot, GROUP_CONCAT(quantity) as cancelled
from cancelled_item_table
group by seq_no) x ON ord.seq_no = x.seq_no
WHERE ord.status = 'A'
GROUP BY ord.item_cd, ord.order_id, ord.descs, quantity

MySQL get top average entries

I am trying to write a mysql query to return the top 3 courses that have the highest average course rating. I have two tables, Ratings and Courses.
The Ratings table:
courseId rating
1 6
2 2
1 4
2 5
3 3
4 0
6 0
The Courses Table:
courseId cnum cname
1 100 name1
2 112 name2
3 230 name3
4 319 name4
5 122 name5
6 320 name6
I need to return the top 3 courses that have the highest average rating. Any ideas how I could do this? Thanks
SELECT Courses.*
FROM Courses NATURAL JOIN (
SELECT courseId, AVG(rating) avg_rating
FROM Ratings
GROUP BY courseId
ORDER BY avg_rating DESC
LIMIT 3
) t
See it on sqlfiddle.