我有一个包含用户元数据的表。有4个字段...只有当另一个键包含特定值时,MySQL唯一键
`ID`,`meta_name`,`meta_value`,`user_id`
我想在此表中存储电子邮件。自然,这些必须是独一无二的。不过,我想将其他数据存储在此表中,其中数据不需要是唯一的。有没有什么办法可以将'meta_value'
限制为唯一,只有'meta_name'
等于'email'?
我有一个包含用户元数据的表。有4个字段...只有当另一个键包含特定值时,MySQL唯一键
`ID`,`meta_name`,`meta_value`,`user_id`
我想在此表中存储电子邮件。自然,这些必须是独一无二的。不过,我想将其他数据存储在此表中,其中数据不需要是唯一的。有没有什么办法可以将'meta_value'
限制为唯一,只有'meta_name'
等于'email'?
通过MySQL的约束 - 没有。
但是,您可以使用插入/更新触发器来验证数据的唯一性并禁止非法操作。
这里是INSERT触发器的草案(你可以在这里发挥它:http://sqlfiddle.com/#!2/5c9e3):
DELIMITER //
CREATE TRIGGER VerifyInsert BEFORE INSERT ON YourTestTable
FOR EACH ROW
BEGIN
IF (SELECT COUNT(1) FROM YourTestTable
WHERE YourTestTable.meta_name = 'EMail' AND YourTestTable.meta_value = NEW.meta_value
AND NEW.meta_name = YourTestTable.meta_name) > 0 THEN
SIGNAL SQLSTATE '45001' SET MESSAGE_TEXT = 'VerifyInsertFailed';
END IF;
END;
//
随着MySQL的约束上这是不可能的,没有特别的技巧(如冗余列unique_helper
与meta_name
= email
恒定值并且对于每个其他+ UNIQUE
索引为unique_helper
+ meta_value
)。
但是你可以在InnoDB表使用自定义触发:(rememeber把yourTable
名)从数据库
CREATE TRIGGER triggerName
BEFORE INSERT ON yourTable
FOR EACH ROW
BEGIN
IF NEW.meta_name = 'email' AND EXISTS (SELECT 1 FROM yourTable WHERE meta_name='email' AND meta_value=NEW.meta_value)
THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Duplicate email';
END IF;
END;
感谢rogal111,我还没有听说过SIGNAL - 我会研究它。 – Shane
直接?你必须创建一个存储过程来添加到这个表中,当meta_name是电子邮件时,你执行表锁,检查电子邮件然后解锁表 – Hawili
不,这正是不使用这种设计的原因。如果'meta_name'可能值的数量很小,则将它们定义为列(然后放置一个约束将很简单);否则请考虑将它们存储在不同的表中。 – raina77ow