Foreign key to multiple records - mysql

I have two tables like so:
Table1
| itemid (PK)|
| typeid (FK)|
| item count |
Table2
| typeid (PK)|
| type name |
Table2 have 4-5 records in it. ...And I'm stuck at this point... Basically the item can be of all types (it can have typeid (FK) = NULL or all 4-5). I just can't get my head round this..At the moment when I add new item to Table1 (using phpmyAdmin ui) it gives me a choice of one FK as a dropdown list.. But what if the item is of two or three types..? It's probably a piece of cake but my brain has stalled... What would be the best way to do it?

Your design support 1-to-many relationship. Perhaps, you need many-to-many relationship between Table1 and Table2. If yes, you need to add a new link table:
Table3:
itemid(FK)
typeid(FK)

You can define a composite key on itemid and typeid in Table1.
That allows combinations of 1-1, 1-2, 3-1, 3-4, etc on itemid and typeid values.

Even your question is not much clear, but what I am understanding that you are not able to insert records in child table (table1) as record does not exist in master table (table 2).
So first you need to add required typeid in master table (table2) then you can enter in its child table.
If your requirement is something different then elaborate, so that you can get better help from community.

Related

SQL - Insert multiple categories to column

I have a table where I store products, and in the same table I store the ID of the category I want the product to be in.
My product table looks like this:
id | product_name | category_id | price
And then I have my category table:
id | category
My problem is to know how I can insert multiple categories into my category_id, and if it is possible.
If not, whats the best way that I could do it?
It is possible but you really don't want to go there. Storing multiple values in a single datarow column is a terrible idea in 99.99999% of the cases.
For more information, read Is storing a delimited list in a database column really that bad?, where you will see a lot of reasons why the answer to this question is Absolutely yes!
What you want to do is to add another table to store the relationship between the products and the categories. This is referred to as a many to many relationship.
This new table should hold the product id in one column and the category id in the other one, and have a composite primary key that is the combination of both these columns.
This way, you can have many products in the same category, and many categories for the same product.
You need a many to many relationship, which mean you need a third table let's call it ProductCategories, in this case you will have
Products
id | product_name | category_id | price
Category
id | category
ProductCategories
PruductID | CategoryID (combined PK)

Why do many to many relation use all the key from previous table?

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).

Insert an entire column content into another table plus a value

Ok, I am new to SQL, so this must sound stupid. Sorry for that.
I have two tables + one junction table (many to many schema) = total of three tables.
First table
students: student_id (PRIMARY) | name | email | password |...
Second table
topics: topic_id (PRIMARY) | topic_name | subject |...
Third table (junction)
jnct_students_topics: id (PRIMARY) | student_id_FK | topic_id_FK | done (boolean) | notes
So how the web app would work?
Second table (topics) is pre-filled with all the topics students need to study.
First table (students) will be filled whenever a new student register for the service.
Junction table (jnct_students_topics) will also be filled when student registers, but (HERE COMES THE QUESTION) I need to know how to insert all topics ids + this student id in topic_id_FK and student_id_FK columns.
Because when a student registers, system will create a list for him/her with all topics to study and a checkbox for each one. After student finishs with topic studying, he/she will check the box and the boolean done column will become true for this topic.
I learned from [this question] (Copy from one column to another (different tables same database) mysql) that, to populate a table column with values from another table column, I could go:
INSERT INTO jnct_students_topics (topic_id_FK)
SELECT topic_id
FROM topics
but I need to build the statement so at the same time the student_id (related to the student that is registering) is inserted (column student_id_FK) in all rows that are being created.
Tired of reading? Well, I don't blame you. Nor english or SQL are native languages of mine... :)
By the way, If you think that this schema is not the best, please, I would appreciate some advice.
Thanks!

Does it make sense to have three primary keys, two of which are foreign keys, in one table?

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.

Primary key on 2 tables

i have two tables, one 'master' and one 'child' table.
Each table has a field named 'ProductNo', which is defined as PRIMARY KEY and UNIQUE.
Is it possible to define the field 'ProductNo' in the table 'child' and the same field in table 'master' as PRIMARY + UNIQUE together?
master:
ID | ProductNo
child:
ID | MasterID (FK on master.ID) | ProductNo
Relation >> 1 (master) : n (child)
example data:
master:
1 | 1234
2 | 4567
child:
100 | 1 | 3333
101 | 1 | 4444
102 | 2 | 5555
103 | 1 | 1234 <----- NOT ALLOWED! PRODUCT NO ALREADY EXISTING IN TABLE `MASTER`
104 | 2 | 1234 <----- NOT ALLOWED! PRODUCT NO ALREADY EXISTING IN TABLE `MASTER`
It is needed to check on inserting/updating table 'child' if 'ProductNo' already exists in table 'master'.
How can I define it?
Or am I needed to create a trigger for this?
TIA Matt
no, there is no such thing as composite PKs among tables.
Just for data consistency, if the Ids are the same, you should add a FK from child to the master.
To solve your problem, a trigger with a check like this:
if exists (select 1 from master where prodcutId=new_productId)
would be a good idea
EDIT:
actually the best idea is to have only one table called product with a ID and a masterID field with a relation to itself. The way you have today Im pretty sure that you have a lot of duplicate data and you are stuck with 2 levels on hierarchy.
(Original answer) You can declare a foreign key from master to child, even if that foreign key points to the primary key of child. This would be a one to zero-or-one relationship, and is not that uncommon. A row cannot exist in child without a matching row in master already being inserted, but a row can exist in master without a matching child row. Your inserts therefore need to happen in the order master then child.
(Edited in light of question edit) HOWEVER, in your case, the column you are referring to looks like it should not actually be the primary key of either table, but rather you have a separate primary/foreign key, and the column in question needs to be unique across the two tables, which has become clear now you've edited some sample data into your question. In this case, you'd be best to use a trigger on both tables, to check existence in the other table and prevent the insert/update if the ProductNo already exists.
Just as #DavidM said, it can be done, but it seems you are with some modelling issues. First, if you have a natural primary key ProductNo, why do you define a surrogate ID? The other thing you might consider is to combine these two tables into a single one (as might make sense for most of 1-to-1 cases).
Are you sure you need the two tables?
Keep just one, having productID plus parentID.
Then productID can be a primary key and auto increment, while everything having a parentID other than null (f.keyed to the same table) would be a child item.
You can add a column named ProductNo in child table and add a foreign key reference to the parent table.