I am creating a database application for a restaurant stock management system. I currently have two database tables, one for the ingredients, and one for each dish.
Database tables and relationships
Each ingredient has a unique ID which is the PK of the table. And the 'ingredients' field in the DISH table is a foreign key linking to ingredient_ID. Each dish will obviously have many ingredients, but the ingredients can also belong to multiple dishes. I have read elsewhere about creating another table called ingredient_dish for example, but I'm not sure I fully understand how this works. Could somebody either point me in the right direction or attempt to explain please, and what sort of columns would I have in this joining table for the above tables?
Thanks a lot.
Since you have a Many-to-Many relationship between Ingredients and Dishes, you may want Ingredient_Dish to be a Cross-Reference table.
Its fields would include ingredient_id, a foreign key to the Ingredients table, and dish_id, a foreign key to the Dish table. Set the primary key of this new table to the combination of both fields. A creation command might look like the following, tailor it to suit:
CREATE TABLE Ingredient_Dish (
ingredient_id INT NOT NULL,
dish_id INT NOT NULL,
CONSTRAINT PK_Ingredients_by_dish PRIMARY KEY (ingredient_id, dish_id))
ALTER TABLE Ingredient_Dish
ADD CONSTRAINT FK_Ingredients FOREIGN KEY (ingredient_id) REFERENCES Ingredient (ingredient_id )
ALTER TABLE Ingredient_Dish
ADD CONSTRAINT FK_Dishess FOREIGN KEY (dish_id) REFERENCES Dish (dish_id)
Many-to-many relationships are best done with such an intermediate (or "bridge") table. The bridge table basically consists of the primary keys of the other tables to form a "bigger" foreign key, which allows you to implement a many-to-many relationship by providing primary key combinations.
Your use case (simplified) would necessitate tables like these:
dishes:
dish_id | other_columns
-------------------------
1 | ...
2 | ...
3 | ...
ingredients:
ingredient_id | other_columns
-------------------------------
1 | ...
2 | ...
3 | ...
dishes_ingredients_bridge:
dish_id | ingredient_id
-------------------------
1 | 1
1 | 2
2 | 2
2 | 3
3 | 3
This means you have 3 dishes and 3 ingredients, where
dish 1 consists of ingredients 1 and 2
dish 2 consists of ingredients 2 and 3
dish 3 consists only of ingredient 3
ingredient 1 is used only in dish 1
ingredient 2 is used in dishes 1 and 2
ingredient 3 is used in dishes 2 and 3
Also, make sure, the combinations in your bridge are unique (create a multi-column unique key). Omitting this usually doesn't result in big problems, but in some edge cases your application could behave in an undefined or unexpected way.
Now you can query (for example) all ingredients of dish 1 like this:
SELECT i.*
FROM ingredients as i
LEFT JOIN dishes_ingredients_bridge dib
ON dib.ingredient_id = dib.ingredient_id
LEFT JOIN dishes as d
ON d.dish_id = dib.dish_id
"Connecting" a dish to an ingredient means adding a row to the bridge. "Disconnecting" a dish from an ingredient means deleting such rows, respectively.
Hope this helps.
You are basically describing a bridge table. It's the only way to describe a many-to-many relationship without concatenating values (which is a very nasty can of worms). I suggest you read this further:
http://www.kimballgroup.com/2012/02/design-tip-142-building-bridges/
Hope it helps.
Related
I'm using MariaDB and PHPMyAdmin, but my code is all neutral so happy to switch to Postgres or whatever, but this should be straight forward enough. I haven't designed anything yet, just after best approaches.
I have 3 database tables that describes a premises. Let's say a hotel.
This theoretical hotel has multiple venues - 2 restaurants and a bar. Each of those has a few different rooms/areas. In these rooms are tables that customers can sit at.
In SQL, I imagine the tables would look like this
Venues
Venue ID
Venue Name
1
Restaurant 1
2
Restaurant 2
3
Bar
Rooms
Room ID
Room Name
Parent Venue (foreign key)
1
Patio
1
2
Function Room
1
3
Alcove
3
4
Private Dining
2
Tables
Table ID
Table Name
Parent Room (foreign key)
1
Table 1
1
2
Table 2
1
3
Table 3
1
4
Table 4
2
5
Table 1
3
6
Table 2
3
7
Table 3
3
8
Table 4
3
9
Table 1
4
10
Table 2
4
11
Table 3
4
I hope that data is correct :p
What I want to do is define a relationship whereas it's impossible to add a Table Name if it already exists in that venue. It doesn't matter what room the table is in.
E.g if I was to add another "Table 4", it would succeed in being entered if it was entered into Room 4, as Room 4 belongs to Restaurant 2, which does not already have a "Table 4". However if it was entered into any other room, it would fail as Restaurant 1 and Bar already have a "Table 4" in one of their rooms.
Now in the server side code this is fairly easy to check as I can do multiple queries or joins or a myriad of other ways, however I was wondering how to do this in SQL/PhpMyAdmin directly. I'm having a bit of trouble finding my way around MyAdmin.
Cheers
My recommendation is to redundantly include the parent venue in the tables table. So tables would have the additional column:
venueID
rooms would have a unique constraint (which is redundant):
alter table rooms add constraint unq_rooms_venueId
unique (venueId, roomId);
Then tables would have a unique constraint:
alter table tables add constraint unq_table_venueId
unique (tableName, venueId);
This solves the problem without having to resort to triggers.
What I'd do is switch from technical IDs to composite natural keys. You can use numbers for this (i.e. give a venue a number, a room a number, maybe a table a number) or use the names, if these are guaranteed not to change. E.g.:
venues
(
venue_name,
primary key (venue_name)
);
rooms
(
venue_name,
room_name,
primary key (venue_name, room_name),
foreign key (venue_name) references venues (venue_name)
)
tables
(
venue_name,
room_name,
table_name,
primary key (venue_name, room_name, table_name),
foreign key (venue_name, room_name) references rooms (venue_name, room_name),
unique constraint (venue_name, table_name)
)
(If using the names for keys and your tables don't contain any other information aside from the names, you can easily remove the tables venues and rooms of course and only keep the tables table, if you want.)
Same thing with numbers:
venues
(
venue_no,
name,
primary key (venue_no)
);
rooms
(
venue_no,
room_no,
name,
primary key (venue_no, room_no),
foreign key (venue_no) references venues (venue_no)
)
tables
(
venue_no,
room_no,
table_no,
name,
primary key (venue_no, room_no, table_no),
foreign key (venue_no, room_no) references rooms (venue_no, room_no),
unique constraint (venue_no, name)
)
I have an extreamly simple idea: table that keeps user "achievements". And it is as simple as that:
user_id | achievement_id
1 | 1
1 | 2
1 | 5
2 | 2
2 | 3
All what I need is user id, and id of achievement if he already got it. All what I need to SELECT is SELECT achievement_id WHERE user_id=x. So no need for an artificial autoincrement column that I'll never use or know what it contains. But setting an primary key is required, so the question is - is it good idea to make such 2-column table and set both columns as multi-column primary key? I already have a set of 3-columns table where 2 are primary key, because it is logic... Well, logic for me, but for the database?
These types of tables are common in cases of n-n relationships, multivalued attributes, and weak entities. It varies a lot from its modeling, but yes, it is a good solution for some cases. the primary key is usually the relation of the columns. In your case it would be user_id and achievement_id.
Yes since the rule for such a set of n-keys is: "I only want one kind of record which has this set (a,b) of keys".
-> therefore you won't be able to add twice "Mario, achievement1".
Primary key will be then (PlayerID, AchievementID).
If you want to add some informations about this achievement (for example, when the player got the achievement), simply do such as: (PlayerID, AchievementID, Date) with PlayerID, AchievementID as primary key.
I hope this will help you.
While using mysql workbench and for designing database using designer the relation tool uses a third table to form a many to many relation between 2 tables.
I have 3 tables
TABLE1
TABLE2
TABLE3
TABLE2 has foregin key from primary key of TABLE1,having a many to one relation
TABLE2 and TABLE3 are related using a many to many relation,
as soon as I create the relation
a new table TABLE3_has_TABLE2 is created with all the key from TABLE2(primarykey of table2 & foreign key of table1) and TABLE3 (primary key of table3).
Now,
why is there foreign key of table1.?
Even if i remove I will be able to query data from table1 and table3 using table2 as intermediate, so is it good to have this kind of relation or avoided?
For Example in below diagram
This is a geographical distribution of location, on right side it shows the hirarchy.
Now,
Table1(Zone) is the primary table i.e Zone
Table2(state) is related to table1 using zone_id
Table3(division) is related to table2(state) using state_id & zone_id of table1(zone)
Question: Should this zone_id column be in the table3 or not?
similarly table4 contains all the previous key columns of table3.
Strictly from a denormalization point-of-view, the DIVISION.STATE_ZONE_ID isn't required.
Since you can get the ZONE_ID from the DIVISION by joining STATE on the state_id.
And it's the same with the division_state_state_id & division_state_zone_id in DISTRICT.
Having the division_division_id is enough to join DIVISION, then STATE, then ZONE.
However, what if you would remove those 'extra' fields?
Then a SQL always needs to go through that cascade of joined tables to get the ZONE.zone_name.
So there's an advantage that by having those 'extra' fields, it becomes possible to JOIN directly to the ZONE table. Which can simplify/speed up certain popular queries.
The disadvantage is that it becomes harder to assure referential integrity.
Because for example, you could assign a different zone_id to a DIVISION.state_zone_id than the STATE.zone_id you can get via DIVISION.state_state_id.
It is best practice in relational models to avoid many-to-many relationships. Workbench usually compensates for user trying to do that as you have seen.
Let us use an example (or check the tl;dr), where there are two identified entities; buyers and hardware items. Some people buy 1 item, others buy more than one. The thing is, that same item can be bought by many people. So the buyer table has Mr. A buying nails. Simple enough to record in one row. But lo' and behold, he ups and gets another item! How do we show that he buys another item?
One way is by adding another attribute to the table (say "item_number_two"). But then he gets another! We can't keep going adding attributes like that. Databases were designed more for vertical addition of records, rather than horizontal addition of attributes (to give a visual picture). There is a longer explanation but you should read up, or probably might figure it out after reading this.
Another way is to re-enter a record for Mr. A and then put the ID of another item in that column, showing that he bought two items (not really "he" from a database stand-point, it's two different people!).
A better method would be to create a table that consists of the unique identifiers found in the original tables (just one per table may be necessary). This is called an intermediary table. The original tables themselves do not have foreign keys from the other table.
This is where the concept of a composite key comes in. It means that two or more candidate keys are used to uniquely identify a record rather than just one. This is how it works:
Person Table:
| person_ID | person_Name |
| P0001 | Mr. A |
| P0002 | Mr. B |
| P0003 | Mr. C |
| P0004 | Mr. D |
Cat Table
| item_ID | cat_Name |
| I0001 | Nails |
| I0002 | Screws |
| I0003 | Hammers |
| I0004 | Power-Saw |
Intermediary table
| person_ID | item_ID |
| P0001 | I0001 |
| P0001 | I0002 |
| P0001 | I0003 | //Shows that person 1 bought more than one item
| P0002 | I0004 |
| P0002 | I0001 | //Shows that an item has been bought by more that one person
So this new table matches a record of one table(through the use of a primary key) to a record of another. The only thing that will ever be repeated is one of the two ID's. A unique record is made as long as no two combinations are repeated.
tl;dr - Having tables mapped in a many to many relationship inevitably wastes space in the DB when entering records, as new records of the same data have to be made to show a small difference (adding no real value in proportion to the space). Another issue is that it causes more calculations than necessary when a query is made, wasting time and space. Or the results returned may just be plain wrong...
EDIT:
If you have tables A and B having a many-to-many relationship, do the following as an alternative. Create a table C. Take the primary keys from table A and B and place them in tables C. In table C they both exist as primary and foreign keys. This would mean the following relationship is created.
| Table A |-----------<| Table C |>------------|Table B|
Table A and B are linked through C.
Sample query:
SELECT C.itemID FROM A, C WHERE A.personID = P0001 AND A.personID = C.personID;
This query will return all ID's of the items bought by the person with an ID of P0001. Records must match the condition of having a personID of P0001, but the record selected must have that matching ID in Table C (the intermediary table). An extended query could be to take the item names from the Table B. Each attribute in C has a recorded value that corresponds to a value of a key in either Table A or B, meaning that a query can be run to pull other info, where the value in Table C is = to the values in Table A/B (depending on which one you want).
i have a question about the 1 normal form and will explain it by an example.
lets imagine that we have a set of students that are working on a set of projects, but not necessarily only one, but more than one (many to many relation). we have a table where the information's of the students are recorded, and one for the projects. but we need to link them together. but since the 1NF says redundancy and only value per tuple, how would you do it?
both fields are primary keys here
illustation 1:
student_ID project_ID
1 7
2 7,1
3 4,1,9
4 1,3
5 1
illustration 2:
student_ID project_ID
1 7
2 1
2 7
3 4
3 1
3 9
4 1
4 3
5 1
Illustration 1: I know that if this would be a result of a table, this would violate the 1NF becuase one than one value per tuple.
Ilustration 2: since they are primary keys they are not allowed to be duplicated, even if i remove the primary key from the student_ID i still would be redundant.
How can i fix this issue?
thanks in advance :)
The primary key of this table will be a composite of the two fields. They must both together be unique. Both fields are foreign keys to their respective tables and they will be unique in their respective tables.
What you have here is basically a junction table, and your second illustration shows the correct way to normalize it.
Note that, as is typical for junction tables, the primary key for your table will consist of both of the columns together. Together, each unique combination of values in these columns specifies a distinct student–project pairing.
Edit: In MySQL, you would define this table e.g. as:
CREATE TABLE student_projects (
student_id INTEGER NOT NULL,
project_id INTEGER NOT NULL,
PRIMARY KEY (student_id, project_id)
)
To enforce relational consistency, you may also want to add explicit foreign key constraints to each of the columns.
I've created a database with three tables in it:
Restaurant
restaurant_id (autoincrement, PK)
Owner
owner_id (autoincrement, PK)
restaurant_id (FK to Restaurant)
Deal
deal_id (autoincrement)
owner_id (FK to Owner)
restaurant_id (FK to Restaurant)
(PK: deal_id, owner_id, restaurant_id)
There can be many owners for each restaurant. I chose two foreign keys for Deal so I can reference the deal by either the owner or the restaurant. The deal table would have three primary keys, two being foreign keys. And it would have two one-to-many relationships pointing to it. All of my foreign keys are primary keys and I don't know if I'll regret doing it like this later on down the road. Does this design make sense, and seem good for what I'm trying to achieve?
Edit: What I really need to be able to accomplish here is when a owner is logged in and viewing their account, I want them to be able to see and edit all the deals that are associated with that particular restaurant. And because there can be more that one owner per restaurant, I need to be able to perform a query something like: select *from deals where restaurant_id = restaurant_id. In other words, if I'm an owner and I'm logged in, I need to be able to make query: get all of the deal that are related to not just me, the owner, but to all of the owners associated with this restaurant.
You're having some trouble with terminology.
A table can only ever have a one primary key. It is not possible to create a table with two different primary keys. You can create a table with two different unique indexes (which are much like a primary key) but only one primary key can exist.
What you're asking about is whether you should have a composite or compound primary key; a primary key using more than one column.
Your design is okay, but as written you probably have no need for the column deal_id. It seems to me that restaurant_id and owner_id together are enough to uniquely identify a row in Deal. (This may not be true if one owner can have two different ownership stakes in a single restaurant as the result of recapitalization or buying out another owner, but you don't mention anything like that in your problem statement).
In this case, deal_id is largely wasted storage. There might be an argument to be made for using the deal_id column if you have many tables that have foreign keys pointing to Deal, or if you have instances in which you want to display to the user Deals for multiple restaurants and owners at the same time.
If one of those arguments sways you to adopt the deal_id column, then it, and only it, should be the primary key. There would be nothing added by including the other two columns since the autoincrement value itself would be unique.
If u have a unique field, this should be the PK, that would be the incremented field.
In this specific case it gives u nothing at all to add more fields to this key, it actually somewhat impacts performance (don't ask me how much, u bench it).
if you want to create 2 foreign keys in the deal table which are the restaurant and the owner the logic is something like a table could exist in the deal even without an owner or an owner could exist in the deal even without identifying the table on it but you could still identify the table because it's being used as a foreign key on the owner table, but if your going to put values on each columns that you defined as foreign key then I think it's going to be redundant cause I'm not sure how you would use the deal table later on but by it's name I think it speaks like it would be used to identify if a restaurant table is being reserved or not by a customer and to see how you have designed your database you could already identify the table which they have reserved even without specifying the table as foreign key in the deal table cause by the use of the owner table you would able to identify which table they have reserved already since you use it as foreign key on the owner table you just really have to be wise on defining relationships between your tables and avoid redundancy as much as possible. :)
I think it is not best.
First of all, the Deal table PK should be the deal_id. There is no reason to add additional columns to it--and if you did want to refer to the deal_id in another table, you'd have to include the restaurant_id and owner_id which is not good. Whether deal_id should also be the clustered index (a.k.a. index organized on this column) depends on the data access pattern. Will your database be full of data_id values most often used for lookup, or will you primarily be looking deals up by owner_id or restaurant_id?
Also, using two separate FKs way the you have described it (as far as I can tell!) would allow a deal to have an owner and restaurant combination that are not a valid (combining an owner that does not belong to that restaurant). In the Deal table, instead of one FK to Owner and one FK to Restaurant, if you must have both columns, there should be a composite FK to only the Owner table on (OwnerID, RestaurantID) with a corresponding unique key in the Owner table to allow this link up.
However, with such a simple table structure I don't really see the problem in leaving RestaurantID out of the Deal table, since the OwnerID always fully implies the RestaurantID. Obviously your deals cannot be linked only with the restaurant, because that would imply a 1:M relationship on Deal:Owner. The cost of searching based on Restaurant through the Owner table shouldn't really be that bad.
Its not wrong, it works. But, its not recommended.
Autoincrement Primary Keys works without Foreign Keys (or Master Keys)
In some databases, you cannot use several fields as a single primary key.
Compound Primary Keys or Compose Primary Keys are more difficult to handle in a query.
Compound Primary Key Query Example:
SELECT
D.*
FROM
Restaurant AS R,
Owner AS O,
Deal AS D
WHERE
(1=1) AND
(D.RestaurantKey = D.RestaurantKey) AND
(D.OwnerKey = D.OwnerKey)
Versus
Single Primary Key Query Example:
SELECT
D.*
FROM
Restaurant AS R,
Owner AS O,
Deal AS D
WHERE
(D.OwnerKey = O.OwnerKey)
Sometimes, you have to change the value of foreign key of a record, to another record. For Example, your customers already order, the deal record is registered, and they decide to change from one restaurant table to another. So, the data must be updated, in the "Owner", and "Deal" tables.
+-----------+-------------+
| OwnerKey | OwnerName |
+-----------+-------------+
| 1 | Anne Smith |
+-----------+-------------+
| 2 | John Connor |
+-----------+-------------+
| 3 | Mike Doe |
+-----------+-------------+
+-----------+-------------+-------------+
| OwnerKey | DealKey | Food |
+-----------+-------------+-------------+
| 1 | 1 | Hamburguer |
+-----------+-------------+-------------+
| 2 | 2 | Hot-Dog |
+-----------+-------------+-------------+
| 3 | 3 | Hamburguer |
+-----------+-------------+-------------+
| 1 | 3 | Soda |
+-----------+-------------+-------------+
| 2 | 1 | Apple Pie |
+-----------+-------------+-------------+
| 3 | 3 | Chips |
+-----------+-------------+-------------+
If you use compound primary keys, you have to create a new record for "Owner", and new records for "Deals", copy the other fields, and delete the previous records.
If you use single keys, you just have to change the foreign key of Table, without inserting or deleting new records.
Cheers.