Re: Way to create unique constraint in Postgres even with null columns

From: Mike Christensen <mike(at)kitchenpc(dot)com>
To: David Johnston <polobo(at)yahoo(dot)com>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: Way to create unique constraint in Postgres even with null columns
Date: 2011-11-27 22:43:42
Message-ID: CABs1bs06mJGO+qGV1fXc9wN-V8=7=JK4XV988b9=dT8buB4jbg@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

On Sun, Nov 27, 2011 at 2:18 PM, David Johnston <polobo(at)yahoo(dot)com> wrote:
> -----Original Message-----
> From: pgsql-general-owner(at)postgresql(dot)org
> [mailto:pgsql-general-owner(at)postgresql(dot)org] On Behalf Of Mike Christensen
> Sent: Sunday, November 27, 2011 5:02 PM
> To: Thomas Kellerer
> Cc: pgsql-general(at)postgresql(dot)org
> Subject: Re: [GENERAL] Way to create unique constraint in Postgres even with
> null columns
>
> On Sun, Nov 27, 2011 at 1:47 PM, Thomas Kellerer <spam_eater(at)gmx(dot)net> wrote:
>> Mike Christensen wrote on 27.11.2011 22:18:
>>>
>>> I have a table with this layout:
>>>
>>>     CREATE TABLE Favorites
>>>     (
>>>       FavoriteId uuid NOT NULL, --Primary key
>>>       UserId uuid NOT NULL,
>>>       RecipeId uuid NOT NULL,
>>>       MenuId uuid
>>>     )
>>>
>>> I want to create a unique constraint similar to this:
>>>
>>>     ALTER TABLE Favorites ADD CONSTRAINT Favorites_UniqueFavorite
>>> UNIQUE(UserId, MenuId, RecipeId);
>>>
>>> However, this will allow multiple rows with the same UserId and
>>> RecipeId, if the MenuId is null.  I want to allow a NULL MenuId to
>>> store a favorite that has no associated menu, but I only want at most
>>> one of these rows per user/recipe pair.
>>
>> In addition to the above unique constraint you will need another one:
>>
>> CREATE UNIQUE INDEX Favorites_UniqueFavorite
>>   ON (UserId, MenuId)
>>   WHERE RecipeId IS NULL;
>
> Excellent solution!  Thanks all..
>
> -------------------------------------------------------------
>
> While the conditional index will work this is one of many situations where
> being explicit is probably the better option.  It is quite likely that you
> will want to use the MenuID in queries and having to deal with NULL in those
> situations is messy.  You should create a "DEFAULT" menu for each user and
> replace any existing NULLs with the DEFAULT MenuID for the given user.
> Then, make the MenuID column "NOT NULL".
>
> Also, the index example above presumes you want RecipeId to be "Null-able"
> as opposed to MenuId as described in your original post.

Yea I assumed the idea was to do something like:

CREATE UNIQUE INDEX IDX_Favorites_NullMenu ON Favorites(UserId,
RecipeId) WHERE MenuId IS NULL;
CREATE UNIQUE INDEX IDX_Favorites_UniqueMenu ON Favorites(UserId,
RecipeId, MenuId) WHERE MenuId IS NOT NULL;

I'm not sure what situations become "messy" when MenuId allows NULLs
though. Maybe you can provide a few more details? I do agree
creating a default Menu for each user is the way to go. However, it
makes inserting a lot more difficult. If a user adds a recipe to
their favorites, and does not specify a menu, I then have to go lookup
the UUID for their default menu first. It's not a huge deal, but I'd
like to avoid that if possible. I think NULL makes sense here since
it really does mean "there is no menu for this row". Thanks!

Mike

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message Thomas Kellerer 2011-11-27 22:59:09 Re: Way to create unique constraint in Postgres even with null columns
Previous Message David Johnston 2011-11-27 22:18:22 Re: Way to create unique constraint in Postgres even with null columns