Unique values, many NULLs - A Dodgy Constraint.
I have seen several times people requesting to place a unique constraint on a column that should allow many NULLs but only allow unique values.
Personally, I have never had to implement such a constraint, and when I see the question posed I assume it is needed because of a underlying design problem.
This only works for SQL 2K (as you will see in a minute) and requires various SET commands to be in place both an DDL and DML time…
The following solution places a UNIQUE constraint on a Computed column and according to BOL has restrict requirements…
These options must be set to ON:
- ANSI_NULLS
- ANSI_PADDING
- ANSI_WARNINGS
- ARITHABORT
- CONCAT_NULL_YIELDS_NULL
- QUOTED_IDENTIFIER
Assume that the column DC is the target of this dodgy constraint…
--DMLCREATE TABLE DodgyConstraint(DC VARCHAR(50) NULL, HelperColoumn INT identity(1,1) NOT NULL,
ComputedConstraint AS CASE WHEN DC IS NULL THEN CAST(HelperColoumn AS VARCHAR(50)) ELSE DC END, UNIQUE (ComputedConstraint))
–Insert 2 nulls
insert DodgyConstraint (DC) Values (NULL)
insert DodgyConstraint (DC) Values (NULL)
–Insert a couple of "real" value
insert DodgyConstraint (DC) Values ('Dave')
insert DodgyConstraint (DC) Values ('Dingo')
–Violation
insert DodgyConstraint (DC) Values ('Dave')
Select * from DodgyConstraint
One of the first things you would do if this type of constraint is needed is to project away the Identity column and the Computed column in a view and never speak of them again…:-)
Legacy Comments
robvolk
2004-05-21 |
re: Unique values, many NULLs - A Dodgy Constraint. David- Awesome! I have a curve ball situation though, if someone happens to store a number in the DC column, it would violate the constraint. But, I have a solution and it doesn't even require a helper column: CREATE TABLE DodgyConstraint(DC VARCHAR(50) NULL, ComputedConstraint AS CASE WHEN DC IS NULL THEN CAST(newid() AS VARCHAR(50)) ELSE DC END, UNIQUE (ComputedConstraint)) HTH |
DavidM
2004-05-22 |
re: Unique values, many NULLs - A Dodgy Constraint. I tried that first Rob and couldn't get it to work, so I switched to the IDENTITY property.. The NEWID function is non-deterministic and so the UNIQUE constraint "should" fail. I can't get that to work on my box... Can you show me the SET statments that you are using? |
SamS
2004-05-25 |
re: Unique values, many NULLs - A Dodgy Constraint. Hi, I have been thinking about this problem on and off for years now. Its the first time I've seen it solved using a computed column. The other solution I've seen is creating a single column view that only includes the not null values in DC. Then apply a unique index to the DC column of the view. As for whether its a dogdy constraint, I'm not really sure. In the example I've got currently, I have a Company table with columns: Id INT NOT NULL PRIMARY KEY ,Name VARCHAR(10) NOT NULL ,ExternalNumber INT NULL etc... Basically we create the company, name it and record some other information for it. Then we apply to a external body for a number for the company which they supply some time later. When they do supply a number it must be unique across all companies. I realise I could have a CompanyNumber table with a FK to the company table and a NOT NULL ExternalNumber field but the design seems a little clunky to me. Any thoughts? |
Brett
2004-05-26 |
re: Unique values, many NULLs - A Dodgy Constraint. Yeah, I'm always amazed that DB2 has something SQL Server doesn't have.... But doesn't anyone else have a problem with messing around with setting? Is it only at CREATE TABLE time? |
DavidM
2004-05-26 |
re: Unique values, many NULLs - A Dodgy Constraint. Brett, The only setting that you have to "mess" with is ARITHABORT.. The others are the SQL92 standard and are defaults for SQL Server Both at DDL and DML time is required. As usual BOL has the details.. |
robvolk
2004-05-27 |
re: Unique values, many NULLs - A Dodgy Constraint. Sorry David, I goofed big time. I didn't realize the non-deterministic functions aren't allowed in this situation (which really sucks) |
rnickel
2005-08-24 |
re: Unique values, many NULLs - A Dodgy Constraint. <blockquote>When I see the question posed I assume it is needed because of a underlying design problem</blockquote> All right, Mr. Smarty David-- at my company we keep a list of customers. Most are from the US and have social security numbers. Some are foreign and have no social security numbers. If the person does have a social, we want to make sure it's not entered more than once. (For example, when someone tries to enter a customer again, not realizing they're already in the system.) For this, I would like to use the unique constraint that allows multiple nulls. What's my underlying design problem? |
alexr
2005-11-08 |
re: Unique values, many NULLs - A Dodgy Constraint. re: SSN, null values and unique constraint Your design problem is that you should move the SSN column into a separate table with FK to your customers table to eliminate these null values. Nulls are the anathema of relational databases! |
brent
2005-12-08 |
re: Unique values, many NULLs - A Dodgy Constraint. What does moving the SSN numbers to a separate table really solve? You still have NULL's in the foreign key in your original table and you still have the problem of enforcing uniqueness of only non-nulls in the referencing column. Then you are also adding a left outer join to all of your retreival code as well. |
James
2006-06-21 |
re: Unique values, many NULLs - A Dodgy Constraint. 'Nulls are the anathema of relational databases!' True, and theoretically everything is as it should be. You do need an extra table to handle this situation properly. However this is a common situation and there really ought to be a workaround. Who really wants to add an extra table with one UNIQUE NOT NULL column just to solve this situation?? A pain in the neck! |
James
2006-06-21 |
re: Unique values, many NULLs - A Dodgy Constraint. Sorry! I'd like to correct myself. This problem is a result of a rubbish implementation by Microsoft and does not agree with SQL standards. Microsoft will point out that they implemented unique constraints before nulls were allowed, but they should have forseen this situation. But the several workarounds I've seen include: separate table for the unique column, triggers, schemebinding view which ignores nulls and has a unique not null constraint on it. You don't use the view, but in effect it acts as a multi-null unique constraint. |
Giannis Tsakiris
2007-08-24 |
re: Unique values, many NULLs - A Dodgy Constraint. Only microsoft would implement unique key constraints in such a peculiar fashion. null is not a value, null is the absence of value, only microsoft engineers could be so "smart" to consider that the absence of value can duplicate. (Obviously, they must implemented NULLs some sort of "special value", instead of no-value at all, and thus NULL fall to the constraint of the rest real value). Your workaround may be working and it's nice that you shared it, but I personally find it quite complicated... Thanks. |
Wes Clark
2008-06-13 |
re: Unique values, many NULLs - A Dodgy Constraint. In SQL Server 2008, filtered indexes are being added that can eliminate the nulls, but it is not a perfect solution when there can be more than one column null. Oracle simple ignores them, and seems to work the best. |