This is a very common scenario in database design, you are looking to create a n:m
(Many to Many) relationship between the order and the product. This can be achieved with a linking table.
- you could use a comma-delimited string, JSON, XML or other serialization method to store this data in a single string column, but that complicates the querying of your data and you lose some of the power that using an RDBMS gives you.
- Other RDBMS allow
VARCHAR(MAX)
which alleviates the field length issue when storing serialized data like this, in MySQL just set the field length to a very large number, or use the max value like VARCHAR(65535)
. See this topic for more help if you go down this route.
In the conceptual case of an Order, this is generally solved by adding a child table OrderItem. (or OrderLine) If you see this data in a report of a receipt, each of these items is a line on the receipt so you might see this referred to as a Line or Line Items approach. The minimum fields you need for this in your model are:
Other common fields you might consider for a table like this include:
- Qty: for scenarios where the user might select Extra Tomatoes, or you can simply allow multiple rows with the same
Product_ID
, perhaps you want both?
- Cost_TaxEx: total cost of the Line Item excluding tax
- Cost: total cost _including_tax.
This can be minimally represented in SQL like this:
CREATE TABLE Client (
ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name VARCHAR(100)
)
CREATE TABLE Product (
ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name VARCHAR(100),
Price DECIMAL(13,2) /* Just an assumption on length */
)
CREATE TABLE Order (
ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Client_ID INT NOT NULL,
/* ... Insert other fields here ... */
FOREIGN KEY (Client_ID)
REFERENCES Client (ID)
)
CREATE TABLE OrderItem (
ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Order_ID INT NOT NULL,
Product_ID INT NOT NULL,
/* ... Insert other fields here ... */
FOREIGN KEY (Order_ID)
REFERENCES Order (ID)
ON UPDATE RESTRICT ON DELETE CASCADE, /* the cascade on order:orderitem is up to you */
FOREIGN KEY (Product_ID)
REFERENCES Product (ID) /*DO NOT cascade this relationship! */
)
The above solution allows any number of Product
entries in an Order
but will also allow duplicate Product
's, If you need to enforce only one of each product per Order
, you can add a Unique Constraint to the OrderItem
table:
CREATE TABLE OrderItem (
ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Order_ID INT NOT NULL,
Product_ID INT NOT NULL,
/* ... Insert other fields here ... */
UNIQUE(Order_ID,Product_ID),
FOREIGN KEY (Order_ID)
REFERENCES Order (ID)
ON UPDATE RESTRICT ON DELETE CASCADE, /* the cascade on order:orderitem is up to you */
FOREIGN KEY (Product_ID)
REFERENCES Product (ID) /*DO NOT cascade this relationship! */
)