MySQL 唯一键仅在另一个键包含特定值的情况下

Posted

技术标签:

【中文标题】MySQL 唯一键仅在另一个键包含特定值的情况下【英文标题】:MySQL unique key only where another key contains a specific value 【发布时间】:2012-09-05 06:44:09 【问题描述】:

我有一个包含用户元数据的表。有4个字段...

`ID`,`meta_name`,`meta_value`,`user_id`

我想在此表中存储电子邮件。当然,这些必须是唯一的。但是,我也想在此表中存储其他数据,其中数据不需要是唯一的。有什么办法可以限制'meta_value' 是唯一的,前提是'meta_name' 等于“电子邮件”?

【问题讨论】:

直接来自数据库?您必须创建一个存储过程才能添加到此表中,当 meta_name 是电子邮件时,您会执行表锁定,检查电子邮件然后解锁表 不,这正是不使用这种设计的原因。如果meta_name 可能值的数量很小,请将它们定义为列(然后放置约束将是微不足道的);否则考虑将它们存储在不同的表中。 【参考方案1】:

通过 mysql 的约束 - 没有。

但是您可以使用插入/更新触发器来验证数据的唯一性并禁止非法操作。

这是一个插入触发器的草稿(你可以在这里玩: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;

//

【讨论】:

Kuba,可以添加唯一约束以满足我上面概述的要求吗? (唯一取决于另一个键) 不,正如我所说:“通过 MySQL 的约束 - 不”。 抱歉,我在阅读您的回复时弄糊涂了 - 我的意思是更新触发器,而不是唯一约束。 请注意SIGNAL 仅适用于 MySQL > 5.5 或 sth.【参考方案2】:

使用 MySQL 约束,如果没有特殊技巧,这是不可能的(例如冗余列 unique_helper 具有恒定值 meta_name=email 并且彼此随机 + UNIQUE 索引 unique_helper+meta_value)。

但您可以在 innoDB 表中使用自定义 TRIGGER:(请记住输入 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;

【讨论】:

以上是关于MySQL 唯一键仅在另一个键包含特定值的情况下的主要内容,如果未能解决你的问题,请参考以下文章

使用带有 Hibernate 的 JPA 注释来描述外键仅在子表中的 @OneToMany 关系

在其中一列中具有多个空值的复合唯一键约束

mysql数据库索引

mysql主键普通索引唯一索引和全文索引的比较

mysql主键普通索引唯一索引和全文索引的比较

生成具有特定列且仅在 corrplot 中具有显着值的相关矩阵