visual español database database-design mysqli relational-database

database - español - Variantes de productos de modelado



mysql workbench database (1)

He estado tratando de modelar variantes de productos y pensé que podría necesitar usar EAV. Podría haber podido hacerlo sin EAV, pero me preocupa que me haya perdido algo. Aquí está mi diseño:

Esto es lo que estoy tratando de representar:

  1. Un product puede tener 0 o más product variants (por ejemplo, un producto de camiseta puede tener variantes de tamaño y color).
  2. Una product variant puede tener 1 o más product variant options (por ejemplo, la variante de tamaño puede ser pequeña, mediana o grande).
  3. Un SKU está compuesto por 1 o más product variant options (la tabla product_variant_option_combination contendría todas las combinaciones posibles de `product_variant_options. Entonces, si hubiera 3 tamaños y 3 colores, habría 3 * 3 = 9 combinaciones - y cada combinación se daría su propio SKU y precio).
  4. Un product puede tener 1 o más SKUs .

Si el producto no tiene ninguna variante, simplemente ignora product_variants , product_variant_options y product_variant_option_combinations .

¿Es este diseño de sonido? ¿Terminaré teniendo problemas para consultar esto? ¿Se escalará? ¿Está normalizado?

ACTUALIZACIÓN 1

@Edper:

Si un producto puede tener 0 o muchas (modo opcional) variantes del producto (por ejemplo, tamaño, color, etc.). ¿Sigue que las variantes de un producto también pueden tener 0 o muchos productos que tienen esa variante?

No lo creo. Es posible que un producto como una "camiseta" tenga una variante de "tamaño" y otro producto como "pantalones" también tenga una variante de "tamaño", pero creo que eso es sólo una casualidad. No es necesario que el "tamaño" aparezca solo como un registro porque "tamaño" puede tener un contexto diferente.

Los productos con los que estoy tratando varían mucho y están obligados a tener variantes con nombres similares.

ACTUALIZACIÓN 2:

Aquí hay un ejemplo de cómo veo mis datos:

He encajonado el Size variante y sus valores asociados. Quiero dejar claro que no se consideran datos duplicados. La variante de Size para los 3 productos es solo una casualidad. No hay necesidad de normalizar esto, creo. Cada producto puede tener 0 o más variantes, y son desconocidas para mí. Espero "duplicados" (aunque no son realmente duplicados, ya que siempre están en el contexto de un producto en particular, por lo tanto, la variante "Tamaño" del Widget 1 no es la misma que la variante "Tamaño" del Widget 2).

ACTUALIZACIÓN 3:

Ahora veo que, en mi diseño, es posible que un product tenga múltiples productos_varianzas idénticas. Creo que eso se puede resolver haciendo product_variants . product_id y product_variants . name una clave compuesta. Esto significa que el Widget 1 solo puede tener una variante de "Tamaño" una vez.

product_variant_options . product_variant_id product_variant_options . name también tendría que ser una clave compuesta.

ACTUALIZACIÓN 4:

Al actualizar mi product_variant_option_combinations para incluir product_variant_id (FK a product_variants . id ) y aplicar una restricción UNIQUE con product_variant_option_combinations . sku_id y product_variant_option_combinations . product_variant_id , creo que pude evitar el problema de tener un SKU que es "Pequeño" y "Grande". ¿Es esto correcto?

-- 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 */;


Podrías tener un diseño como:

+---------------+ +-------------------+ | PRODUCTS |-----< PRODUCT_VARIANTS | +---------------+ +-------------------+ | #product_id | | #product_id | | product_name | | #variant_id | +---------------+ | sku_id | | +-------------------+ | | +--------^--------+ +--------^--------+ | PRODUCT_OPTIONS |-----< VARIANT_VALUES | +-----------------+ +-----------------+ | #product_id | | #product_id | | #option_id | | #variant_id | +--------v--------+ | #option_id | | | value_id | +-----------------+ +--------v--------+ | OPTIONS | | +-----------------+ | | #option_id | | | option_name | | +-----------------+ | | | +-------^-------+ | | OPTION_VALUES |---------------+ +---------------+ | #option_id | | #value_id | | value_name | +---------------+

Con las claves primarias, únicas y extranjeras:

  • PRODUCTOS
    • PK: product_id
    • Reino Unido: nombre_producto
  • OPCIONES
    • PK: option_id
    • Reino Unido: option_name
  • OPTION_VALUES
    • PK: option_id, value_id
    • Reino Unido: option_id, value_name
    • FK: option_id OPCIONES DE REFERENCIA (option_id)
  • PRODUCT_OPTIONS
    • PK: product_id, option_id
    • FK: product_id REFERENCIAS PRODUCTOS (product_id)
    • FK: option_id OPCIONES DE REFERENCIA (option_id)
  • PRODUCT_VARIANTS
    • PK: product_id, variant_id
    • Reino Unido: sku_id
    • FK: product_id REFERENCIAS PRODUCTOS (product_id)
  • VARIANT_VALUES
    • PK: product_id, variant_id, option_id
    • FK: product_id, variant_id REFERENCIAS PRODUCT_VARIANTS (product_id, variant_id)
    • FK: product_id, option_id REFERENCIAS PRODUCT_OPTIONS (product_id, option_id)
    • FK: option_id, value_id REFERENCES OPTION_VALUES (option_id, value_Id)

Tienes:

  • PRODUCTOS por ejemplo, camisa, jumper, pantalones
  • OPCIONES ej. Tamaño, Color, Longitud
  • OPTION_VALUES p. Ej. Tamaño: pequeño, mediano, grande; Color - Rojo, Blanco, Azul
  • PRODUCT_OPTIONS ej. Camisa - Tamaño, Color; Pantalones - Longitud, Color

A continuación, debe crear una matriz n-dimensional, con el número de dimensiones igual al número de opciones para el producto. Cada elemento de la matriz corresponde a una variante de producto. Siempre habrá al menos una variante de producto para cada producto; Como siempre existe la opción pseudo del producto "tal cual"

  • PRODUCT_VARIANTS ej. Camisa 1, Camisa 2
  • VARIANT_VALUES por ejemplo, Camisa 1: Rojo pequeño; Camisa 2: Blanco pequeño

Es posible que desee tener una validación para asegurarse de que no se asigne un SKU a menos que se hayan especificado valores para todas las opciones asociadas con un producto.

De acuerdo con la hoja de cálculo de cómo ve sus datos, puede ingresar datos en sus tablas de la siguiente manera:

PRODUCTS ======== id name --- -------- 1 Widget 1 2 Widget 2 3 Widget 3 PRODUCT_VARIANTS ================ id product_id name --- ---------- ------ 1 1 Size (Widget 1) 2 1 Color (Widget 1) 3 2 Size (Widget 2) 4 3 Class (Widget 3) 5 3 Size (Widget 3) PRODUCT_VARIANT_OPTIONS ======================= id product_variant_id name --- ------------------ ------------- 1 1 Small (Widget 1; Size) 2 1 Large (Widget 1; Size) 3 2 White (Widget 1; Color) 4 2 Black (Widget 1; Color) 5 3 Small (Widget 2; Size) 6 3 Medium (Widget 2; Size) 7 4 Amateur (Widget 3; Class) 8 4 Professional (Widget 3; Class) 9 5 Medium (Widget 3; Size) 10 5 Large (Widget 3; Size) SKUS ==== id product_id sku price --- ---------- ------ ----- 1 1 W1SSCW 10 (Widget 1) 2 1 W1SSCB 10 (Widget 1) 3 1 W1SLCW 12 (Widget 1) 4 1 W1SLCB 15 (Widget 1) 5 2 W2SS 100 (Widget 2) 6 2 W2SM 100 (Widget 2) 7 3 W3CASM 50 (Widget 3) 8 3 W3CASL 50 (Widget 3) 9 3 W3CPSM 150 (Widget 3) 10 3 W3CPSL 160 (Widget 3) PRODUCT_VARIANT_OPTION_COMBINATIONS =================================== product_variant_option_id sku_id ------------------------- ------ 1 1 (W1SSCW; Size; Small) 3 1 (W1SSCW; Color; White) 1 2 (W1SSCB; Size; Small) 4 2 (W1SSCB; Color; Black) 2 3 (W1SLCW; Size; Large) 3 3 (W1SLCW; Color; White) 2 4 (W1SLCB; Size; Large) 4 4 (W1SLCB; Color; Black) 5 5 (W2SS; Size; Small) 6 6 (W2SM; Size; Medium) 7 7 (W3CASM; Class; Amateur) 9 7 (W3CASM; Size; Medium) 7 8 (W3CASL; Class; Amateur) 10 8 (W3CASL; Size; Large) 8 9 (W3CPSM; Class; Professional) 9 9 (W3CPSM; Size; Medium) 8 10 (W3CPSL; Class; Professional) 10 10 (W3CPSL; Size; Large)

Parece que no hay nada en su diseño que impida la adición de la entrada del registro (product_variant_option_id: 2; sku_id 1), por lo que SKU W1SSCW tiene ahora las opciones de Small y Large. No hay nada que detenga la entrada del registro (product_variant_option_id: 7; sku_id: 1), por lo que SKU W1SSCW también tiene la opción Amateur.

Según la hoja de cálculo de cómo ve sus datos, puede ingresar datos en mis tablas de la siguiente manera:

PRODUCTS ======== product_id product_name ---------- ------------ 1 Widget 1 2 Widget 2 3 Widget 3 OPTIONS ======= option_id option_name --------- ----------- 1 Size SL 2 Color 3 Size SM 4 Class 5 Size ML OPTION_VALUES ============= option_id value_id value_name --------- -------- ------------ 1 1 Small (Size SL) 1 2 Large (Size SL) 2 1 White (Color) 2 2 Black (Color) 3 1 Small (Size SM) 3 2 Medium (Size SM) 4 1 Amateur (Class) 4 2 Professional (Class) 5 1 Medium (Size ML) 5 2 Large (Size ML) PRODUCT_OPTIONS =============== product_id option_id ---------- --------- 1 1 (Widget 1; Size SL) 1 2 (Widget 1; Color) 2 3 (Widget 2; Size SM) 3 4 (Widget 3; Class) 3 5 (Widget 4; Size ML) PRODUCT_VARIANTS ================ product_id variant_id sku_id ---------- ---------- ------ 1 1 W1SSCW (Widget 1) 1 2 W1SSCB (Widget 1) 1 3 W1SLCW (Widget 1) 1 4 W1SLCB (Widget 1) 2 1 W2SS (Widget 2) 2 2 W2SM (Widget 2) 3 1 W3CASM (Widget 3) 3 2 W3CASL (Widget 3) 3 3 W3CPSM (Widget 3) 3 4 W3CPSL (Widget 3) VARIANT_VALUES ============== product_id variant_id option_id value_id ---------- ---------- --------- -------- 1 1 1 1 (W1SSCW; Size SL; Small) 1 1 2 1 (W1SSCW; Color; White) 1 2 1 1 (W1SSCB; Size SL; Small) 1 2 2 2 (W1SSCB; Color; Black) 1 3 1 2 (W1SLCW; Size SL; Large) 1 3 2 1 (W1SLCW; Color; White) 1 4 1 2 (W1SLCB; Size SL; Large) 1 4 2 2 (W1SLCB; Color; Black) 2 1 3 1 (W2SS; Size SM; Small) 2 2 3 2 (W2SM; Size SM; Medium) 3 1 4 1 (W3CASM; Class; Amateur) 3 1 5 1 (W3CASM; Size ML; Medium) 3 2 4 1 (W3CASL; Class; Amateur) 3 2 5 2 (W3CASL; Size ML; Large) 3 3 4 2 (W3CPSM; Class; Professional) 3 3 5 1 (W3CPSM; Size ML; Medium) 3 4 4 2 (W3CPSL; Class; Professional) 3 4 5 2 (W3CPSL; Size ML; Large)

En mi diseño, no pudo ingresar el registro VARIANT_VALUES adicional (product_id: 1; variant_id: 1; option_id: 1; value_id: 2) - por lo que SKU W1SSCW tiene ahora las opciones de Small y Large - debido a la clave principal en VARIANT_VALUES y el registro VARIANT_VALUES existente (product_id: 1; variant_id: 1; option_id: 1; value_id: 1). En mi diseño, no pudo ingresar el registro VARIANT_VALUES (product_id: 1; variant_id: 1; option_id: 4; value_id: 1), por lo que SKU W1SSCW también tiene la opción Amateur, debido a la clave externa que hace referencia a Product_OPTIONS y la falta de el registro en esta tabla de (product_id: 1; option_id: 4) indica que Class es una opción válida para el producto Widget 1.

EDITAR : diseño sin tabla PRODUCT_OPTIONS

Podrías tener un diseño como:

+---------------+ +---------------+ | PRODUCTS |-----< PRODUCT_SKUS | +---------------+ +---------------+ | #product_id | | #product_id | | product_name | | #sku_id | +---------------+ | sku | | | price | | +---------------+ | | +-------^-------+ +------^------+ | OPTIONS |------< SKU_VALUES | +---------------+ +-------------+ | #product_id | | #product_id | | #option_id | | #sku_id | | option_name | | #option_id | +---------------+ | value_id | | +------v------+ +-------^-------+ | | OPTION_VALUES |-------------+ +---------------+ | #product_id | | #option_id | | #value_id | | value_name | +---------------+

Con las claves primarias, únicas y extranjeras:

  • PRODUCTOS
    • PK: product_id
    • Reino Unido: nombre_producto
  • OPCIONES
    • PK: product_id, option_id
    • Reino Unido: product_id, option_name
  • OPTION_VALUES
    • PK: product_id, option_id, value_id
    • Reino Unido: product_id, option_id, value_name
    • FK: product-id, option_id REFERENCIAS OPCIONES (product_id, option_id)
  • PRODUCT_SKUS
    • PK: product_id, sku_id
    • Reino Unido: sku_id
    • FK: product_id REFERENCIAS PRODUCTOS (product_id)
  • SKU_VALUES
    • PK: product_id, sku_id, option_id
    • FK: product_id, sku_id REFERENCIAS PRODUCT_SKUS (product_id, sku_id)
    • FK: product_id, option_id REFERENCIAS OPCIONES (product_id, option_id)
    • FK: product_id, option_id, value_id REFERENCES OPTION_VALUES (product_id, option_id, value_id)

Según la hoja de cálculo de cómo ve sus datos, puede ingresar datos en estas tablas de la siguiente manera:

PRODUCTS ======== product_id product_name ---------- ------------ 1 Widget 1 2 Widget 2 3 Widget 3 OPTIONS ======= product_id option_id option_name ---------- --------- ----------- 1 1 Size (Widget 1) 1 2 Color (Widget 1) 2 1 Size (Widget 2) 3 1 Class (Widget 3) 3 2 Size (Widget 3) OPTION_VALUES ============= product_id option_id value_id value_name ---------- --------- -------- ------------ 1 1 1 Small (Widget1; Size) 1 1 2 Large (Widget1; Size) 1 2 1 White (Widget1; Color) 1 2 2 Black (Widget1; Color) 2 1 1 Small (Widget2; Size) 2 1 2 Medium (Widget2; Size) 3 1 1 Amateur (Widget3; Class) 3 1 2 Professional (Widget3; Class) 3 2 1 Medium (Widget3; Size) 3 2 2 Large (Widget3; Size) PRODUCT_SKUS ============ product_id sku_id sku ---------- ------ ------ 1 1 W1SSCW (Widget 1) 1 2 W1SSCB (Widget 1) 1 3 W1SLCW (Widget 1) 1 4 W1SLCB (Widget 1) 2 1 W2SS (Widget 2) 2 2 W2SM (Widget 2) 3 1 W3CASM (Widget 3) 3 2 W3CASL (Widget 3) 3 3 W3CPSM (Widget 3) 3 4 W3CPSL (Widget 3) SKU_VALUES ========== product_id sku_id option_id value_id ---------- ------ --------- -------- 1 1 1 1 (W1SSCW; Size; Small) 1 1 2 1 (W1SSCW; Color; White) 1 2 1 1 (W1SSCB; Size; Small) 1 2 2 2 (W1SSCB; Color; Black) 1 3 1 2 (W1SLCW; Size; Large) 1 3 2 1 (W1SLCW; Color; White) 1 4 1 2 (W1SLCB; Size; Large) 1 4 2 2 (W1SLCB; Color; Black) 2 1 1 1 (W2SS; Size; Small) 2 2 1 2 (W2SM; Size; Medium) 3 1 1 1 (W3CASM; Class; Amateur) 3 1 2 1 (W3CASM; Size; Medium) 3 2 1 1 (W3CASL; Class; Amateur) 3 2 2 2 (W3CASL; Size; Large) 3 3 1 2 (W3CPSM; Class; Professional) 3 3 2 1 (W3CPSM; Size; Medium) 3 4 1 2 (W3CPSL; Class; Professional) 3 4 2 2 (W3CPSL; Size; Large)