5

I have a table with a 12-column UNIQUE index. \d sales shows sales_uq UNIQUE, btree (a1, a2, a3, ... a12).

I do the following query:

SELECT a1, a2, a3, ... a12 FROM sales GROUP BY a1, a2, a3, ... a12 HAVING count(1) > 1;

and I get a bunch of results. How is that possible?! Is it possible that the index is there but somehow disabled? Or can there be some issue with NULLs? Or with floating point numbers (two of the columns in the index are of type double precision)?

2 Answers 2

12

because two NULLs don't compare as equal, they play funny games with UNIQUE constraints.

See last paragraph of UNIQUE constraints in the PostgreSQL documentation:

In general, a unique constraint is violated when there are two or more rows in the table where the values of all of the columns included in the constraint are equal. However, two null values are not considered equal in this comparison. That means even in the presence of a unique constraint it is possible to store duplicate rows that contain a null value in at least one of the constrained columns.

Sign up to request clarification or add additional context in comments.

2 Comments

Damn, this sucks. I knew NULL is not equal to NULL, but for some reason I was expecting it to be different in the index. :)
@ionut bizau - of course, the real fun is that, for GROUPing purposes, NULLs are grouped together. And as the documentation states, some other servers (e.g. SQL Server) do implement UNIQUE constraints only allowing a single NULL (although this violates the ANSI SQL spec)
2

A double is inexact, that's why this might happen. Use an exact datatype and you won't have problems like this.

2 Comments

Although this doesn't solve my problem, it's a really good point. I will consider changing the database to use NUMERIC. Thanks.
Wouldn't for example 45.454545454 always result in the same inexact value therefor it would result in the same inexact number causing two rows columns to be the same? Or are you saying 45.454545454 will result in 45.455 and sometimes 45.454? Of course the numbers I'm using is just for discussion purposes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.