Let's assume we have two tables: products and orders. As it is a multi-to-many relationship, I've created an extra table: ordersproducts.
As I read from many threads, two primary keys are recommended in this case - table ordersproducts:
order_id (PK), product_id (PK, FK),
However, in this situation there can't be duplicates in the table. Order_id can be duplicated, but product_id has to be unique, and I need a bit more flexibility - order_id should be able to duplicate and so should product_id.
Works correctly after removing the primary keys, leaving only the foreign key at product_id, however - table without primary keys doesn't seem right, does it?
Always have a PRIMARY KEY. It sounds like you need either (not both) of these:
PRIMARY KEY(order_id, product_id)
PRIMARY KEY(product_id, order_id)
These say (because a MySQL PK must be unique) that there may be duplicates of either column, but the pair is never duplicates.
Since you probably want to go both directions (given an order, find all the products and given a product, find all the orders), you need indexes both ways:
PRIMARY KEY(order_id, product_id),
INDEX(product_id, order_id)
Remember, a PK is UNIQUE and is an INDEX.
Here are more tips on virtually any many:many table. That discusses a generic solution to your generic problem.
Related
Lets says that I have an order table and item table :
CREATE TABLE if not exists ORDERS (
ORDERID INTEGER AUTO_INCREMENT,
ORDERTYPE VARCHAR (20) NOT NULL,
ShippedTime VARCHAR(40),
ORDERDATE DATE,
PRIMARY KEY (ORDERID),
);
CREATE TABLE if not exists ITEM(
ITEMID INTEGER AUTO_INCREMENT,
NAME VARCHAR (20) NOT NULL,
PRICE INTEGER NOT NULL CHECK (PRICE > 0),
PRIMARY KEY (ITEMID)
);
and the relation between the both tables will be existof :
CREATE TABLE if not exists EXISTOF (
ORDERID INTEGER NOT NULL,
ITEMID INTEGER NOT NULL,
FOREIGN KEY (ORDERID) REFERENCES ORDERS(ORDERID) ON DELETE CASCADE,
FOREIGN KEY (ITEMID) REFERENCES ITEM(ITEMID) ON DELETE CASCADE,
PRIMARY KEY (ORDERID,ITEMID)
);
The explanation should be for each order has multiple item and each item belongs to many orders.
If I do like this it will not be work because the ids are primary keys and I can't insert for specific order multiple item and also it can not items belongs to multiple order.
Does anyone have any recommendation how to do that?
Your Existof Table is not flexible enough. The way most order processing systems deal with this situation is to add a column, which we can call Quantity, to the Existof table. The default value is 1, but other quantities can be put in as well.
So if a given order wants to order say 5 reams of paper,and ream of paper in a product, the entry for this item in Existof will have a quantity of 5.
This assumes that all 5 reams are interchangeable, and therefore described by the same data. If some of the paper reams are of different colors, than they ought to be different products.
Create an intermediate table OrderItems with foreign keys item_id and order_id. There are other options but this is the easiest way I find to break down many-many relationships!
"... have to be ..." -- no. FOREIGN KEYs are never "required".
A FK provides three things:
A dynamic check that there is a matching element. This is useful as an integrity check on the data, but is not mandatory.
An INDEX to make the above check significantly faster. Manually specifying an INDEX is just as good. Anyway, a PRIMARY KEY is an index.
"Casscading delete, etc". This is an option that few schemas use, or even need.
There are 3 main types of "relations" between tables:
1:1 -- But why bother having two tables? The columns could simply be in a single table. (There are exceptions.)
1:many -- (This sounds like "many items in one order"??) That is implemented by simply having order_id in the Items table. (And index that column.) Optionally, it can be a FK. Others call the table OrderItems. And it links to a Products table.
many:many -- This is when you need an extra table with (usually) exactly two columns, namely ids into the other two tables. (Eg, Student vs class) Each column could be an FK, but the optimal indexes are PRIMARY KEY(a_id, b_id) and INDEX(b_id, a_id). The FKs would see that you already have indexes starting with a_id and b_id, so it would not create an extra index. Do not have "a unique junction table ID"; it is less efficient than the PK I suggest here. (More discussion: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table)
Back to your proposed design. I suggest that "item" implies the product and quantity of that product and the price charged at that time. Hence it needs to be 1:many. And that "product" is what you are thinking of. Please change the table name so I am not confused.
Now, another issue... Price. Is the price fixed forever? Or is the price going to be different for today's Orders than for yesterday's? Again, the Item and Price are tied to one Order. There may be a Price on the Product table, and that may be "current_price", which gets used when creating new Orders.
ShippedTime VARCHAR(40) -- Perhaps should be DATETIME?
i have two tables in my database which belongs to each other.
mp_order and mp_order_items.
mp_order has the main informations of an order of a customer like adress, date etc.
(order_id, customer_company, customer_name, customer_adress, order_date, ... [etc.])
mp_order_items has the priducts/items which was ordered
(order_id, item_id, item_qty)
Due to order_id and item_id can repeat (but not in combination) i cant set one column as primary key.
Should i implement another column as unique identifier for the single entries or is it valid to have a table without primary key?
You have two options:
Define a primary key on (order_id, item_id)
Define a synthetic primary key, such as an auto-incremented column.
I prefer the second method. It is more flexible for the future:
Perhaps an order could contain the same items, but with different pricing or shipping addresses or shipping times.
The rows are uniquely defined with a single number, which makes it easier to find them if you need to modify rows in the future.
The rows are more easily referenced in another table, for instance, if you had a returns table or if the items.
Of course, having a composite primary key also works and is a very viable method for implementing the logic as well.
Since, you requirement is that order_id and item_id can not repeat in combination meaning: (ord_134, itm_123) can't repeat itself then, I believe you need to create a COMPOSITE KEY.
PRIMARY KEY(order_id, item_id)
Basically, a combination of both Order Id and Item Id is what will uniquely identify a record in the table.
There is a caveat, if required, while defining a FOREIGN KEY, you can't link the tables using just order_id. You will need to include all the columns that are part of the COMPOSITE KEY inside the FOREIGN KEY relation.
I have read somewhere here that having primary key in each every table is a good thing to do... Let me say I have two tables "student" and "student_details" and i am using INNODB
"student" has a few columns like - student_id(Primary Key), student_name
"student_details" has a few columns like - student_id(Foreign Key), Address, Phone, Mobile, etc..
Do "student_details" still need a primary key?
Whether you know it or not, what you are doing is column partitioning the table. You can have studentdetails.studentid be both a primary key and a foreign key. No problem with that. So, you can have a primary key in the table.
There are several reasons to do column partitioning, usually related to performance on commonly used columns or to create rows with more than the maximum number of columns. I doubt either of these apply in your case.
In fact, given the nature of the data, the studentdetails table is actually storing a "slowly-changing dimension". In simpler language, students move, so their address changes. Students change their telephone number. And so on. What you should really have is an effective and end date for each student details record. Then you can add an auto-incrementing primary key (which is what I would do) or you could declare studentdetails(studentid, effdate) as the primary key.
Imagine we have three tables in a MySQL database:
posts
categories
category_post
There is a one-to-many relationship between posts and categories so that a single post may have many categories.
The category_post table is the pivot table between categories and posts and has the following columns:
id (primary key, auto-incrementing, big integer)
category_id
post_id
Let's also imagine that we have 1,000,000 rows in our category_post table.
My question is:
Is there any performance benefit to having the id column in the category_post table or does it just take up extra space?
Posts and categories is probably many-to-many, not one-to-many.
A many-to-many relationship table is best done something like
CREATE TABLE a_b (
a_id ... NOT NULL,
b_id ... NOT NULL,
PRIMARY KEY (a_id, b_id),
INDEX(b_id, a_id) -- include this if you need to go both directions
) ENGINE = InnoDB;
With that, you automatically get "clustered" lookups both directions, and you avoid the unnecessary artificial id for the table.
(By the way, N.B., an implicit PK is 6 bytes, not 8. There is a lengthy post by Jeremy Cole on the topic.)
A one-to-many relationship does not need this extra table. Instead, have one id inside the other table. For example, a City table will have the id for the Country in it.
Having category_id and post_id as a compound primary key will have better performance than having an extra id as a primary key. This is because making it a primary key will also create an index on it automatically. If you really want an extra Id column you can improve performance by manually defining an index on category_id and post_id. There is no benefit of having an extra key column though and this is generally a bad practice.
not having id is good, but when you care about ordering by the pivot table you will need to have id or timestamp in pivot table
I have two columns in a table that will always be unique, vendor_identifier and product_identifier. Both of them are about equal length. Should I add both of them as primary keys, or only one, or some variant of that? Is there any difference between adding one or two here?
are que querying by both keys? or maybe one at the time?
depending on the answer you can do a composite index or two different indexes.. if you are adding two different indexes remember that the most used one should be at the left
but basically all depends of the architecture of your app / and the DB schema you choose to use...
In MySql the primary key gets the clustered index, so you should make the primary key be the unique identifier you will most frequently query. (This includes joins.)
It's not quite clear from your question if those two fields are each unique on their own, or if they're only guaranteed to be unique as a combination. If they should always be unique individually, then at the least you should put a separate unique index on each of them. If they're only unique in combination, then that's your only guarantee of uniqueness and the primary key should be the two of them together as a single key.
You can only have one be the primary key. You can have the other be a UNIQUE key.
Whichever you prefer to be the default PRIMARY KEY is your choice.
There is something you need to ask yourself:
Will a table that has both columns allow multiple products?
Will a table that has both columns allow multiple vendor?
Will a table that has both columns allow the tuple (vendor,product) one or more times?
Answering these rhetorial questions will help you decide whether a table has one of the following as the PRIMARY KEY
vendor_identifier
product_identifier
vendor_identifier,product_identifier
Consider the following:
(1) is the combination of vendor_id and product_id also guaranteed to be unique?
(2) will you always search with both vendor_id and product_id?
A compound primary key only makes sense if you can answer yes to both. If you cannot, then just select the one with higher cardinality to be the primary key and make a secondary index on the other.
since you dont describe your tables - i'm going to suggest that you actually have 3 tables here:
VENDOR
--------
vendor_id
other_cols
PRODUCT
---------
product_id
other_cols
VENDOR_PRODUCT
--------------
vendor_id
product_id
price-description-dates etc.
in this case - the VENDOR_ID in the VENDOR table is the PK.
the PRODUCT_ID in the PRODUCT table is the PK (for that table)
the VENDOR_ID in the VENDOR_PRODUCT table is a foreign key
the PRODUCT_ID in the VENDOR_PRODUCT table is a foreign key
you may choose to enforce uniqueness on the pair VENDOR_ID, PRODUCT_ID in the VENDOR_PRODUCT table, or not as you choose. If unique, they may be acting as a COMPOUND KEY in that table. If you need to reference rows in the VENDOR_PRODUCT from somewhere else in your schema, then you may consider a new single value primary key instead of copying these two columns to the new table and trying to get the FK definitions correct.
Assuming your vendor_identifier is a foreign key relating to a vendor table, and product_identifier is a foreign key relating to a product table, I'd create an autonumber field (vendor_product_identifier, perhaps?) to be the primary key of the table that has both vendor_id and product_id in it. Then I'd place a unique index on the combination of vendor_id and product_id.
So, the general idea would be:
Vendor
------
vendor_identifier PK
name
phone
etc...
Product
-------
product_identifier PK
name
category
etc...
Vendor_Product
--------------
vendor_product_identifier //"AUTONUMBER PK"
vendor_identifier //"FK to Vendor, and part of COMBOINDEX1"
product_identifier //"FK to Vendor, and part of COMBOINDEX1"
etc...
Having a new key for vendor_product gives you just one key to pass around on the application side to refer to a combination of both vendor and product. Having a unique index on the combination of vendor_id and product_id in the vendor_product table ensures that you won't get duplicate entries for that combination of data either (has to be a unique index though, not just an index).