0

我要做的是设置数据库表,以便一组多个属性必须是唯一的,但可以尽可能多次地放入数据库中。例如,如果我有以下以 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

如果电子邮件使用不同的名称,则可以进行组合。我希望它抛出异常。有没有办法在没有触发器或创建单独的表的情况下做到这一点。如果不是,为什么不呢?谢谢你。

4

1 回答 1

1

您的问题意味着name应该“依赖”于email. 因此,您的架构违反了3NF,并且,如果没有充分的理由,应该避免:相反,您应该有一个在列上定义约束的(email, name)对表(如果同一名称不能与多个电子邮件相关联,则在列上定义另一个约束)地址):UNIQUEemailname

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)
    
于 2013-07-12T15:24:46.840 回答