具有多个属性的独特组合

时间:2013-07-12 15:23:26

标签: mysql sql database

我要做的是设置数据库表,以便一组多个属性必须是唯一的,但可以尽可能多地放入数据库中。例如,如果我将以下信息与ID作为主键:

 id    email                  name     value
  1      a@gmail.com           A        AValue
  2      a@gmail.com           A        BValue
  3      b@gmail.com           B        CValue

我不想

 id     email                 name     value 
  4      a@gmail.com           B        yetAnotherValue

可以将电子邮件用于其他名称。我希望它抛出异常。有没有办法在没有触发器或创建单独的表的情况下执行此操作。如果没有,为什么不呢?谢谢。

1 个答案:

答案 0 :(得分:1)

您的问题意味着name应该“依赖”email。因此,您的架构违反了3NF,并且在没有充分理由的情况下应该避免:相反,您应该有一个(email, name)对的表格,UNIQUE约束在email上定义}列(以及name列上的另一列,如果同一名称无法与多个电子邮件地址关联):

CREATE TABLE email_names (PRIMARY KEY (email))
  AS SELECT DISTINCT email, name FROM your_table

然后,您的数据表应该只包含一个外键到这个新表中:

ALTER TABLE your_table
  DROP COLUMN name,
  ADD FOREIGN KEY (email) REFERENCES email_names (email)

要检索包含数据的名称,您需要在相关的SELECT语句中将表连接在一起:

SELECT o.id, o.email, n.name, o.value
FROM   your_table AS o JOIN email_names AS n USING (email)

然而, 有时是使用非规范化模式的充分理由 - 通常在性能问题发挥作用时 - 这种性质的约束可以在MySQL中实施。在引用“预期的”性能问题之前,应该注意Knuth的格言“过早优化是所有邪恶的根源”,并且由于采用了索引,上述方法将非常高效。不过,要在现有表中强制执行此约束:

  1. 在上面创建的表中的组合列上创建一个复合索引:

    ALTER TABLE email_names
      ADD INDEX (email, name)
    
  2. 然后,改为以上对当前表的更改,在新表中定义复合外键

    ALTER TABLE your_table
      ADD FOREIGN KEY (email, name) REFERENCES email_names (email, name)