我要做的是设置数据库表,以便一组多个属性必须是唯一的,但可以尽可能多地放入数据库中。例如,如果我将以下信息与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
可以将电子邮件用于其他名称。我希望它抛出异常。有没有办法在没有触发器或创建单独的表的情况下执行此操作。如果没有,为什么不呢?谢谢。
答案 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的格言“过早优化是所有邪恶的根源”,并且由于采用了索引,上述方法将非常高效。不过,要在现有表中强制执行此约束:
在上面创建的表中的组合列上创建一个复合索引:
ALTER TABLE email_names
ADD INDEX (email, name)
然后,改为以上对当前表的更改,在新表中定义复合外键:
ALTER TABLE your_table
ADD FOREIGN KEY (email, name) REFERENCES email_names (email, name)