【问题标题】:MySql - Product Variants Table (Wide Table) - Unique with NULLsMySql - 产品变体表(宽表) - 具有 NULL 的唯一性
【发布时间】:2016-11-24 06:30:28
【问题描述】:

我有一个 products 表和一个 product_variants 表(一对多)。

product_variants 表结构如下:

CREATE TABLE product_variants (
  id int(11) NOT NULL AUTO_INCREMENT,
  id_product int(11) NOT NULL,
  id_colourSet int(11) DEFAULT NULL,
  id_size int(11) DEFAULT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY UNIQUE (id_product,id_colourSet,id_size),
  KEY idx_prod (id_product),
  KEY idx_colourSet (id_colourSet),
  KEY idx_size (id_size),
  CONSTRAINT fk_df_product_variants_id_colurSet FOREIGN KEY (id_colourSet) REFERENCES df_colour_sets (id_colourSet) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT fk_df_product_variants_id_product FOREIGN KEY (id_product) REFERENCES df_products (id) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT fk_df_product_variants_id_size FOREIGN KEY (id_size) REFERENCES df_sizes (id) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB

这些选项在编译时是已知的。每个选项都有一个专用表的外键,唯一键是所有选项的组合。

然后我使用"ON DUPLICATE KEY UPDATE ..." 语句插入产品,如果变体已经存在,则查询将使用现有变体。

问题是某些产品没有颜色,也没有尺寸。在这种情况下,唯一约束失败,我在 product_variants 表中插入了许多几乎为空的行。

为了解决这个问题,我在各个选项表中为每个选项(例如“NO_COLOR”、“NO_SIZE”)创建了一个“NULL”值,并将其用作 product_variants 中选项列的默认值表。

这是推荐的解决方案吗?有没有更好的方法来构建这些数据?我真的很想避免 EAV 设计。

谢谢

【问题讨论】:

    标签: mysql sql entity-attribute-value


    【解决方案1】:

    指定一个意味着“缺失值”的魔法值并不是几乎在所有情况下都是正确的解决方案。这就是 NULL 的用途。

    也不清楚“NO_COLOR”如何用于整数。我猜它会映射到值 0,通常不会在自动增量列中使用。

    您可以创建另一个列作为三个唯一键列的哈希,默认为 '' 以避免空问题。然后对该散列设置唯一约束。

    CREATE TABLE product_variants (
      id int(11) NOT NULL AUTO_INCREMENT,
      id_product int(11) NOT NULL,
      id_colourSet int(11) DEFAULT NULL,
      id_size int(11) DEFAULT NULL,
      option_hash binary(16) NOT NULL,
      PRIMARY KEY (id),
      UNIQUE KEY (option_hash),
      KEY idx_prod (id_product),
      KEY idx_colourSet (id_colourSet),
      KEY idx_size (id_size),
      CONSTRAINT fk_df_product_variants_id_colurSet FOREIGN KEY (id_colourSet) REFERENCES df_colour_sets (id_colourSet) ON DELETE NO ACTION ON UPDATE NO ACTION,
      CONSTRAINT fk_df_product_variants_id_product FOREIGN KEY (id_product) REFERENCES df_products (id) ON DELETE NO ACTION ON UPDATE NO ACTION,
      CONSTRAINT fk_df_product_variants_id_size FOREIGN KEY (id_size) REFERENCES df_sizes (id) ON DELETE NO ACTION ON UPDATE NO ACTION
    ) ENGINE=InnoDB;
    
    CREATE TRIGGER product_variants_ins BEFORE INSERT ON product_variants
    FOR EACH ROW SET option_hash = UNHEX(MD5(CONCAT_WS('|',
        COALESCE(id_product, ''),
        COALESCE(id_colourSet, ''),
        COALESCE(id_size, ''))));
    
    CREATE TRIGGER product_variants_upd BEFORE UPDATE ON product_variants
    FOR EACH ROW SET option_hash = UNHEX(MD5(CONCAT_WS('|',
        COALESCE(id_product, ''),
        COALESCE(id_colourSet, ''),
        COALESCE(id_size, ''))));
    

    【讨论】:

    • 触发器能很好地处理事务吗?例如。一个事务中有许多“INSERT ... ON DUPLICATE KEY UPDATE ...”语句。
    • @mils,您几乎可以在单个事务中进行任意数量的更改,包括在触发器内部进行的更改。触发器中的更改与生成触发器的更改属于同一事务。
    猜你喜欢
    • 2019-03-05
    • 2017-03-29
    • 1970-01-01
    • 1970-01-01
    • 2015-02-19
    • 1970-01-01
    • 2017-01-01
    • 2018-12-24
    • 1970-01-01
    相关资源
    最近更新 更多