My SQL schema is
CREATE TABLE Foo (
`bar` INT NULL ,
`name` VARCHAR (59) NOT NULL ,
UNIQUE ( `name`, `bar` )
) ENGINE = INNODB;
MySQL is allowing the following statement to be repeated, resulting in duplicates.
INSERT INTO Foo (`bar`, `name`) VALUES (NULL, 'abc');
despite having
UNIQUE ( `name`, `bar` )
Why is this tolerated and how do I stop it?
Warning: This answer is outdated. As of MySQL 5.1, BDB is not supported.
It depends on MySQL Engine Type
. BDB
doesn't allow multiple NULL
values using UNIQUE
but MyISAM
and InnoDB
allows multiple NULL
s even with UNIQUE
.
In general, depending on the storage engine, NULL
may or may not be seen as a unique value. You must be using a storage engine which doesn't recognise NULL
as a unique value, eg. InnoDB or MyISAM.
To get around this you can create a "null value", such as 99999999, which you can recognise as NULL
as there is no way to change how your storage engine decides to deal with nulls in unique keys.
UPDATE: You should use the idea suggested by @greenoldman in the comment below instead. Create a boolean field with triggers to set the value based on whether your nullable field is NULL or not and then combine the boolean field in a unique constraint with the other fields that define uniqueness.
I found a way around this problem if you must enforce the unique constraint but also need to have a foreign key on the column, thus requiring it to be nullable. My solution was derived from this and will require a little extra space. This is an example with a numeric id field.
The basic concept is that you have to create another non-nullable field that will have the value of your nullable field with the foreign key duplicated into it with a trigger. The unique constraint will then be enforced on the non-nullable duplicate field. To do this you need to define a non-nullable field with a default value of 0
similar to this:
ALTER TABLE `my_table` ADD `uniq_foo` int(10) UNSIGNED NOT NULL DEFAULT '0';
Then you just have to define some triggers like this:
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 ;
BDB doesn't allow multiple NULL values using UNIQUE.
But MySQL drop the BDB engine (http://dev.mysql.com/doc/relnotes/mysql/5.1/en/news-5-1-12.html).
So now : http://dev.mysql.com/doc/refman/5.5/en/create-index.html
For all engines, a UNIQUE index permits multiple NULL values for columns that can contain NULL.
If you specify a prefix value for a column in a UNIQUE index, the column values must be unique within the prefix.