MySQL join on max value - mysql

From joining the tables below on the entry.id, I want to extract the rows from the food_brands table which have the highest type_id - so I should be getting the top 3 rows below, with type_id 11940
food_brands
id brand type_id
15375 cesar 11940
15374 brunos 11940
15373 butchers 11940
15372 bakers 11939
15371 asda 11939
15370 aldi 11939
types
id type quantity food_id
11940 comm 53453 10497
11939 comm 999 10496
foods
id frequency entry_id
10497 twice 12230
10496 twice 12230
10495 once 12230
entries
id number
12230 26
My attempt at the query isn't filtering out the lower type.id records - so from the table records below in food_brands, i'm getting those with type_id 11940 and 11939. Grateful for any help fix this!
SELECT fb.*
FROM food_brands fb
INNER JOIN types t ON fb.type_id = t.id
INNER JOIN
(
SELECT MAX(id) AS MaxID
FROM types
GROUP BY id
) t2 ON t.food_id = t2.food_id AND t.id = t2.MaxID
INNER JOIN foods f ON t.food_id = f.id
INNER JOIN entries e ON f.entry_id = e.id
WHERE entries.id = 12230

A simple subquery should do it just fine;
SELECT * FROM food_brands WHERE type_id=
(SELECT MAX(t.id) tid FROM types t
JOIN foods f ON f.id=t.food_id AND f.entry_id=12230)
An SQLfiddle to test with.

If you just want to return the rows from food_brands with the max type id, you should be able to use:
SELECT fb.*
FROM food_brands fb
INNER JOIN
(
select max(id) id
from types
) t
on fb.type_id = t.id
See SQL Fiddle with Demo

I don't know why you are doing all these inner joins after the one on the t2 subquery, since you are only retrieving the columns of fb, but I suppose that you are not showing the whole query, and you just want to get that one fixed.
The issue is actually in the subquery t2: there, for some untold reason, you choose to do a GROUP BY id which changes the MAX function semantic to generate a maximum value per id, and since you are asking the maximum on that very column, MAX and GROUP BY cancel out each other. Just removing the GROUP BY clause fixes the query.
If for some untold reason you cannot remove that clause, perhaps replacing MAX(id) by id and adding ORDER BY id DESC LIMIT 1 would do.
Also, your subquery should probably select also food_id since it is used in the subsequent INNER JOIN clause.

Related

Use SELECT through three table

I tried to write a query, but unfortunately I didn't succeed.
I want to know how many packages delivered over a given period by a person.
So I want to know how many packages were delivered by John (user_id = 1) between 01-02-18 and 28-02-18. John drives another car (another plate_id) every day.
(orders_drivers.user_id, plates.plate_name, orders.delivery_date, orders.package_amount)
I have 3 table:
orders with plate_id delivery_date package_amount
plates with plate_id plate_name
orders_drivers with plate_id plate_date user_id
I tried some solutions but didn't get the expected result. Thanks!
Try using JOINS as shown below:
SELECT SUM(o.package_amount)
FROM orders o INNER JOIN orders_drivers od
ON o.plate_id=od.plate_id
WHERE od.user_id=<the_user_id>;
See MySQL Join Made Easy for insight.
You can also use a subquery:
SELECT SUM(o.package_amount)
FROM orders o
WHERE EXISTS (SELECT 1
FROM orders_drivers od
WHERE user_id=<user_id> AND o.plate_id=od.plate_id);
SELECT sum(orders.package_amount) AS amount
FROM orders
LEFT JOIN plates ON orders.plate_id = orders_drivers.plate_id
LEFT JOIN orders_driver ON orders.plate_id = orders_drivers.plate_id
WHERE orders.delivery_date > date1 AND orders.delivery_date < date2 AND orders_driver.user_id = userid
GROUP BY orders_drivers.user_id
But seriously, you need to ask questions that makes more sense.
sum is a function to add all values that has been grouped by GROUP BY.
LEFT JOIN connects all tables by id = id. Any other join can do this in this case, as all ids are unique (at least I hope).
WHERE, where you give the dates and user.
And GROUP BY userid, so if there are more records of the same id, they are returned as one (and summed by their pack amount.)
With the AS, your result is returned under the name 'amount',
If you want the total of packageamount by user in a period, you can use this query:
UPDATE: add a where clause on user_id, to retrieve John related data
SELECT od.user_id
, p.plate_name
, SUM(o.package_amount) AS TotalPackageAmount
FROM orders_drivers od
JOIN plates p
ON o.plate_id = od.plate_id
JOIN orders o
ON o.plate_id = od.plate_id
WHERE o.delivery_date BETWEEN convert(datetime,01/02/2018,103) AND convert(datetime,28/02/2018,103)
AND od.user_id = 1
GROUP BY od.user_id
, p.plate_name
It groups rows on user_id and plate_name, filter a period of delivery_date(s) and then calculate the sum of packageamount for the group

Get a row which has the maximum id

Problem in simple words, 1st must be left joined to the 2nd table where the record is latest. So, I use an approach of using function MAX()
Currently I have 2 tables.
matches
matches_payments
|
Now I want to join the second table to first one using MAX(id) on matches_payments
Desired result
but I am not getting desired result due to greatest-n-per-group problem.
Query
SELECT matches.id, mp.*
FROM matches
LEFT JOIN (SELECT
MAX(id) AS id,
match_id
paymentStatus
FROM matches_payments
GROUP BY match_id) AS mp ON mp.id = matches.id;
Desired result is not produced due to : Stackoverflow Question
When using this feature, all rows in each group should have the same values for the columns that are ommitted from the GROUP BY part. The server is free to return any value from the group, so the results are indeterminate unless all values are the same.
FROM MySQL Dev
PS : I know the tables are poorly designed. It is not my work as the last developer did those.
You need two joins. You need a self-join of the matches_payments table to get the row with the highest ID for each match_id, as shown in SQL Select only rows with Max Value on a Column. Then you LEFT JOIN this to matches to combine the two tables:
SELECT m.*, mp.paymentStatus, mp.paymentAmount
FROM matches AS m
LEFT JOIN (
SELECT mp1.*
FROM matches_payments AS mp1
JOIN (SELECT match_id, MAX(id) AS id
FROM matches_payments
GROUP BY match_id) AS mp2
ON mp1.match_id = mp2.match_id AND mp1.id = mp2.id
) AS mp ON mp.match_id = m.id

mysql Left Join, group by with count

I have two tables - one for courses and one for people attending the course.
Both are joined by course_id
table 1: firstaid - has all the course names
table 2: first_aid_att - records attendees and captures first aid
course id
I would like to get a count of attendees per course.
I have got a join working but don't know how to do the group by and count.
SELECT *
FROM firstaid
LEFT JOIN first_aid_att ON firstaid.course_id = first_aid_att.course_id
ORDER BY `sortDate` ASC
Try this:
SELECT f1.*, COUNT(f2.course_id)
FROM firstaid f1
LEFT JOIN first_aid_att f2 ON (f1.course_id = f2.course_id)
GROUP BY f1.course_id
ORDER BY f2.sortDate

MySQL's count(*) doesn't work properly

I want to count all rows from the game_votes where g_id is equal to 14, it is working almost good, but if there aren't any records with g_id = 14 it does still show 1 in the cnt field.
Here is my query:
SELECT
SUM(vote) as vote,
COUNT(*) as cnt
FROM (`games`)
LEFT JOIN `game_votes`
ON
`game_votes`.`g_id` = `games`.`id`
WHERE `games`.`id` = '14'
Whats wrong? Am I missing something?
You're getting a count of 1 because COUNT(*) essentially counts the number of rows in your result set. Since you're selecting a row out of your games table with an id of 14 and left joining that to the game_votes table, you're going to always have 1 or more rows as long as there exists a game with an id of 14 regardless of whether or not it contains any corresponding votes in your game_votes table. Instead of COUNT(*), try COUNT(game_votes.g_id). If there are no votes, the g_id field will contain a null value, and COUNT() will not include a null value in its calculation.
Check the result of
SELECT *
FROM (`games`)
LEFT JOIN `game_votes`
ON
`game_votes`.`g_id` = `games`.`id`
WHERE `games`.`id` = '14'
and you will see that your using LEFT JOIN (instead of JOIN) is the cause.
SELECT SUM(vote) as vote, COUNT(*) as cnt from games,game_votes where game_votes.g_id=games.id and games.id=14;
This should work
The MySQL SUM function requires a GROUP BY ... see http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html

query to join a table with two fields into one list containing items in both fields

Looking at similar questions, I actually want the exact opposite of this:
SQL query for getting data in two fields from one column
I have a table meetings with paired users:
A_user_id | B_user_id
1 2
3 4
There is a user table as well.
Is there a simple mysql query that lists all the user_ids into one long list?
query result
1
2
3
4
I was thinking something like this but it doesn't work:
select *
from user
where user.id in (
(select A_user_id from meeting)
or
(select B_user_id from meeting)
)
Thanks!
UPDATE (UNION solved this, but let's make this a bit more challenging):
I want to get a list of usernames and location names (both are reference tables) so I need to join this union query to them. Here's what I tried:
select u1.fname, l1.name
from meeting m1
join user u1 on m1.A_user_id=u1.id
join locations l1 on m1.location_id=l1.id
union
select u2.fname, l2.name
from meeting m2
join user u2 on m2.A_user_id=u2.id
join locations l2 on m2.location_id=l2.id
order by location_id asc
I'm getting two errors:
1- Not sure what kind of joins I need on these. (without the last 'order by' line) I'm getting a list of only 2 (there should be 4, as there are 2 pairs of people meeting). It seems to be pulling only the first item from each part of the union. I believe this relates to the type of join I'm doing for each, but not sure. So, users are distinct (there is only 1 user in the meeting table and it matches only 1 user in the user table), but locations are not (2 users are meeting at 1 location, and I think when I join on locations it is messing things up).
2- How do I use the "order by" at the end to order by the resulting list of "location_id"s, since now I have two named tables to deal with.
Thanks!
UPDATE 2:
Ok I put the two selects into parenthesis and UNIONed them and now I can order by the location_id... but I still have no idea how to join on the location table. Mysql doesn't like what I tried
(select u1.fname, m1.location_id
from meeting m1
join user u1 on m1.A_user_id=u1.id)
union
(select u2.fname, m2.location_id
from meeting m2
join user u2 on m2.B_user_id=u2.id)
#join locations l on l.id = location_id // this line messes things up *
order by location_id asc
Doesn't there need to be an all encompassing select around this whole thing?
How do I join the locations.id field on the "location_id" field that gets kicked off of the union query? Since the "location_id" field is technically in two different tables?
THe join above throws an error.
UPDATE 3: SOLVED
Here's my final query:
select tb1.fname, l.name
from (
(select u1.fname, m1.location_id
from meeting m1
join user u1 on m1.A_user_id=u1.id)
union
(select u2.fname, m2.location_id
from meeting m2
join user u2 on m2.B_user_id=u2.id)
) tb1
join locations l on l.id = tb1.location_id
order by location_id asc
select A_user_id as id from meetings
union
select B_user_id as id from meetings
in your example code, you could use an 'or', but the 'or' has to join two 'in' statements, if you get what I mean.
select *
from user
where
(
(user.id in (select A_user_id from meeting))
or
(user.id in ((select B_user_id from meeting))
)
And to answer you second update, you want something like
select locations.* from
(
(select A_user_id as id from meeting)
union
(select B_user_id as id from meeting)
) as UIDS
join
locations on locations.id = UIDS.id
select A_user_id as user_id from meetings
union all
select B_user_id as user_idfrom meetings
order by user_id
Notes:
UNION ALL keeps duplicates, UNION doesn't
Any ORDER BY goes at the end of the UNION