Mysql – Unique Index/Constraint with multiple columns, one column is nullable

indexMySQLnull

My questions is whether it's possible to have unique index comprised of multiple columns where one of the columns may contain NULL.

Example: A table named 'regulated_person' has a number of columns including LAST_NAME, FIRST_NAME, BIRTH_DATE and ALIAS. The data type for BIRTH_DATE is date, for the others it's String/VARCHAR. LAST_NAME, FIRST_NAME and BIRTH_DATE are not nullable, i.e. they require values. ALIAS serves as a tie-breaker for cases where two or more people have the same first/last names and are born the same day. Because the tie-breaking situations are not common I want to avoid the need to provide an ALIAS value unless it's necessary.

By way of background the primary key for the table is handled by an auto-increment generator. The purpose for the unique index is to provide a 'business key' that will identify the row without having to resort to the primary key. I'm working with MySQL 5.1.35 and Hibernate ORM ver. 4.3.10.

Any suggestions as to server/database providers apart from MySQL would be welcome.

Thanks in advance for any guidance, and also apologies in advance for any unintended violations of 'forum protocol' as this is the first time I've submitted a question ANYWHERE.

Best Answer

Since the alias column is nullable, if you add a unique constraint on the composite (last_name, first_name, birth_date, alias), there will still be duplicates allowed, with the same values in the first 3 columns and NULL in the alias. The constraint is skipped / accepted when at least one value is null. MySQL documentation on CREATE TABLE is not very clear but you can test the behaviour:

  • 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.

What you could do is to define the alias as not null and add a default value, (say 'NONE' or 'DEFAULT' or the empty string ''). You (or the user) will not have to provide that value, it will be automatically saved in all rows. Once someone tries to add a new row with same last name, first name and birth date as an existing row, the unique constraint will forbid it. I guess you could add some procedure at that point, that asks for a different value for the alias and adds the new row with it.