Database normalization with multi table query - mysql

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:

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?

Adding many to many data to MYSQL tables

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?

MySQL design and relations

I'm creating one project for restaurants where user can browse and choose food. I didn't made before such a think and have some troubles with design and relations in database tables. This is the case
1. Restaurants
2. Customer click on restaurant-1
3. Customer get menu list for foods and drinks
4. Customer browse the food via sub-categories ( Salads, Drinks, Desserts and so on )
5. Customer choose some food and drinks...
As I can see here I would need 4 main tables restaurants, meals, meal_types and menu. Table Restaurants will hold restaurants
id
name
menu
image
text
address
Table Meal_types will hold main meal category - Drinks, Salads, Desserts and so on
id
name
Table meals will hold all foods/drinks
id
name
image
text
weigh
price
Table menu must keep which food/drinks to which restaurant to show when is selected.
id
name
So here is the tricky/hard part for me. How to make relations between them. One of the relations that I see and must have is between meals and meal_types. But others? How to connect restaurants with them and when user click on some restaurant to see the food that is served only from this restaurant. First thought for me was with this table menu but don't know how exactly.
I found it easier to Name the ids according to the items they represent. So I would suggest to Name the column id in your table restaurant Restaurant_id. This might help you Keep the general view in your relations.
Start from your smallest part: Your table meals. You have to combine this table with your Meal_types table since you have a 1:1 relationship between both (each meal has exactly one type, so just add another colum meal_type to meals).
Second you have your restaurants.
Now you just need an Information about the meals a Restaurant offers. This Translation table is your table menue and holds columns like this:
Restaurant_id,
Meal_id
To get the menue of a certain Restaurant you would query
SELECT
meals.meal_type, meals.name, meals.price
FROM
restaurant, menue, meals
WHERE
Restaurant.restaurant_id = menue.restaurant_id
AND menue.meal_id = meals.meal_id
AND Restaurant.name = 'Mc Donald's'

Database Design: product and product combo

Say I am selling a number of product. Sometimes, the product is actually a combination of other product. For example, say I am selling a:
hot dog
soda
hot dog + soda combo
How should I model something like this? Should I have a product table to list the individual products, then a product_combo table that describes the combo, and another table that is associated with product and product_combo to itemize the products in the combo? This seems straightforward to me.
However, what if I wanted to record all the sales in one table? Meaning, I don't want product_sales table and a product_combo_sales table. I want all sales to be in just one table. I'm a bit unsure how to model product and product combos in such a way I can later record all sales in one table.
Suggestions?
NOTE: I'm wondering if I could put product and product combo in one table using a parent-child relationship. With one table, then recording sales won't be hard. I'd just have to implement a business rule that editing a product combo when a sale is already recorded against that combo that the edit actually results in a new entry. Could get messy, though.
This depends on what you actually need to do with your system. A system that needs to track inventory is going to need to understand that a "combo meal" needs to debit the inventory by one hot dog and 32 ounces of soda (or whatever). A system that only keeps track of orders and dollars, however, doesn't really care about what "goes into" the combo meal -- only that you sold one and got paid for it.
That said, let's assume you need the inventory system. You can reduce your complexity by changing your definition a little bit. Think in terms of (1) inventory items and (2) menu items. Your inventory_items table contains items that you purchase and track as inventory (hot dogs, soda, etc). Your menu_items table contains items that you sell (Big Dog Combo Meal, Hot Dog (sandwich only), etc).
You can have some menu items that, coincidentally, have the same name as an inventory item but for these menu items treat them the same way you do a combo item and stick a single record into the linking table:
inventory_items menu_items recipes (menu_item, inventory, qty)
--------------- ------------ ----------
hot dog Hot Dog Hot Dog, hot dog, 1
hot dog bun Hamburger Hot Dog, hot dog bun, 1
hamburger patty (4oz) Big Dog Combo Hamburger, hamburger patty (4oz), 1
hamburger bun Soda (32oz) Hamburger, hamburger bun, 1
cola Big Dog Combo, hot dog, 1
ginger ale Big Dog Combo, hot dog bun, 1
Big Dog Combo, *soda, 32
Soda (32oz), *soda, 32
Just constructing this example, it turns out that even the lowly hot dog has two components (you have to count the bun), not just one. To come up with the simplest case (a menu item with a single component), I added Soda to the menu. Consider, however, that if you are going to inventory non-food items (cups) then even a simple Soda is going to have two components (three if you're inventorying the straws).
Note that with this design there will be no special codepaths for handling combo items and non-combo items. All menu-related functionality will use only the menu_items table, all inventory and food-prep related functionality will JOIN menu_items to recipes and (if additional fields are needed) to inventory_items.
You'll need special handling for optional components (sauerkraut, relish, chili, etc) and for components that can be selected from different inventory items (represented as *soda in this model), but this should get you started.
Both you're approaches are OK. But there's at least one other way to solve the problem which is to apply discounts to product combinations (which means you can also apportion the discount selectively) e.g.
CREATE TABLE products
(
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(128),
description TEXT,
price INT
);
CREATE TABLE combo_discounts
(
id NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(128),
description TEXT
);
CREATE TABLE cd_products
(
cd_id INT /* REFERENCES combo_discounts.id */,
p_id INT /* REFERENCES product.id */
price_reduction INT
);
CREATE TABLE sales
(
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
location ...whatever...
);
CREATE TABLE sales_items
(
sale_id INT /* REFERENCES sales.id */
p_id INT /* REFERENCES product.id */
cd_discount INT /* REFERENCES cd_products.cd_id */
);
But bear in mind that you'll need to use procedural code to assign the discounts the sale (and flag each sold item as you go) to address the problem of someone buying 2 hot dogs and one soda (and hence only getting one discount).
...and hence the total price for a sale is
SELECT SUM(p.price)-SUM(cd.price_reduction)
FROM sales s INNER JOIN sales_items si ON (si.sale_id=s.id)
LEFT JOIN cd_products cdp ON (si.cd_discount = cdp.cd_id
AND si.p_id=cdp.p_id)
AND s.id=?
I suggest you think in terms of "orders" and "items". An Order consists of many items. Items can be different "products". So, examples for Orders can be:
1) hot dog
2) soda
3) hot dog + soda
Examples for Items can be:
A) hot dog
B) soda
Also this way you can keep sales, in the orders table.
I don't think you need to have the prises for the "combo" in your database.
This is business logic that should be applied in the code, not in database.
You can apply all your discounts later in the code.

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