Я бы рекомендовал либо Наследование бетонных таблиц , либо Наследование таблиц классов . Оба дизайна удовлетворяют всем четырем вашим критериям.
Наследование бетонного стола:
- Ipods хранятся в таблице
product_ipods
со столбцами ID
, Name
, Capacity
, Generation
.
- Футболки хранятся в таблице
product_tshirts
с колонками ID
, Name
, Size
, Color
.
- Определение конкретных типов продуктов содержится в метаданных (определениях таблиц)
product_ipods
и product_tshirts
.
SELECT SUM(Capacity) FROM product_ipods GROUP BY Generation
;
В таблице наследования классов:
Общие атрибуты продукта хранятся в таблице Products
со столбцами ID
, Name
.
Ipods хранятся в таблице product_ipods
со столбцами product_id
(внешний ключ к Products.ID
), Capacity
, Generation
.
- Футболки хранятся в таблице
product_tshirts
с колонками product_id
(внешний ключ к Products.ID
), Size
, Color
.
- Определение конкретных типов продуктов содержится в метаданных (определениях таблиц)
products
, product_ipods
и product_tshirts
.
SELECT SUM(Capacity) FROM product_ipods GROUP BY Generation
;
См. Также мой ответ на " Таблица продуктов, много видов продуктов, каждый продукт имеет много параметров ", где я опишу несколько решений для типа проблемы, которую вы описываете. Я также подробно расскажу о , почему EAV - это неправильный дизайн.
Комментарий от @dcolumbus:
С CTI, будет ли каждая строка product_ipods вариацией со своей собственной ценой?
Я ожидаю, что столбец цены появится в таблице products
, если цена для каждого типа товара есть. В CTI таблицы типов продуктов обычно содержат столбцы для атрибутов, которые относятся только к этому типу продуктов. Любые атрибуты, общие для всех типов продуктов, получают столбцы в родительской таблице.
Кроме того, при хранении позиций заказа вы бы затем сохранили строку из product_ipods как позицию?
В таблице позиций храните идентификатор продукта, который должен иметь одинаковое значение как в таблице products
, так и в таблице product_ipods
.
Комментарии от @dcolumbus:
Мне кажется, что это излишне ... в этом сценарии я не вижу смысла в дополнительной таблице. Но даже если подстолбок имеет смысл, что связывает id
?
Смысл этой таблицы состоит в том, чтобы хранить столбцы, которые не нужны для всех других типов продуктов.
Идентификатором подключения может быть число с автоматическим приращением. Таблице подтипов не нужно автоматически увеличивать свой собственный идентификатор, потому что она может просто использовать значение, сгенерированное супер-таблицей.
CREATE TABLE products (
product_id INT AUTO_INCREMENT PRIMARY KEY,
sku VARCHAR(30) NOT NULL,
name VARCHAR(100) NOT NULL,
price NUMERIC(9,2) NOT NULL
);
CREATE TABLE product_ipods (
product_id INT PRIMARY KEY,
size TINYINT DEFAULT 16,
color VARCHAR(10) DEFAULT 'silver',
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
INSERT INTO products (sku, name, price) VALUES ('IPODS1C1', 'iPod Touch', 229.00);
INSERT INTO product_ipods VALUES (LAST_INSERT_ID(), 16, 'silver');
INSERT INTO products (sku, name, price) VALUES ('IPODS1C2', 'iPod Touch', 229.00);
INSERT INTO product_ipods VALUES (LAST_INSERT_ID(), 16, 'black');
INSERT INTO products (sku, name, price) VALUES ('IPODS1C3', 'iPod Touch', 229.00);
INSERT INTO product_ipods VALUES (LAST_INSERT_ID(), 16, 'red');
INSERT INTO products (sku, name, price) VALUES ('IPODS2C1', 'iPod Touch', 299.00);
INSERT INTO product_ipods VALUES (LAST_INSERT_ID(), 32, 'silver');
INSERT INTO products (sku, name, price) VALUES ('IPODS2C2', 'iPod Touch', 299.00);
INSERT INTO product_ipods VALUES (LAST_INSERT_ID(), 32, 'silver');
INSERT INTO products (sku, name, price) VALUES ('IPODS2C3', 'iPod Touch', 299.00);
INSERT INTO product_ipods VALUES (LAST_INSERT_ID(), 32, 'red');