SQL join over multiple tables - mysql

With a statement like this, I can get recipe names along with how many
ingredients each one of them has.
SELECT
r.name, COUNT(i.id) as num_ingredients
FROM recipes AS r
LEFT JOIN recipe_ingredients ON r.id = recipe_ingredients.recipe_id
LEFT JOIN ingredients AS i ON recipe_ingredients.ingredient_id = i.id
GROUP BY r.id
How would I add chefs.name to my SELECT along with data that I already have?

Try this
SELECT
r.name, COUNT(i.id) as num_ingredients, che.name AS chefs_name
FROM recipes AS r
LEFT JOIN recipe_ingredients ON r.id = recipe_ingredients.recipe_id
LEFT JOIN ingredients AS i ON recipe_ingredients.ingredient_id = i.id
LEFT JOIN chefs AS che ON r.chef_id = che.id
GROUP BY r.id
If I understood, you would like to JOIN chefs table also and select its name.
You have to alias it in the SELECT statement because you select 2 columns with the same name.
I also think that the data type for column recipes.chef_id should be the same as chefs.id (both int(11) or int(255)).

Related

3 Table Join giving me duplicate records

I'm trying to do a 3 table join and it's giving me duplicate records so I'm unsure what I'm doing incorrectly.
SELECT e.*, cs.*, c.* FROM employee e
LEFT JOIN coffee_shop cs ON e.shop_id = cs.shop_id
LEFT JOIN coffee c ON cs.shop_id = c.shop_id
I want the coffee_shop table to join on the employee table's shop_id and the coffee table to join on coffee_shop's shop_id to perform a 3 table join. However it's giving me duplicate rows (9 rows) when all the tables only have 3 rows each.
How do I perform this join without duplicates?
Edit:
If I do only the join on the first two tables(employee and coffee_shop) it is as expected
I want to perform one more join from coffee onto coffee_shop. Which should also return 3 rows
Here is the result I want:
This will give you 3 rows for your use-case. For each shop_id in the coffee table, this will return the row with the first coffee_id.
Depending on which coffee you want to return, you can adjust the logic for the row_rank field.
SELECT e.*, cs.*, c.*
FROM employee e
LEFT JOIN coffee_shop cs ON e.shop_id = cs.shop_id
LEFT JOIN (
SELECT *,
RANK() OVER(PARTITION BY shop_id ORDER BY coffee_id) as row_rank
FROM coffee
) c ON cs.shop_id = c.shop_id and c.row_rank = 1
Try to use DISTINCT in your query like :
SELECT DISTINCT e.*, cs.*, c.* FROM employee e
LEFT JOIN coffee_shop cs ON e.shop_id = cs.shop_id
LEFT JOIN coffee c ON cs.shop_id = c.shop_id
if your main tables is employee,
SELECT e.*, cs.*, c.* FROM employee e
INNER JOIN coffee_shop cs ON e.shop_id = cs.shop_id
LEFT JOIN coffee c ON cs.shop_id = c.shop_id

when i try to count the number of likes instead it shows the number of ingredients used in the recipe

This is my mysql query
SELECT r.RECIPE_ID as recipe_id,
r.RECIPE_NAME as recipe_name,
r.RECIPE_DESC as recipe_desc,
r.RECIPE_DURATION duration,
group_concat(i.ING_NAME separator ', ') as recipe_ingredients,
rc.CUSINE_NAME as cusine,
rt.RECIPE_TYPE_NAME as type,
r.image ,
count(lr.likecount)
FROM RECIPE_LIST r
inner join likerecipes lr on r.recipe_id = lr.recipe_id
inner JOIN RECIPE_INGLIST ri ON r.RECIPE_ID = ri.recipe_id
inner JOIN ING_LIST i ON ri.ING_ID = i.ING_id and r.RECIPE_ID = ri.recipe_id
inner JOIN RECIPE_CUSINE rc ON r.RECIPE_CUSINE_ID = rc.CUSINE_ID
inner JOIN RECIPE_TYPE rt ON r.RECIPE_TYPE_ID = rt.recipe_typeid
WHERE r.RECIPE_ID >= 1
GROUP BY r.RECIPE_NAME
The output table is displayed below
Image1
But when i remove the ingredients field and all its joins and execute the same query
SELECT r.RECIPE_ID as recipe_id,
r.RECIPE_NAME as recipe_name,
r.RECIPE_DESC as recipe_desc,
r.RECIPE_DURATION duration,
rc.CUSINE_NAME as cusine,
rt.RECIPE_TYPE_NAME as type,
r.image ,
count(lr.likecount)
FROM RECIPE_LIST r
inner join likerecipes lr on r.recipe_id = lr.recipe_id
inner JOIN RECIPE_CUSINE rc ON r.RECIPE_CUSINE_ID = rc.CUSINE_ID
inner JOIN RECIPE_TYPE rt ON r.RECIPE_TYPE_ID = rt.recipe_typeid
WHERE r.RECIPE_ID >= 1
GROUP BY r.RECIPE_NAME
I get the desired result ->
Image 2
Is there any way that i can display the right amount of likes along with the ingredients.
(PS. i know that the first query is showing no. of ingredients instead of likes because when i deduced one of the ingredients the like amount decreased. also the recipes displayed are displayed through a pivot table recipe_inglist joining recipe_list and ing_list table(if that had anything to do with it))
Aggregate the likes before doing the rest of the joins:
FROM RECIPE_LIST r JOIN
(SELECT lr.recipe_id, COUNT(*) as likes
FROM likerecipes lr
GROUP BY lr.recipe_id
) lr
ON r.recipe_id = lr.recipe_id . . .

Cartesian join with multple outer joins to common root

I have the following schema.
I can run two queries fairly simply
select * from booking_model_assignment
join booking_model on booking_model_assignment.booking_model_id = booking_model.id
left outer join axis_channel_mappings on bmi_id = axis_channel_mappings.assignment_id
left outer join axis_revenue_stream_mappings on bmi_id = axis_revenue_stream_mappings.assignment_id
which will give me all of the combinations of channel mappings and 'revenue_stream_mappings' which fit a booking model, with Null if there is one which only matches in one of the tables.
The other query
select * from axis_channel join axis_revenue_stream
Gives all of the possible combinations of channels and revenue streams.
What I would like is a query which will give all of the combinations, and the booking_model if that combination matches.
Any time I try to join or subquery I seem to get too many, or too few results. I think the issue is that I want the assignment_id to match across outer joins but only if there is an outer join.
The schema is laid out like this so it will be possible to add new axis and fit models to combinations, so if there is an easier way to achieve this I would be open to changing the schema.
EDIT
I have a partial solution based on Eggyal's answer but it is not extendable.
SELECT c.*, r.*, GROUP_CONCAT(a.bmi_id), GROUP_CONCAT(b.name) AS booking_models
FROM axis_channel c
CROSS JOIN axis_revenue_stream r
LEFT JOIN axis_channel_mappings cm ON cm.channel_id = c.id
LEFT JOIN axis_revenue_stream_mappings rm ON rm.revenue_stream_id = r.id
LEFT JOIN booking_model_assignment a ON (a.bmi_id = cm.assignment_id
AND a.bmi_id = rm.assignment_id)
OR (a.bmi_id = cm.assignment_id
AND rm.assignment_id IS NULL)
OR (cm.assignment_id IS NULL
AND a.bmi_id = cm.assignment_id)
LEFT JOIN booking_model b ON b.id = a.booking_model_id
GROUP BY c.id, r.id
But if I were to add more axes this query would grow way to cumbersome.
SELECT c.*, r.*, GROUP_CONCAT(b.name) AS booking_models
FROM axis_channel c
CROSS JOIN axis_revenue_stream r
LEFT JOIN axis_channel_mappings cm ON cm.channel_id = c.id
LEFT JOIN axis_revenue_stream_mappings rm ON rm.revenue_stream_id = r.id
LEFT JOIN booking_model_assignment a ON a.bmi_id = cm.assignment_id
AND a.bmi_id = rm.assignment_id
LEFT JOIN booking_model b ON b.id = a.booking_model_id
GROUP BY c.id, r.id

MySQL Join Query (possible two inner joins)

I currently have the following:
Table Town:
id
name
region
Table Supplier:
id
name
town_id
The below query returns the number of suppliers for each town:
SELECT t.id, t.name, count(s.id) as NumSupplier
FROM Town t
INNER JOIN Suppliers s ON s.town_id = t.id
GROUP BY t.id, t.name
I now wish to introduce another table in to the query, Supplier_vehicles. A supplier can have many vehicles:
Table Supplier_vehicles:
id
supplier_id
vehicle_id
Now, the NumSupplier field needs to return the number of suppliers for each town that have any of the given vehicle_id (IN condition):
The following query will simply bring back the suppliers that have any of the given vehicle_id:
SELECT * FROM Supplier s, Supplier_vehicles v WHERE s.id = v.supplier_id AND v.vehicle_id IN (1, 4, 6)
I need to integrate this in to the first query so that it returns the number of suppliers that have any of the given vehicle_id.
SELECT t.id, t.name, count(s.id) as NumSupplier
FROM Town t
INNER JOIN Suppliers s ON s.town_id = t.id
WHERE s.id IN (SELECT sv.supplier_id
FROM supplier_vehicles sv
WHERE sv.vehicle_id IN (1,4,6))
GROUP BY t.id, t.name
Or you could do an INNER JOIN (as your supplier join is INNER, but this will remove towns with no suppliers with those vehicles) and change the COUNT(s.id) TO COUNT(DISTINCT s.id)
If I remember correctly, you can put your second query inside the LEFT OUTER JOIN condition.
So for example, you can do something like
...
LEFT OUTER JOIN (SELECT * FROM Suppler s, Supplier_vehicles ......) s ON s.town_id=t.id
In that way you are "integrating" or combining the two queries into one. Let me know if this works.
SELECT t.name, count(s.id) as NumSupplier
FROM Town t
LEFT OUTER JOIN Suppliers s ON t.id = s.town_id
LEFT OUTER JOIN Supplier_vehicles v ON s.id = v.supplier_id
WHERE v.vehicle_id IN (1,4,6)
GROUP BY t.name

Join expression not supported for inner join with subquery

In Access 2003, I'm getting a "Join expression not supported" exception for this:
SELECT ID FROM Recipes INNER JOIN
(SELECT RecID, COUNT(RecID) AS NumIngredients
FROM Ingredients GROUP BY RecID)
ON RecID = ID
I have two tables, Recipes and Ingredients. Recipes.ID corresponds to foreign key Ingredients.RecID. I want to get the number of rows in Ingredients that correspond to each row in Recipes. Suggestions?
Try without joining on sub-query:
SELECT
r.ID AS RecID,
COUNT(i.ID) AS NumIngredients
FROM
Recipes r
INNER JOIN Ingredients i ON i.RecID = r.ID
GROUP BY
r.ID
Does that work?
SELECT R.ID, COUNT(I.ID) AS CountOfIngredientRecords
FROM Recipes R INNER JOIN Ingredients I
ON R.ID = I.RecID
GROUP BY R.ID