阻止MySQL在UNIQUE约束中容忍多个NULL

时间:2012-02-14 16:41:57

标签: mysql sql mysql5

我的SQL架构是

CREATE TABLE Foo (
 `bar` INT NULL ,
 `name` VARCHAR (59) NOT NULL ,
 UNIQUE ( `name`, `bar` )
) ENGINE = INNODB;

MySQL允许重复以下语句,导致重复。

INSERT INTO Foo (`bar`, `name`) VALUES (NULL, 'abc');

尽管有

UNIQUE ( `name`, `bar` )

为什么容忍这种情况?如何阻止它?

4 个答案:

答案 0 :(得分:12)

警告:此答案已过时。从MySQL 5.1开始,不支持BDB。

取决于MySQL Engine TypeBDB使用NULL不允许多个UNIQUE值,MyISAMInnoDB允许使用NULL多个UNIQUE

答案 1 :(得分:2)

通常,根据存储引擎,NULL可能会或可能不会被视为唯一值。您必须使用不会将NULL识别为唯一值的存储引擎,例如。 InnoDB或MyISAM。

要解决此问题,您可以创建一个“空值”,例如99999999,您可以将其识别为NULL,因为无法更改存储引擎决定处理唯一键中的空值的方式。

答案 2 :(得分:1)

更新:您应该在下面的评论中使用@greenoldman建议的想法。创建一个带触发器的布尔字段,根据您的可空字段是否为NULL来设置值,然后将唯一约束中的布尔字段与定义唯一性的其他字段组合。


如果你必须强制执行唯一约束但是还需要在列上有一个外键,那么我找到了解决这个问题的方法,因此要求它可以为空。我的解决方案来自this,需要额外的空间。这是一个带有数字id字段的示例。

基本概念是你必须创建另一个不可为空的字段,该字段具有可空字段的值,并且外键与触发器重复。然后,将对不可空的重复字段强制执行唯一约束。为此,您需要定义一个不可为空的字段,其默认值为0,类似于:

ALTER TABLE `my_table` ADD  `uniq_foo` int(10) UNSIGNED NOT NULL DEFAULT '0';

然后你只需要定义一些这样的触发器:

DROP TRIGGER IF EXISTS `my_table_before_insert`;
DELIMITER ;;
CREATE TRIGGER `my_table_before_insert` BEFORE INSERT ON `my_table`
FOR EACH ROW
BEGIN
    SET NEW.uniq_foo = IFNULL(NEW.foo_id, 0);
END;;
DELIMITER ;

DROP TRIGGER IF EXISTS `my_table_before_update`;
DELIMITER ;;
CREATE TRIGGER `my_table_before_update` BEFORE UPDATE ON `my_table`
FOR EACH ROW
BEGIN
    SET NEW.uniq_foo = IFNULL(NEW.foo_id, 0);
END;;
DELIMITER ;

答案 3 :(得分:0)

BDB不允许使用UNIQUE多个NULL值。 但是MySQL放弃了BDB引擎(http://dev.mysql.com/doc/relnotes/mysql/5.1/en/news-5-1-12.html)。

现在:http://dev.mysql.com/doc/refman/5.5/en/create-index.html

  

对于所有引擎,UNIQUE索引允许包含NULL的列的多个NULL值。   如果为UNIQUE索引中的列指定前缀值,则列值在前缀中必须是唯一的。