我一直在尝试对产品变体进行建模,并认为我可能需要使用EAV . 我可能没有EAV就可以做到这一点,但我担心我可能会错过一些东西 . 这是我的设计:
这是我想要表达的内容:
-
A
product
可以具有0或更多product variants
(例如,T恤产品可以具有尺寸和颜色变体) . -
A
product variant
可以有1个或多个product variant options
(例如,大小变体可以是小,中,大) . -
SKU
由1个或多个product variant options
组成(product_variant_option_combination
表将包含`product_variant_options的所有可能组合 . 因此,如果有3种尺寸和3种颜色,则会有3 * 3 = 9种组合 - 并且每种组合都会给予自己的SKU和价格) . -
A
product
可以有1个或多个SKUs
.
如果产品没有任何变体,则只需忽略 product_variants
, product_variant_options
和 product_variant_option_combinations
.
这个设计听起来好吗?我最终会在查询时遇到问题吗?它会扩展吗?它正常化了吗?
UPDATE 1
@Edper:
如果产品可以有0或许多(可选模式)产品变体(例如尺寸,颜色等) . 是否遵循产品变体也可以有0个或多个具有该变体的产品?
我不这么认为 . 像“T恤”这样的产品可能具有“尺寸”变体而另一种产品如“裤子”也可能具有“尺寸”变体,但我认为这只是偶然事件 . 没有必要使“大小”仅显示为一个记录,因为“大小”可能具有不同的上下文 .
我正在处理的产品差异很大,他们必然会有类似命名的变体 .
UPDATE 2:
以下是我如何查看数据的示例:
我已经装了变种 Size
及其相关值 . 我想说清楚这些不被认为是重复数据 . 3种产品的 Size
变体只是偶然的 . 我认为没有必要将其正常化 . 每个产品可以有0个或更多变体 - 我不知道它们 . 我期待"duplicates"(尽管它们不是't really duplicates as they always are in the context of a particular product -- so, Widget 1' s "Size"变体与Widget 2的"Size"变体不同) .
UPDATE 3:
我现在看到,在我的设计中, product
可能有多个相同的 product_variants
. 我认为可以通过制作 product_variants
来解决 . product_id
和 product_variants
. name
复合键 . 这意味着Widget 1只能拥有"Size"变体一次 .
product_variant_options
. product_variant_id
product_variant_options
. name
也需要是一个复合键 .
UPDATE 4:
通过更新我的 product_variant_option_combinations
以包含 product_variant_id
(FK到 product_variants
. id
)并使用 product_variant_option_combinations
强制执行UNIQUE约束 . sku_id
和 product_variant_option_combinations
. product_variant_id
,我想我能够防止出现一个同时具有"Small"和"Large"的SKU的问题 . 这是正确的吗?
-- phpMyAdmin SQL Dump
-- version 4.1.14
-- http://www.phpmyadmin.net
--
-- Host: 127.0.0.1
-- Generation Time: Jul 30, 2014 at 03:35 AM
-- Server version: 5.6.17
-- PHP Version: 5.5.12
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
--
-- Database: `mydb`
--
-- --------------------------------------------------------
--
-- Table structure for table `products`
--
CREATE TABLE IF NOT EXISTS `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
--
-- Dumping data for table `products`
--
INSERT INTO `products` (`id`, `name`) VALUES
(1, 'Widget 1');
-- --------------------------------------------------------
--
-- Table structure for table `product_variants`
--
CREATE TABLE IF NOT EXISTS `product_variants` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` int(11) NOT NULL,
`name` varchar(45) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UNIQUE_product_id_name` (`product_id`,`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
--
-- Dumping data for table `product_variants`
--
INSERT INTO `product_variants` (`id`, `product_id`, `name`) VALUES
(2, 1, 'Color'),
(1, 1, 'Size');
-- --------------------------------------------------------
--
-- Table structure for table `product_variant_options`
--
CREATE TABLE IF NOT EXISTS `product_variant_options` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_variant_id` int(11) NOT NULL,
`name` varchar(45) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UNIQUE_product_variant_id_name` (`product_variant_id`,`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;
--
-- Dumping data for table `product_variant_options`
--
INSERT INTO `product_variant_options` (`id`, `product_variant_id`, `name`) VALUES
(2, 1, 'Large'),
(1, 1, 'Small'),
(4, 2, 'Black'),
(3, 2, 'White');
-- --------------------------------------------------------
--
-- Table structure for table `skus`
--
CREATE TABLE IF NOT EXISTS `skus` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` int(11) NOT NULL,
`sku` varchar(45) NOT NULL,
`price` decimal(10,2) NOT NULL,
PRIMARY KEY (`id`),
KEY `skus_product_id_products_id_idx` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;
--
-- Dumping data for table `skus`
--
INSERT INTO `skus` (`id`, `product_id`, `sku`, `price`) VALUES
(1, 1, 'W1SSCW', '10.00'),
(2, 1, 'W1SSCB', '10.00'),
(3, 1, 'W1SLCW', '12.00'),
(4, 1, 'W1SLCB', '15.00');
-- --------------------------------------------------------
--
-- Table structure for table `skus_product_variant_options`
--
CREATE TABLE IF NOT EXISTS `skus_product_variant_options` (
`sku_id` int(11) NOT NULL,
`product_variant_id` int(11) NOT NULL,
`product_variant_options_id` int(11) NOT NULL,
PRIMARY KEY (`sku_id`,`product_variant_options_id`,`product_variant_id`),
UNIQUE KEY `UNIQUE_sku_id_product_variant_id` (`sku_id`,`product_variant_id`),
KEY `spvo_product_variant_options_id_pro_idx` (`product_variant_options_id`),
KEY `spvo_product_variant_id_product_var_idx` (`product_variant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Dumping data for table `skus_product_variant_options`
--
INSERT INTO `skus_product_variant_options` (`sku_id`, `product_variant_id`, `product_variant_options_id`) VALUES
(1, 1, 1),
(2, 1, 1),
(3, 1, 2),
(4, 1, 2),
(1, 2, 3),
(3, 2, 3),
(2, 2, 4),
(4, 2, 4);
--
-- Constraints for dumped tables
--
--
-- Constraints for table `product_variants`
--
ALTER TABLE `product_variants`
ADD CONSTRAINT `product_variants_product_id_products_id` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;
--
-- Constraints for table `product_variant_options`
--
ALTER TABLE `product_variant_options`
ADD CONSTRAINT `product_variant_options_product_variant_id_product_variants_id` FOREIGN KEY (`product_variant_id`) REFERENCES `product_variants` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;
--
-- Constraints for table `skus`
--
ALTER TABLE `skus`
ADD CONSTRAINT `skus_product_id_products_id` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;
--
-- Constraints for table `skus_product_variant_options`
--
ALTER TABLE `skus_product_variant_options`
ADD CONSTRAINT `skus_product_variant_options_sku_id_skus_id` FOREIGN KEY (`sku_id`) REFERENCES `skus` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
ADD CONSTRAINT `spvo_product_variant_options_id_product_variant_options_id` FOREIGN KEY (`product_variant_options_id`) REFERENCES `product_variant_options` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
ADD CONSTRAINT `spvo_product_variant_id_product_variants_id` FOREIGN KEY (`product_variant_id`) REFERENCES `product_variants` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
1 回答
你可以有一个像这样的设计:
使用主键,唯一键和外键:
产品
PK:product_id
英国:product_name
选项
PK:option_id
UK:option_name
OPTION_VALUES
PK:option_id,value_id
UK:option_id,value_name
FK:option_id REFERENCES OPTIONS(option_id)
PRODUCT_OPTIONS
PK:product_id,option_id
FK:product_id参考产品(product_id)
FK:option_id REFERENCES OPTIONS(option_id)
PRODUCT_VARIANTS
PK:product_id,variant_id
英国:sku_id
FK:product_id参考产品(product_id)
VARIANT_VALUES
PK:product_id,variant_id,option_id
FK:product_id,variant_id REFERENCES PRODUCT_VARIANTS(product_id,variant_id)
FK:product_id,option_id REFERENCES PRODUCT_OPTIONS(product_id,option_id)
FK:option_id,value_id REFERENCES OPTION_VALUES(option_id,value_Id)
你有:
产品,例如衬衫,跳线,长裤
选项,例如尺寸,颜色,长度
OPTION_VALUES例如尺寸 - 小,中,大;颜色 - 红色,白色,蓝色
PRODUCT_OPTIONS,例如衬衫 - 尺码,颜色;长裤 - 长度,颜色
然后,您需要创建一个n维数组,其维数等于产品的选项数 . 数组中的每个元素对应于产品变体 . 每种产品总会至少有一种产品变体;因为产品“as-is”总是存在伪选项
PRODUCT_VARIANTS例如衬衫1,衬衫2
VARIANT_VALUES例如衬衫1:小红色;衬衫2:小白
您可能希望进行验证以确保未分配SKU,除非已为与产品关联的所有选项指定了值 .
根据您如何查看数据的电子表格,您可以在表格中输入数据,如下所示:
您的设计中似乎没有任何内容可以停止添加记录条目(product_variant_option_id:2; sku_id 1),以便SKU W1SSCW现在具有Small和Large选项 . 没有什么可以阻止记录的输入(product_variant_option_id:7; sku_id:1)这样SKU W1SSCW也有选项Amateur .
根据您如何查看数据的电子表格,您可以在我的表格中输入数据,如下所示:
在我的设计中,您无法输入额外的VARIANT_VALUES记录(product_id:1; variant_id:1; option_id:1; value_id:2) - 因此SKU W1SSC现在具有Small和Large选项 - 由于VARIANT_VALUES上的主键和现有的VARIANT_VALUES记录(product_id:1; variant_id:1; option_id:1; value_id:1) . 在我的设计中,您无法输入VARIANT_VALUES记录(product_id:1; variant_id:1; option_id:4; value_id:1) - 因此SKU W1SSCW也有选项Amateur - 由于外键引用PRODUCT_OPTIONS而缺少记录在此表(product_id:1; option_id:4)中,表示Class是产品Widget 1的有效选项 .
EDIT :没有PRODUCT_OPTIONS表的设计
你可以有一个像这样的设计:
使用主键,唯一键和外键:
产品
PK:product_id
英国:product_name
选项
PK:product_id,option_id
UK:product_id,option_name
OPTION_VALUES
PK:product_id,option_id,value_id
UK:product_id,option_id,value_name
FK:product-id,option_id REFERENCES OPTIONS(product_id,option_id)
PRODUCT_SKUS
PK:product_id,sku_id
英国:sku_id
FK:product_id参考产品(product_id)
SKU_VALUES
PK:product_id,sku_id,option_id
FK:product_id,sku_id REFERENCES PRODUCT_SKUS(product_id,sku_id)
FK:product_id,option_id REFERENCES OPTIONS(product_id,option_id)
FK:product_id,option_id,value_id REFERENCES OPTION_VALUES(product_id,option_id,value_id)
根据您如何查看数据的电子表格,您可以在这些表格中输入数据,如下所示: