Bear with me, im really bad at explaining thing and i dont even know an appropriate title for this problem
Ok guys i have this problem
I already have one table name meal
+------+--------+-----------+---------+
| id | name | serving | price |
+------+--------+-----------+---------+
| 1 | soup1 | 2 person | 12.50 |
+------+--------+-----------+---------+
| 2 | soup2 | 2 person | 15.50 |
+------+--------+-----------+---------+
| 3 | soup3 | 2 person | 23.00 |
+------+--------+-----------+---------+
| 4 | drink1 | 2 person | 4.50 |
+------+--------+-----------+---------+
| 5 | drink2 | 2 person | 3.50 |
+------+--------+-----------+---------+
| 6 | drink3 | 2 person | 5.50 |
+------+--------+-----------+---------+
| 7 | frui1 | 2 person | 3.00 |
+------+--------+-----------+---------+
| 8 | fruit2 | 2 person | 3.50 |
+------+--------+-----------+---------+
| 9 | fruit3 | 2 person | 4.50 |
+------+--------+-----------+---------+
Ok now i want to allow admin to create a combo meal from this meal table
So that mean, a combo meal can have unlimited number amout of meal
Currently im puzzle how to store/link combo meal to the meal
I donw want to store something lke below
+------+--------------+-----------+-----------+
| id | combo_name | serving | meal_id |
+------+--------------+-----------+-----------+
| 1 | combo1 | 2 person | 1,4,7,9 |
+------+--------------+-----------+-----------+
| 2 | combo2 | 2 person | 2,5,8 |
+------+--------------+-----------+-----------+
| 4 | combo3 | 2 person | 3,5,6,9 |
+------+--------------+-----------+-----------+
Look at the meal_id column, i dont think that is a good way to store a data
Create a many-to-many link table:
combo_id meal_id
1 1
1 4
1 7
1 9
2 2
2 5
2 8
3 3
3 5
3 6
3 9
To select all meals for a given combo:
SELECT m.*
FROM combo_meal cm
JOIN meal m
ON m.id = cm.meal_id
WHERE cm.combo_id = 1
No. It's definitely not a good way to store data. You will be better with a combo_header table and a combo_details table.
combo_header will be something like:
+------+--------------+-----------+
| id | combo_name | serving |
+------+--------------+-----------+
| 1 | combo1 | 2 person |
+------+--------------+-----------+
| 2 | combo2 | 2 person |
+------+--------------+-----------+
| 4 | combo3 | 2 person |
+------+--------------+-----------+
And then, combo_details will be something like:
+------+-----------+
| id | meal_id |
+------+-----------+
| 1 | 1 |
+------+-----------+
| 1 | 4 |
+------+-----------+
| 1 | 7 |
+------+-----------+
| 1 | 9 |
+------+-----------+
... / you get the idea!
By the way, by using multiple values in a single column you are violating first normal form of relational databases.
The way I'm proposing will let you answer queries like get all name of the meals of combo1 very easy to resolve.
This is called a many-to-many relationship between meals and combo. A meal can be listed in multiple combos and a combos can contain multiple meals. You will need a link table (instead of the combo.meal_id field) that contains all possible meal-combo pairs.
In the end, you will have three tables:
meal (meal_id, serving, name)
combo (combo_id, serving, name)
meal_combo (autoid, meal_id, combo_id)
meal_combo.autoid is not strictly needed, it's just a general recommendation.
To list a combo with all it's meals in it:
SELECT meal.id, meal.name FROM comboINNER JOIN meal_combo ON meal_combo.combo_id = combo.id INNER JOIN meal ON meal.id = meal_combo.meal_id WHERE combo.id = 132
Google for 'many-to-many relationship' or 'database link table' for details.
Related
This question already has answers here:
Many-to-many relationships examples
(5 answers)
Closed 1 year ago.
I have a mySQL database containing where Schools located in different countries provide training (the product) in different cars, with different objectives.
SCHOOLS
id| schoolname |
----------------------------------
1 | Pete’s Driving school |
2 | Karen’s Driving school |
3 | John’s Driving school |
4 | Donald’s Driving school |
CARS
id| carbrand |
----------------------------------
1 | Buick |
2 | Mercedes |
3 | Tesla |
4 | Audi |
PROVIDES (PROVIDES THIS TRAINING)
id| name |
----------------------------------
1 | Get License |
2 | Practise driving |
3 | Maneuvering |
4 | Winter training |
LOCATIONS
id| name |
----------------------------------
1 | USA |
2 | UK |
3 | France |
4 | Japan |
I also have these tables telling me which schools have which cars, which location, and provide which training:
SCHOOL_OWNS
id| schoolid | carsid
----------------------------------
1 | 1 | 2
2 | 1 | 1
3 | 2 | 1
4 | 3 | 2
SCHOOL_PROVIDES
id| schoolid | providesid
----------------------------------
1 | 1 | 2
2 | 1 | 3
3 | 2 | 1
4 | 3 | 2
SCHOOL_LOCATIONS
id| schoolid | locationsid
----------------------------------
1 | 1 | 2
2 | 2 | 4
3 | 2 | 1
4 | 3 | 2
My products which I'm trying to select and output..
PRODUCT
id| productname | schoolid | carid | locationid | price
----------------------------------
1 | Product1 | 2 | 1 | 4 | 400 USD
2 | Product2 | 3 | 1 | 2 | 300 USD
3 | Product3 | 1 | 2 | 1 | 200 USD
4 | Product4 | 2 | 2 | 1 | 100 USD
My question is now how to write a JOIN query to get what I'm looking for. This is doing my head in and not even sure where to start or if the way I have done it is a recommended way of setting it up?
I’m trying to create a SQL query that lets me select and sort depending on three criteria, car brand, provides and location.
I have on the top of the page three dropdown menus "CARS", "PROVIDES SERVICE" and "LOCATION".
What SQL Query could match these two scenarios?! Thanks I'm a bit lost..
1. If I want to display all products that fulfill all
these three criteria (Buick, Maneuvering, Japan)
cars=1&provides=3&location=4
Output (only one product meet this criteria):
Product1 | Karen’s Driving school | 400 USD
-------------------
2. And if I only want display all products that provide ‘practise driving’ ?cars=&provides=2&location= ,
Then all products should show that have a company that provides “practice driving” ..
Output (only one two products meet this criteria):
Product1 | Karen’s Driving school | 400 USD
Product3 | John’s Driving school | 200 USD
it looks like you can't make those joins since you do not have foreign keys in your tables.
as an example.. linking cars id to a provides id will not work, so it can't reach that table an easy way... you will need a foreign key or make a sub table to make it easier for yourself!
I'm kinda lost on what kind of SQL query I should do to achieve what I want.
Let's say I have three tables :
select * FROM trip;
| trip_id | title | description
----------------------------------
| 1 | title1 | desc1 |
| 2 | title2 | desc2 |
| 3 | title3 | desc3 |
| 4 | title4 | desc4 |
| 5 | title5 | desc5 |
| 6 | title6 | desc6 |
select * FROM weekly_report;
| report_id | trip_id| incident_id
----------------------------------
| 1 | 1 | (null) |
| 2 | 1 | (null) |
| 3 | 1 | 1 |
| 4 | 2 | 2 |
| 5 | 3 | 3 |
| 6 | 3 | (null) |
select * FROM incident;
| incident_id | error_code |
----------------------------------
| 1 | 22223 |
| 2 | 25456 |
| 3 | 25456 |
So for a little operationnal knowledge :
The trip table contains 1 record PER trip done by the customer.
The weekly_report contains A report per Week of the trip. (1 trip of 2 weeks will have 2 records, 1 trip or 5 weeks will have 5.. ).
The incident table contains 1 record per incident. (If an incident happened during a week : we create a record in the incident table, else we do nothing)
I'd like to find in a single query (or if it has to be, with subqueries) the number of trips where during at least a week there has been an incident declared for the error_code "25456".
Expected result from the sample data : 2 ( because for trip 2 and three there exist an incident with the error code 25456 ).
I can explain more if needed, is there anybody out there willing to help me ?
Thanks,
You need to take count of distinct trips for related incidents
select count(distinct w.trip_id)
from weekly_report w
inner join incident i
on w.incident_id = i.incident_id
where i.error_code = 25456;
Try this:
SELECT w.trip_id
FROM incident i
INNER JOIN weekly_report w ON i.incident_id=w.incident_id
WHERE error_code='25456'
and if you want the count,then
SELECT COUNT(w.trip_id)
FROM incident i
INNER JOIN weekly_report w ON i.incident_id=w.incident_id
WHERE error_code='25456'
I want to make entries of the table 'field_value', which containt a foreign key to table 'field', as many columns result with custom column name.
Let me explain on an example :
The table 'field_value' contains the values :
+---------------------+
| field_value |
+---------------------+
|v_value v_id |
| Peter 1 |
| Lagaf 2 |
| Football 3 |
| Male 4 |
| 12345678 5 |
+---------------------+
The table field will contain the named columns
+--------------------+
| field |
+--------------------+
| f_id f_label |
| 1 surname |
| 2 name |
| 3 hobbies |
| 4 sex |
| 5 phone |
+--------------------+
And the result will be as the following :
+---------------------------------------------+
| Result |
+---------------------------------------------+
| surname name hobbies sex phone |
| Peter Lagaf Football Male 12345678 |
+---------------------------------------------+
Your database is not normalized - and without knowing what the normalized schema should look like it is impossible to give a definitive answer. Further, your schema is invalid for holding more than one record. The most significant issues with your question is that there is nothing to group together the set of field values making up a record, you don't say what would be considered a unique identifier for each record nor if each "record" would have a complete set of attributes in the field_value table.
Consider the case where there is more than record in the database - how do we know that the phone number 12345678 is associated with the forename Peter and not Paul.
The simplest solution (from a static data viewpoint) is to add an attribute for the record identifier to the field table then:
SELECT record.value, surname.value, name.value, hobbies.value....
FROM field AS record
INNER JOIN field AS surname
ON record.record_id=surname.record_id
AND surname.f_id=1
INNER JOIN field AS name
ON record.record_id=name.record_id
AND name.f_id=2
INNER JOIN field AS hobbies
ON record.record_id=hobbies.record_id
AND hobbies.f_id=3
...
WHERE record.f_id=0
ON record.record_id=name.record_id
Thank symcbean for your response.
I wanted to simplify the post, this is the real tables and the real result :
I want to display orders item that have the collect_id = 2
And I want to display all the fields related to each order_item.
+-------------------------------+
| order_item |
+-------------------------------+
| oi_id oi_price oi_collect_id |
| 1 100 2 |
| 2 30 2 |
| 3 55 3 |
| 4 70 4 |
| 5 220 2 |
| 6 300 4 |
+-------------------------------+
+-----------------------------------+
| field_value |
+-----------------------------------+
| v_value v_fk_field_id oi_fk_id |
| Peter 1 1 |
| Lagaf 2 1 |
| Football 3 1 |
| Male 4 1 |
| 12345678 5 1 |
| Frank 1 2 |
| Loran 2 2 |
| Tennis 3 2 |
| Male 4 2 |
| 11223658 5 2 |
| Nathali 1 3 |
| Waton 2 3 |
| Reading 3 3 |
+-----------------------------------+
oi_fk_id : foreign key ref(order_item.oi_id)
v_fk_field_id : foreign key ref(field.f_id)
+--------------------+
| field |
+--------------------+
| f_id f_label |
| 1 surname |
| 2 name |
| 3 hobbies |
| 4 sex |
| 5 phone |
+--------------------+
+-----------------------------------------------------------------------------+
| Result |
+-----------------------------------------------------------------------------+
| oi_id oi_price oi_collect_id surname name hobbies sex phone |
| 1 100 2 Peter Lagaf Football Male 12345678 |
| 2 30 2 Frank Loran Tennis Male 11223658 |
| 5 220 2 Nathali Waton Reading null null |
+-----------------------------------------------------------------------------+
Important : The table field does not contain only these 5 fields (name, surname, hobbies, sex, phone), but it can contain many others, that the developper may not know, same thing for the correspondant value on the table 'field_value'
In a simple sales sample I have 3 primary tables: Order, Product, Orders_Products:
Product table
+----+-----------+
| id | name |
+----+-----------+
| 1 | A |
| 2 | B |
+----+-----------+
order table
+----+---------+------------+------------+---------------------+
| id | user_id | total_cost | order_date | status_id |
+----+---------+------------+------------+---------------------+
| 1 | 5 | 25.00 | 2012-02-03 23:30:24 | 1 |
| 2 | 7 | 30.00 | 2012-02-13 18:06:12 | 1 |
+----+---------+------------+------------+---------------------+
orders_products table
+----+----------+------------+--------+
| id | order_id | product_id | cost |
+----+----------+------------+--------+
| 1 | 1 | 34 | 10.00 |
| 2 | 1 | 25 | 10.00 |
| 3 | 1 | 27 | 2.50 |
| 4 | 1 | 36 | 2.50 |
| 5 | 2 | 75 | 25.00 |
| 6 | 2 | 74 | 5.00 |
+----+----------+------------+--------+
But in my system:
A user adds money into his account then he can spend it
Products are services like Product A: user can post 5 Ads so when user post a Ads that 5 become 4 and so on.
How should I design DB for it??
You currently have no table to store customer data. I would strongly advise creating one using an Auto-Increment ID field, a name field and a field to store the money on their account which can be modified when the add money to it or purchase something.
In the Order table, the user_id field should be a foreign key from the Customer table I just told you how to create.
If you want to better understand what you should be doing, I would recommend looking at the Entity-Relationship Model
I don't entirely understand what your second question is, can you explain it in more detail? Are all the products just a set number of ads that the customer can post?
I'm having difficulty trying to form the actual question I have, so hopefully I can get the point across with visual aid.
What I'm wondering is whether or not my current database design is horribly flawed, slightly inefficient, or ... correct.
Q: Is there a better way for a row cell to reference a column in another table, aside from just saving a string of that column's name?
Example:
There are two tables.
table01: has 3 columns - c_id, customer, tier (tier holds the column name of a tier in table02 )
table02: has 5 columns - i_id, item, tier1, tier2, tier3
table01 +------+----------+------+
|'c_id'|'customer'|'tier'|
+------+----------+------+
| 1 | John | tier1|
| 2 | Lisa | tier2|
| 3 | Mike | tier1|
| 4 | Tom | tier3|
+------+----------+------+
table02 +------+------+-------+-------+-------+
|'i_id'|'item'|'tier1'|'tier2'|'tier3'|
+------+------+-------+-------+-------+
| 1 | apple| $1.99 | $2.99 | $3.99 |
| 2 | chalk| $2.99 | $3.99 | $4.99 |
| 3 | pens | $3.99 | $4.99 | $5.99 |
| 4 | shirt| $4.99 | $5.99 | $6.99 |
+------+------+-------+-------+-------+
Result:
John +------+-------+
| apple| $1.99 |
| chalk| $2.99 |
| pens | $3.99 |
| shirt| $4.99 |
+------+-------+
Selecting John's row would yield tier1, which is then used to query for table02.tier1, and grab that column's contents. (In this discounted prices for tier1 customers). The tier1 items would then be displayed with their correct prices.
Is there a more efficient way to reference an outside table's column name, like... in the style of foreign keys? Where if the column name changes, then that information waterfalls to other linked data cells? Is my approach correct, or should I restructure how I'm doing things?
It isn't completely clear how the c_id and i_id columns are supposed to be used, but a more conventional design would be to use a design like this:
table01 +------+----------+------+
|'c_id'|'customer'|'tier'|
+------+----------+------+
| 1 | John | 1 |
| 2 | Lisa | 2 |
| 3 | Mike | 1 |
| 4 | Tom | 3 |
+------+----------+------+
table02 +------+------+-------+
|'i_id'|'tier'|'cost' |
+------+------+-------+
| 1 | 1 | $1.99 |
| 2 | 1 | $2.99 |
| 3 | 1 | $3.99 |
| 4 | 1 | $4.99 |
| 1 | 2 | $2.99 |
| 2 | 2 | $3.99 |
| 3 | 2 | $4.99 |
| 4 | 2 | $5.99 |
| 1 | 3 | $3.99 |
| 2 | 3 | $4.99 |
| 3 | 3 | $5.99 |
| 4 | 3 | $6.99 |
+------+------+-------+
I edited the example to better exemplify my thoughts. Which really doesn't change your answer much. So it'd be better to consolidate the tier columns into one column and just repeat the item id (i_id) data several times? My reasoning behind breaking the tier/cost structure into columns was to cut down on redundancy. Would that approach require me to make a new table to index the tiers for foreign keys?
I understand what you're doing now. Somewhere along the line, you might have a 'Sales' table which records a c_id, and i_id, a quantity, a date and other such information (if each sale consists of one item; otherwise, you'd have an 'Orders' table and an 'OrderItems', and the c_id would be associated with the orders table and the i_id would be associated with order items, and there'd be an order number to connect the two tables).
If you add your item desciption to the revised table02 above, you would be violating 3NF. You should have a table such as 'Products' with the i_id and item columns. This would give names to item numbers. The table02 (maybe 'TieredItemCosts') table I proposed would remain as it is; the primary key is the combination of (i_id, tier).