Adding many to many data to MYSQL tables - mysql

I have three tables (ingredient, recipe, recipe_ingredient) and a csv file with around 4000 rows of recipes :
name, ingredients, time, url,...
Chicken salad, ['chicken', 'lettuce', 'tomato'] ...
The ingredients table is already populated with all ingredients, and has a simple schema (id, name).
Is there an easy way of finding the corresponding ingredient id from its name, and adding the relevant recipe id along with all ingredient ids to recipe_ingredient?

Related

MySQL query in a database of food inventory and recipes

I'm new to mysql and I have to do a kitchen inventory database with recipes for a school project. I'm trying to get a query that shows recipes and users when users have all the ingredients to that recipe. I'm trying to work with the following tables for this query:
Products
ProdID
name (brand included)
tag - FK
Tags (Since there are different brands of products, a tag table to associate each product to a generic type, like orange juice)
TagID
name
Recipes
RecipeID
Name
Description
Ingredients (To associate all the ingredients with each recipe)
IgrID
TagID - FK
RecipeID - FK
Inventory
InvID
UserID
ProductID - FK
QTY
My idea was to get all the ingredients a user have and then check if they complete a recipe, but I don't know how to put together all the tables to get the first part. I tought of doing a join with users ingredients and recipes for the second part, I don't know if it would work though. Maybe the structure I made is unnecessarily complex too. Could anyone give me a hand?

MySQL how to use SET type to select records where a SET contains one or more items from another SET

I have a table called 'recipes' that lists, in a SET type called 'ingredients', all of the foods used in a recipe (recipes are restricted to using a small number of specific ingredients).
recipes table
id (int)
recipeName (text)
ingredients (SET)
I have another table called 'food_types'. Each record has a 'name' field (e.g. 'fruit', 'poultry', 'spices', 'meat', ...) and a SET type called 'items' that holds the ingredients belonging to that food type. E.g. for the 'fruit' record the SET might be 'apple,orange,pear,banana'.
'
food_types table
id (int)
category (text)
items (SET)
My problem is how to create a MySQL query that selects all records from the 'recipes' table that has one or more item from the given 'items' set in the 'ingredients' set.
So in English my query might be:
'Select all recipes where the ingredients contains one or more fruit'
Can anyone suggest a good way to do this with a MySQL query?
NOTE: I appreciate that there are better ways to structure the tables for a recipes/ingredients problem but I am looking for a MySQL query solution that does this with SETs and the tables described above.
This is an inappropriate use of a SET field - you can't add a food_type without having to do a schema modification, always a good indicator that your structure is wrong. Use a join table to represent a many:many relationship. In this case, create a table ingredient_type that refers to both tables with ingredient_id and food_type_id. This also allows you to have ingredients with multiple types, like a SET does, but much more flexible.
ingredient (ingredient):
apple
orange
chicken
ginger
potato
food_type (type):
fruit
vegetable
meat
poultry
spice
ingredient_type (ingredient, type)
apple, fruit
orange, fruit
chicken, meat
chicken, poultry
ginger, vegetable
ginger, spice
potato, vegetable
recipe_ingredient (recipe, ingredient):
recipe1, chicken
recipe1, potato
recipe2, orange
recipe2, ginger
With that structure, you can do queries like this:
SELECT DISTINCT(recipe) FROM recipe_ingredient WHERE ingredient = 'orange';
That will show you all recipes that use oranges. Slightly more complex:
SELECT DISTINCT(recipe) FROM recipe_ingredient JOIN ingredient_type on recipe_ingredient.ingredient = ingredient_type.ingredient WHERE ingredient_type.type = 'fruit';
That will find all recipes that use any ingredient that is a fruit.
EDIT: On using SETs.
You can do this by making use of the binary nature of SET storage. Where there is an overlap between recipe ingredients and category members, the number of set bits in a bitwise AND (using the & operator) will be > 0:
SELECT DISTINCT recipeName FROM recipes JOIN food_types ON BIT_COUNT(food_types.items & recipes.ingredients) > 0 WHERE food_types.category = 'fruit';
This will only work if the ingredients and items set definitions are absolutely identical.
There are other problems with SETs:
they can only contain up to 64 items
field values are always in the same order as the set
most queries other than simple matches (for example to match on a single item within a set) are not indexed
unless definitions are identical, SETs can't be compared
There is nowhere to put additional metadata about each item
This approach defeats most of the point of using a relational database. This is textbook first-normal-form database stuff. The only purpose I can see for a structure like this is to use as an example of how not to do it.

How do i include multiple row reference in one row?

I have table pizza. It includes fields like cost, id, name (of pizza), and ingredients.
I also have table ingredients, with name of ingredient, and id. How to i put in table pizza ingedients for example 1,2,4,15, and be able to get that ingredients name from table ingredients?
Table Pizza:
id name cost ingredients
1 Vegie Pizza 12,59 1,2
Table Ingredients
id name
1 cheese
2 broccoli
3 pepperoni
I would like to get for egzample name and ingredients:
Vegie Piza - cheese, broccoli - 12,59
Or be able to order Vegie Pizza with pepperoni.
How do i connect this two tables in a way I described?
First of all donot store relations as comma separated values instead use junction table to relate 2 entities for this see Database Normalization
For your current solution you need to use find_in_set in join condition
select p.id,group_concat(i.name) ingredients,p.cost
from
Pizza p
join Ingredients i on(find_in_set(i.id,p.ingredients) > 0)
group by p.id
Fiddle Demo
You should have a table PizzaIngredients, with one row per pizza and per ingredient in the table. Someones, one doesn't have control over the data structure being used. If so, there is a solution in MySQL:
select p.name, p.cost, group_concat(i.name)
from pizza p join
ingredients i
on find_in_set(i.id, p.ingredients) > 0
group by p.name, p.cost;
However, a junction/association table is a much better way to store such data in a relational database.

Database normalization with multi table query

I'm trying to create a site related to recipes where users can add custom meals, and within meals they can add foods and then list the ingredients of the foods. For example:
Meal = Dinner
Food = Hamburger
Ingredient = Tomato
Users can select foods from a pre-filled database of food items. They can also add ingredients from a central ingredients database. So the same food and ingredient ids can be used by any user of the site.
The challenge I have is ensuring the food_has_ingredients table is linked to the user somehow. In the diagram below the meal is associated to the user. Since the foods and ingredients ids can be re-used by multiple users I can't rely on those ids to determine which user adds ingredients to a food.
Take this example:
User 1 adds the food "hamburger" (id 10) to the meal_has_food table, then associates the ingredients "ketchup" (id 20) to the food_has_ingredients table.
User 2 adds the food "hamburger" (id 10) to the meal_has_food table, then associates the ingredients "pickles" (id 21) to the food_has_ingredients table.
If someone does a search get all ingredients from the meal hamburger (10) and limit it to one row, it would always give the first person's entry. So I've associated the meal id as a foreign key that way I can say get the ingredient for hamburger that belongs to meal id X.
I'd like to know if that makes sense or if there's a better way.
Here's a rough db schema:

MySQL Database column having multiple values

I had a question about whether or not my implementation idea is easy to work with/write queries for.
I currently have a database with multiple columns. Most of the columns are the same thing (items, but split into item 1, item 2, item 3 etc).
So I have currently in my database ID, Name, Item 1, Item 2 ..... Item 10.
I want to condense this into ID, Name, Item.
But what I want item to have is to store multiple values as different rows. I.e.
ID = One Name = Hello Item = This
That
There
Kind of like the format it looks like. Is this a good idea and how exactly would I go about doing this? I will be using no numbers in the database and all of the information will be static and will never change.
Can I do this using 1 database table (and would it be easy to match items of one ID to another ID), or would I need to create 2 tables and link them?
If so how exactly would I create 2 tables and make them relational?
Any ideas on how to implement this? Thanks!
This is a classical type of denormalized data base. Denormalization sometimes makes certain operations more efficient, but more often leads to inefficiencies. (For example, if one of your write queries was to change the name associated with an id, you would have to change many rows instead of a single one.) Denormalization should only be done for specific reasons after a fully normalized data base has been designed. In your example, a normalized data base design would be:
table_1: ID (key), Name
table_2: ID (foreign key mapped to table_1.ID), Item
You're talking about a denormalized table, which SQL databases have a difficult time dealing with. Your Item field is said to have a many-to-one relationship to the other fields. The correct things to do is to make two tables. The typical example is an album and songs. Songs have a many-to-one relationship to albums, so you could structure your ables like this:
Table Album
album_id [Primary Key]
Title
Artist
Table Song
song_id [Primary Key]
album_id [Foreign Key album.album_id]
Title
Often this example is given with a third table Artist, and you could substitute the Artist field for an artist_id field which is a Foreign Key to an Artist table's artist_id.
Of course, in reality songs, albums, and artists are more complex. One song can be on multiple albums, multiple artists can be on one album, there are multiple versions of the same song, and there are even some songs which have no album release at all.
Example:
Album
album_id Title Artist
1 White Beatles
2 Black Metallica
Song
song_id album_id Title
1 2 Enter Sandman
2 1 Back in the USSR
3 2 Sad but True
4 2 Nothing Else Matters
5 1 Helter Skelter
To query this you just do a JOIN:
SELECT * FROM Album INNER JOIN Song ON Album.album_id = Song.album_id
I don't think one table really makes sense in this case. Instead you can do:
Main Table:
ID
Name
Item Table:
ID
Item #
Item Value
Main_ID = Main Table.ID
Then when you do queries you can do a simple join