Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MySQL falsely allowing duplicate entries when one of the fields involved is NULL

Using InnoDB/MySQLi, I have a simple table: mytable. The table has four fields: id (primary, auto_inc), field1, field2, field3. All of them are BIGINT and, except for id, can be NULL.

I have added a unique constraint like so:

ALTER TABLE mytable ADD UNIQUE INDEX(field1,field2,field3);

However, I am perfectly able to add the following rows without any error being generated. I would like for this to generate a 'duplicate' error, but it doesn't:

INSERT INTO mytable VALUES (NULL,3,NULL)
INSERT INTO mytable VALUES (NULL,3,NULL)

It only generates a 'duplicate' error if all of the fields have non-NULL values - e.g.,

INSERT INTO mytable VALUES (2,3,4)
INSERT INTO mytable VALUES (2,3,4)

How can I tell MySQL to generate 'duplicate' errors even if one (or more) of the fields have NULL values?

EDIT: This was previously added as a "bug" to MySQL: http://bugs.mysql.com/bug.php?id=25544

like image 597
a.real.human.being Avatar asked Feb 11 '14 07:02

a.real.human.being


3 Answers

You can't compare NULL's (if you compare anything with NULL even NULL=NULL the results is always FALSE) this behavior is documented in MySQL ref.

A UNIQUE index creates a constraint such that all values in the index must be distinct. An error occurs if you try to add a new row with a key value that matches an existing row. For all engines, a UNIQUE index permits multiple NULL values for columns that can contain NULL.

So I think the only way is define columns NOT NULL or handle this issue in a trigger.

like image 162
valex Avatar answered Nov 14 '22 09:11

valex


The root of the problem is - in comparison of NULL-s. You should understand logical meaning of NULL. And it is "no value". Not "zero value" or "unknown value", but "no value". That's a big difference.

That is why making part of unique index NULL-able is certainly bad idea. You can not compare NULL's as you can not compare two values, both of which are absent. Thus, DBMS can not maintain NULL-s to be unique as far as comparison isn't applicable to them in normal way. Yes, such things as <=> operator exist in MySQL (or IS NULL in other DBMS) - but that is about technical resolution of how to deal with comparisons with NULL values - but not the logical.

So you're in the middle of XY-problem. Do not use NULL-s with unique keys - they can not be there by definition of what is NULL and what is intention of unique key. And from the technical viewpoint (see part about index creation), NULL=NULL will always result in false - thus, it's permitted to insert NULL value if another NULL-value exists.

like image 40
Alma Do Avatar answered Nov 14 '22 09:11

Alma Do


Go to: How to Use Unique Indexes in MySQL and Other Databases and see the "MySQL NULLs" section.

like image 43
Bartosz Polak Avatar answered Nov 14 '22 07:11

Bartosz Polak