Related
I'm building an ecommerce website for fun with three main components: frontend in Angular, MySQL database and a PHP backend that will function as a REST API.
The inventory database consists of products of which there are many variants (Yes, I've seen many questions on StackExchange discussing these kind of issues but I havent found a satisfying soultion yet). After reading several horror stories of using an EAV approach, Im avoiding that.
I think I have made a database solution that works, but Im uncertain to how I should query the data. As there are several many-to-many relationships a query for 1 product and all its variants can return several rows where only a couple columns contain "new" data.
(TL:DR) Main question: When querying a product for all its variants (colors, sizes of available colors and quantity of a color/size variant), what is most efficient:
Perform 1 database query returning many rows where I would need to build an associative array in PHP, discarding "duplicate" data?
Perform several queries when retrieving all variants of a product?
Or is there a flaw in the database design which is the cause of these issues?
Database schema:
CREATE TABLE IF NOT EXISTS `products` (
`productID` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`longDescription` TEXT,
`shortDescription` VARCHAR(1000),
PRIMARY KEY (`productID`)
);
INSERT INTO `products` (`productID`, `name`, `longDescription`, `shortDescription`) VALUES
(1, 'A shirt', 'Long description of this product', 'shortDesc of shirt');
CREATE TABLE IF NOT EXISTS `productpricing` (
`productID` INT(11) NOT NULL,
`startDate` TIMESTAMP NOT NULL DEFAULT '1971-01-01 00:00:00',
`endDate` TIMESTAMP NOT NULL DEFAULT '2099-01-01 00:00:00',
`price` DECIMAL(10, 2) NOT NULL,
PRIMARY KEY(`productID`, `endDate`),
FOREIGN KEY (`productID`) REFERENCES products(`productID`)
);
INSERT INTO `productpricing` (`productID`, `startDate`, `endDate`, `price`) VALUES
(1, '1971-01-01 00:00:00', '2099-01-01 00:00:00', 309.99);
CREATE TABLE IF NOT EXISTS `categories` (
`categoryID` INT(11) NOT NULL AUTO_INCREMENT,
`categoryName` VARCHAR(100) NOT NULL,
PRIMARY KEY (`categoryID`)
);
INSERT INTO `categories` (`categoryID`, `categoryName`) VALUES
(1, 'Test Category');
CREATE TABLE IF NOT EXISTS `sizes` (
`sizeID` INT(11) NOT NULL,
`size` INT NOT NULL,
PRIMARY KEY (`sizeID`)
);
INSERT INTO `sizes` (`sizeID`, `size`) VALUES
(1, 50),
(2, 56),
(3, 62),
(4, 68),
(5, 74),
(6, 80),
(7, 86);
CREATE TABLE IF NOT EXISTS `colors` (
`colorID` INT(11) NOT NULL,
`color` VARCHAR(100) NOT NULL,
PRIMARY KEY (`colorID`)
);
INSERT INTO `colors` (`colorID`, `color`) VALUES
(1, "Red"),
(2, "White"),
(3, "Blue"),
(4, "Purple");
CREATE TABLE IF NOT EXISTS `product_variants` (
`productvariantID` INT(11) NOT NULL,
`productID` INT(11) NOT NULL,
`categoryID` INT(11) NOT NULL,
`colorID` INT(11) NOT NULL,
`sizeID` INT(11) NOT NULL,
`sku` VARCHAR(50) NOT NULL UNIQUE,
`quantity` INT(11) NOT NULL,
`isActive` BOOLEAN NOT NULL DEFAULT 0,
PRIMARY KEY (`productvariantID`),
UNIQUE (`productID`, `colorID`, `sizeID`),
FOREIGN KEY (`productID`) REFERENCES products(`productID`),
FOREIGN KEY (`categoryID`) REFERENCES categories(`categoryID`),
FOREIGN KEY (`colorID`) REFERENCES colors(`colorID`),
FOREIGN KEY (`sizeID`) REFERENCES sizes(`sizeID`)
);
INSERT INTO `product_variants` (`productvariantID`, `productID`, `categoryID`, `colorID`, `sizeID`, `sku`, `quantity`, `isActive`) VALUES
(1, 1, 1, 2, 1, 'clalb121', 2, 1),
(2, 1, 1, 3, 2, 'clalb132', 1, 1),
(3, 1, 1, 2, 2, 'clalb122', 5, 1);
CREATE TABLE IF NOT EXISTS `images` (
`imageID` INT(11) NOT NULL AUTO_INCREMENT,
`imageFilename` VARCHAR(100) NOT NULL,
PRIMARY KEY(`imageID`)
);
INSERT INTO `images` (`imageID`, `imageFilename`) VALUES
(1, 'shirtwhite1.jpg'),
(2, 'shirtwhite2.jpg'),
(3, 'shirtblue1.jpg'),
(4, 'shirtblue2.jpg');
CREATE TABLE IF NOT EXISTS `product_variant_images` (
`productvariantID` INT(11) NOT NULL,
`imageID` INT(11) NOT NULL,
FOREIGN KEY(`productvariantID`) REFERENCES product_variants(`productvariantID`),
FOREIGN KEY(`imageID`) REFERENCES images(`imageID`)
);
INSERT INTO `product_variant_images` (`productvariantID`, `imageID`) VALUES
(1, 1),
(1, 2),
(2, 3),
(2, 4),
(3, 1),
(3, 2);
(Im going to remove categoryID from the product_variants table as different variants of the same product does not have different categories.)
Example of querying 1 product for all its variants (In one query):
SELECT
p.productID,
p.name,
p.longDescription,
p.shortDescription,
colors.color,
sizes.size,
pvar.quantity,
pprice.price,
images.imageFilename
FROM products as p
JOIN product_variants as pvar
ON p.productID = pvar.productID
JOIN productpricing as pprice
ON pprice.productID = p.productID
JOIN colors
ON colors.colorID = pvar.colorID
JOIN sizes
ON sizes.sizeID = pvar.sizeID
JOIN product_variant_images as pvari
ON pvari.productvariantID = pvar.productvariantID
JOIN images
ON images.imageID = pvari.imageID
WHERE p.productID = 1 AND pvar.isActive = 1 AND NOW() BETWEEN pprice.startDate AND pprice.endDate;
Example return set:
# productID, name, longDescription, shortDescription, color, size, quantity, price, imageFilename
'1', 'A shirt', 'Long description of this product', 'shortDesc of shirt', 'White', '50', '2', '309.99', 'shirtwhite1.jpg'
'1', 'A shirt', 'Long description of this product', 'shortDesc of shirt', 'White', '50', '2', '309.99', 'shirtwhite2.jpg'
'1', 'A shirt', 'Long description of this product', 'shortDesc of shirt', 'White', '56', '5', '309.99', 'shirtwhite1.jpg'
'1', 'A shirt', 'Long description of this product', 'shortDesc of shirt', 'White', '56', '5', '309.99', 'shirtwhite2.jpg'
'1', 'A shirt', 'Long description of this product', 'shortDesc of shirt', 'Blue', '56', '1', '309.99', 'shirtblue1.jpg'
'1', 'A shirt', 'Long description of this product', 'shortDesc of shirt', 'Blue', '56', '1', '309.99', 'shirtblue2.jpg'
As can be seen in the result set the white variant (of one size) of the shirt is associated with two images, therefore there are two records with only imageFilename containing "new data".
Example of using several queries:
SELECT
p.productID,
p.name,
p.longDescription,
p.shortDescription,
pprice.price
FROM products as p
JOIN productpricing as pprice
ON pprice.productID = p.productID
WHERE p.productID = 1 AND NOW() BETWEEN pprice.startDate AND pprice.endDate;
SELECT
c.color,
s.size,
pvar.quantity
FROM product_variants as pvar
JOIN colors AS c
ON c.colorID = pvar.colorID
JOIN sizes as s
ON s.sizeID = pvar.sizeID
WHERE pvar.productID = 1;
SELECT DISTINCT
c.color,
i.imageFilename
FROM images AS i
JOIN product_variant_images as pvari
ON pvari.imageID = i.imageID
JOIN product_variants as pvar
ON pvar.productvariantID = pvari.productvariantID
JOIN colors AS c
ON c.colorID = pvar.colorID
WHERE pvar.productID = 1;
Several queries result sets:
# productID, name, longDescription, shortDescription, price
'1', 'A shirt', 'Long description of this product', 'shortDesc of shirt', '309.99'
# color, size, quantity
'White', '50', '2'
'Blue', '56', '1'
'White', '56', '5'
# color, imageFilename
'White', 'shirtwhite1.jpg'
'White', 'shirtwhite2.jpg'
'Blue', 'shirtblue1.jpg'
'Blue', 'shirtblue2.jpg'
Any advice regarding the database design/queries is much appreciated!
I have the code here, but it was written by my teachers
create database abc_quanlybanhang111111;
use abc_quanlybanhang111111;
create table abc_nhacc
(
MaCC1 varchar(10) primary key,
TenNhaCC varchar(50) not null,
DiaChiCC varchar(50),
PhoneCC varchar(11),
);
create table abc_mamh
(
MaMH1 varchar(50) primary key,
TenMH varchar(100),
DonGia int,
SoLuong int,
MaCC1 varchar(10) foreign key references abc_nhacc(MaCC1)
);
create table abc_khachhang
(
MaMh1 VARCHAR(10) PRIMARY KEY,
TenKh varchar(50),
DiaChi varchar(50),
SĐT int,
);
CREATE TABLE abc_donhang
(
MaDH1 varchar(10) primary key,
NgayDH DATE default GetDate(),
MaKH1 varchar(10) foreign key references abc_khachhang(MaMH1)
);
create table abc_chitietdonhang
(
MaDH1 varchar(10) foreign key references abc_donhang(MaDH1) ,
MaMH1 varchar(50) foreign key references abc_mamh(MaMH1),
SoLuong int check (soluong>0)
constraint pk_dmhh primary key ( MaDH1, MaMH1)
);
insert into abc_nhacc
values
('K001', 'THE GIOI DI DONG', '121 TRAN QUANG KHAI', '0164789720'),
('K002', 'NGUYEN KIM', '12 TRAN PHU', '0161792793'),
('K003', 'THIEN HOA', '2 BA HUYEN THANH QUAN', '094850873'),
('K004', 'PHONG VU', '32 LE VAN VIET QUAN 9', '85839201'),
('K005', 'TAN BINH', '14 NGUYEN THI DINH', '0912012901')
SELECT *
FROM abc_nhacc;
insert into abc_mamh
values
('S001', 'MSI ACER GAMING', 2000000, 1, 'K001');
insert into abc_mamh
values
('S002', 'MSI ASUS GAMING', 1000000, 10, 'K002'),
('S003', 'MSI GAMING', 1100000, 1, 'K003'),
('S004', 'LENOVO GAMING', 2000, 111, 'K004'),
('S005', 'IPHONE', 120000, 1, 'K005')
SELECT *
FROM abc_mamh;
insert into abc_khachhang
values
('KH1', 'LONG NGUYEN', '12 TRAN QUANG DIEU QUAN 1', '0938078972');
insert into abc_khachhang
values
('KH2', 'THONG NGUYEN', '1 TRAN DIEU QUAN 2', '0968071972'),
('KH3', 'THANH NGUYEN', '23 NGUYEN THI DINH QUAN 8', '0138073972'),
('KH4', 'THINH NGUYEN', '1 TRUONG DINH QUAN 1', '016479828'),
('KH5', 'LINH TRAN', '2 TRAN QUANG KHAI QUAN 1', '0938078122')
SELECT *
FROM abc_mamh;
insert into abc_chitietdonhang
values('DH001', 'MH001', 2),
('DH002', 'MH002', 3),
('DH003', 'MH003', 1),
('DH004', 'MH004', 9),
('DH004', 'MH005', 4),
('DH003', 'MH006', 11),
('DH001', 'MH007', 12);
I have try to fix the code with the step delete the foreign key but it always show errors after I delete it :
Msg 547, Level 16, State 0, Line 72
The INSERT statement conflicted with the FOREIGN KEY constraint "FK__abc_chiti__MaDH1__4222D4EF". The conflict occurred in database "abc_quanlybanhang1111111", table "dbo.abc_donhang", column 'MaDH1'
Please help me learn how to can fix this errors. Thank.
You have to add the rows in abc_donhang which you are trying to reference in your insert into abc_chitietdonhang ... query. You try to reference the row with the Id DH001, but it doesn't exists (yet). Same goes for the Id MH001, it doesn't exists in the abc_mamh table either.
I have to do a many to many tables between a table MEAL and a table RESTAURANT. First I created the two tables:
CREATE TABLE RESTAURANT (
ID_Restaurant VARCHAR(10) NOT NULL,
ID_Hotel VARCHAR(10) NOT NULL,
Name VARCHAR(30) NOT NULL,
Number_of_Tables INT(3) NOT NULL,
PRIMARY KEY (ID_Restaurant),
FOREIGN KEY (ID_Hotel) REFERENCES HOTEL (ID_Hotel));
CREATE TABLE MEAL(
ID_Meal VARCHAR(10) NOT NULL,
Name VARCHAR(30) NOT NULL,
Preparation_Time VARCHAR(20),
Cooking_Time VARCHAR(20),
PRIMARY KEY (ID_Meal));
Then I created the 'joint' tables:
CREATE TABLE MEAL_SERVED(
ID_Meal VARCHAR(10) NOT NULL,
ID_Restaurant VARCHAR(10) NOT NULL,
Price INT(5) NOT NULL,
PRIMARY KEY (ID_Meal, ID_Restaurant, Price),
FOREIGN KEY(ID_Meal) REFERENCES MEAL(ID_Meal),
FOREIGN KEY(ID_Restaurant) REFERENCES RESTAURANT (ID_Restaurant));
I entered some data in the first two tables:
INSERT INTO RESTAURANT(ID_Restaurant, ID_Hotel, Name, Number_of_Tables)
VALUES ('REST1', 'H1', 'Benares Indisk Restaurant', 26);
('REST2', 'H2', 'La Gaichel', 35),
('REST3', 'H3', 'Tapas Restaurant', 17),
('REST4', 'H4', 'Faubourg 101', 19),
('REST5', 'H5', 'Pizzeria Roma', 38);
INSERT INTO MEAL(ID_Meal, Name, Preparation_Time, Cooking_Time)
VALUES ('MEAL1', 'Croque-Monsieur', '5 min', '4 min'),
('MEAL2', 'Salad', '6 min', NULL),
('MEAL3', 'Hot Dog', '3 min', '2min'),
('MEAL4', 'Panini', '6 min', '5 min'),
('MEAL5', 'Coca-Cola', NULL, NULL);
Until, now there is no problem, but when I tried to enter data in the third tables with:
INSERT INTO MEAL_SERVED(ID_Meal, ID_Restaurant, Price)
VALUES ('MEAL1', 'REST1', 50),
('MEAL4', 'REST1', 50),
('MEAL5', 'REST1', 35),
('MEAL1', 'REST2', 3.5),
('MEAL2', 'REST2', 3.5),
('MEAL4', 'REST2', 5);
for instance, then I have an error message:
FOREIGN KEY constraint failed: INSERT INTO MEAL_SERVED(ID_Meal, ID_Restaurant, Price)
I don't understand why I have this message and how to correct it. Thanks in advance.
As Shadow said in the comment section.
First, fix your typo in one of your SQL statements:
INSERT INTO RESTAURANT(ID_Restaurant, ID_Hotel, Name, Number_of_Tables)
VALUES ('REST1', 'H1', 'Benares Indisk Restaurant', 26);
('REST2', 'H2', 'La Gaichel', 35),
('REST3', 'H3', 'Tapas Restaurant', 17),
('REST4', 'H4', 'Faubourg 101', 19),
('REST5', 'H5', 'Pizzeria Roma', 38);
should be:
INSERT INTO RESTAURANT(ID_Restaurant, ID_Hotel, Name, Number_of_Tables)
VALUES ('REST1', 'H1', 'Benares Indisk Restaurant', 26),
('REST2', 'H2', 'La Gaichel', 35),
('REST3', 'H3', 'Tapas Restaurant', 17),
('REST4', 'H4', 'Faubourg 101', 19),
('REST5', 'H5', 'Pizzeria Roma', 38);
Second:
Do yourself a favor and use integers for primary keys and with the auto_increment option, you can just ignore the id.
CREATE TABLE RESTAURANT (
`id` INT NOT NULL AUTO_INCREMENT,
`hotel` INT NOT NULL,
`name` VARCHAR(30) NOT NULL,
`numberOfTables` INT NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (hotel) REFERENCES HOTEL (`id`));
CREATE TABLE MEAL(
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(30) NOT NULL,
`preparationTime` VARCHAR(20),
`cookingTime` VARCHAR(20),
PRIMARY KEY (`id`));
CREATE TABLE MEAL_SERVED(
`id` INT NOT NULL AUTO_INCREMENT,
`meal` INT NOT NULL,
`restaurant` INT NOT NULL,
Price FLOAT NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY(meal) REFERENCES MEAL(`id`),
FOREIGN KEY(restaurant) REFERENCES RESTAURANT (`id`));
Data:
INSERT INTO RESTAURANT(`hotel`, `name`, `numberOfTables`)
VALUES ('1', 'Benares Indisk Restaurant', 26),
(2, 'La Gaichel', 35),
(3, 'Tapas Restaurant', 17),
(4, 'Faubourg 101', 19),
(5, 'Pizzeria Roma', 38);
INSERT INTO MEAL(`name`, `preparationTime`, `cookingTime`)
VALUES ('Croque-Monsieur', '5 min', '4 min'),
('Salad', '6 min', NULL),
('Hot Dog', '3 min', '2min'),
('Panini', '6 min', '5 min'),
('Coca-Cola', NULL, NULL);
INSERT INTO MEAL_SERVED(`meal`, `restaurant`, `price`)
VALUES (1, 1, 50),
(4, 1, 50),
(5, 1, 35),
(1, 2, 3.5),
(2, 2, 3.5),
(4, 2, 5);
Third:
INT(3) has no effects. The space for the INT will be allocated anyway.
You can use TINYINT or SMALLINT instad, maybe. Look here: https://dev.mysql.com/doc/refman/5.7/en/integer-types.html
Fourth:
Use camel-case or snake-case but not both please ;-)
i keep getting the error 1136 in mysql, i need help, what's wrong with this code?
CREATE table Artist (
ArtistID INT,Salary varchar (20),Contract_End_Date date,Trackname varchar (20),
Artistname varchar (15),
Fname varchar (20),
Lname varchar (20),
Birthday date ,
PRIMARY KEY(ArtistID),
FOREIGN KEY (Salary) REFERENCES Contract(Salary),
FOREIGN KEY (Contract_End_Date) REFERENCES Contract(Contract_End_Date),
FOREIGN KEY (Trackname) REFERENCES Track(Trackname));
INSERT INTO Artist(ArtistID, Artistname, Fname, Lname, Birthday, Salary, Contract_End_Date, Trackname) VALUES (
'1','JM','John','Mcfierceson','1978-05-20','$100000','2017-05-08','Cries by the Ocean',
'2','Ray','Ray','Grueson','1990-07-10','$500000','2017-09-12','Jumping Jacks',
'3','Shiin','Charlie','Shiin','1989-02-12','$700000','2020-12-17','I can feel my head',
'4','King','Bobby','Naval','1978-09-24','$7878787','2014-10-11','Rain',
'5','Yellowman','Chris, Yellow','1984-11-11','$8000000','2014-09-08','Falling',
'6','Sting','Karl','Shakur','1967-10-06','$5600000','2014-05-15','X',
'7','Kboy','Kendrick','Maine','1990-12-25','$8099999','2021-09-12','Trick');
CREATE table Contract (
Contractcode varchar (20), Artistname varchar(15),
Contract_start_Date date,
Contract_End_Date date,
Salary varchar(20),
PRIMARY KEY(Contractcode),
FOREIGN KEY (Artistname) REFERENCES Artist(Artistname));
INSERT INTO Contract VALUES (
'1004JM', 'JM', '2011-05-08', '2017-05-08', '$100000 ',
'2424RG', 'Ray', '2013-09-12', '2017-09-12', '$500000',
'3446SC', 'Shiin', '2010-12-17', '2020-12-17', '$700000',
'9999BN', 'King', '1990-10-11', '2014-10-11', '$7878787',
'2546CY', 'Yellowman', '2000-09-08', '2014-09-08', '$8000000',
'4446KS', 'Sting', '1980-05-15', '2014-05-15', '$5600000',
'5454KM', 'Kboy', '2010-09-12', '2021-09-12', '$8099999');
CREATE table Track (
Trackname varchar (20),
Artistname varchar (15),
Tracktype varchar (20),
Tracklength int ,
PRIMARY KEY(Trackname),
FOREIGN KEY (Artistname) REFERENCES Artist(Artistname));
INSERT INTO Track VALUES (
'Cries by the Ocean', 'Jumping Jacks', 'I can feel my head', 'Rain', 'Falling', 'X', 'Trick',
'JM', 'Ray', 'Shiin', 'King', 'Yellowman', 'Sting', 'Kboy',
'Rock', 'Rock', 'Indie', 'RnB', 'Rock', 'Rock', 'Rock',
'4', '5', '3', '3', '5', '5', '5');
Mysql Error 1136 means Column count doesn't match value count.
You seem to be inserting multiple rows with a single insert statement.
Each row of data should be in its own set of parenthesis. And each set of parenthesis should be separated by a comma. Something like this:
INSERT INTO artist
(artistid, artistname, fname, lname, birthday, salary, contract_end_date, trackname)
VALUES
('1', 'JM', 'John', 'Mcfierceson', '1978-05-20', '$100000', '2017-05-08', 'Cries by the Ocean'),
('2', 'Ray', 'Ray', 'Grueson', '1990-07-10', '$500000', '2017-09-12', 'Jumping Jacks'),
('3', 'Shiin', 'Charlie', 'Shiin', '1989-02-12', '$700000', '2020-12-17', 'I can feel my head'),
('4', 'King', 'Bobby', 'Naval', '1978-09-24', '$7878787', '2014-10-11', 'Rain'),
('5', 'Yellowman', 'Chris, Yellow', '1984-11-11', '$8000000', '2014-09-08', 'Falling'),
('6', 'Sting', 'Karl', 'Shakur', '1967-10-06', '$5600000', '2014-05-15', 'X'),
('7', 'Kboy', 'Kendrick', 'Maine', '1990-12-25', '$8099999', '2021-09-12', 'Trick');
INSERT Syntax (Documentation)
You are trying to plug more data than you have fields for. Try this:
CREATE table Track ( Trackname varchar (20),
Artistname varchar (15),
Tracktype varchar (20),
Tracklength int ,
PRIMARY KEY(Trackname),
FOREIGN KEY (Artistname)
REFERENCES Artist(Artistname));
INSERT INTO Track VALUES ( 'Cries by the Ocean', 'JM', 'Rock', '4'),
('Jumping Jacks', 'Ray', 'Rock', '5');
Enclose each row in a set of (), one row of data at a time.
I am looking to create a MySQL shop that is capable of handling multiple categories. I have all of the category facility etc sorted but the bit I am not getting anywhere with is this..
Each item can have multiple options, for example a T-Shirt should have the options 'Colour' and 'Size'. I then need to create a number of variations/ derived products from the parent product specifying that an Extra Large Blue T-Shirt has 20 in stock (for example). The problem is, it's not just clothes being sold, it could be any number of things. So I also need this schema to be able to handle an infinite number of variants such as '6mm' 'Large' Birthday Card with 'Sports Car' design. 6mm, Large, and 'Ace' being the variables. This way I am able to ensure that we do not have any stock control issues. If it is any use to you, below is my current site structure.
Existing Database Schema http://www.hallwaystudios.com/screenshots/uploads/g5B7SNKU.png
I hope you understand what I mean and that someone has an answer to my problem! Many thanks in advance (and after of-course)
Not too sure what the problem is here... I'd probably create four tables:
-- a table of item types (t-shirt, birthday card, etc.)
CREATE TABLE ItemTypes (
TypeID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
TypeName VARCHAR(20) NOT NULL
);
-- a table of associated properties
CREATE TABLE TypeProperties (
PropertyID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
TypeID INT NOT NULL,
PropName VARCHAR(20) NOT NULL,
INDEX(Property, TypeID),
FOREIGN KEY(TypeID) REFERENCES ItemTypes(TypeID)
);
-- a table of specific items (XL Blue t-shirt, large bday card w/sports car, etc.)
CREATE TABLE Items (
ItemID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
TypeID INT NOT NULL,
ItemName VARCHAR(100) NOT NULL,
ItemPrice DECIMAL UNSIGNED NOT NULL,
ItemStock INT UNSIGNED NOT NULL,
INDEX(ItemID, TypeID),
FOREIGN KEY(TypeID) REFERENCES ItemTypes(TypeID)
);
-- the dictionary of property values
CREATE TABLE ItemProperties (
ItemID INT NOT NULL,
TypeID INT NOT NULL,
PropertyID INT NOT NULL,
Value VARCHAR(20) NOT NULL,
PRIMARY KEY(ItemID, Property),
INDEX(ItemID, TypeID),
INDEX(PropertyID, TypeID),
FOREIGN KEY( TypeID) REFERENCES ItemTypes ( TypeID),
FOREIGN KEY(ItemID, TypeID) REFERENCES Items (ItemID, TypeID),
FOREIGN KEY(PropertyID, TypeID) REFERENCES TypeProperties(PropertyID, TypeID)
);
It ought to be fairly obvious, but just in case, the example data would look something like:
INSERT INTO ItemTypes (TypeID, TypeName) VALUES
(1, 'T-Shirt' ),
(2, 'Birthday Card'),
(3, 'Balloon' );
INSERT INTO TypeProperties(PropertyID, TypeID, PropName) VALUES
(51, 1, 'Colour' ), (52, 1, 'Size'),
(53, 2, 'Size/mm'), (54, 2, 'Size'), (55, 2, 'Design'),
(56, 3, 'Colour' );
INSERT INTO Items (ItemID, TypeID, ItemName, ItemPrice, ItemStock) VALUES
(101, 1, 'Extra Large Blue T-Shirt', 10.99, 20),
(102, 2, '6mm Large Birthday Card with Sports Car Design', 2.99, 17),
(103, 1, 'Extra Large Black T-Shirt', 10.99, 5),
(104, 3, 'Pink balloon', 0.10, 60);
INSERT INTO ItemProperties (ItemID, TypeID, PropertyID, Value) VALUES
(101, 1, 51, 'Blue' ),
(101, 1, 52, 'Extra Large'),
(102, 2, 53, '6' ),
(102, 2, 54, 'Large' ),
(102, 2, 55, 'Sports Car' ),
(103, 1, 51, 'Black' ),
(103, 1, 52, 'Extra Large'),
(104, 3, 56, 'Pink' );