Received: from maia.hub.org (unknown [200.46.204.183]) by mail.postgresql.org (Postfix) with ESMTP id 7804F632BD4 for ; Mon, 29 Jun 2009 08:32:39 -0300 (ADT) Received: from mail.postgresql.org ([200.46.204.86]) by maia.hub.org (mx1.hub.org [200.46.204.183]) (amavisd-maia, port 10024) with ESMTP id 49290-10 for ; Mon, 29 Jun 2009 08:32:38 -0300 (ADT) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from mail.postnewspapers.com.au (202-89-185-120.static.dsl.amnet.net.au [202.89.185.120]) by mail.postgresql.org (Postfix) with ESMTP id AA2896324F5 for ; Mon, 29 Jun 2009 08:32:37 -0300 (ADT) Received: from localhost (access [127.0.0.1]) by mail.postnewspapers.com.au (Postfix) with ESMTP id 7EC6E1E045A; Mon, 29 Jun 2009 19:32:34 +0800 (WST) X-Virus-Scanned: Debian amavisd-new at postnewspapers.com.au Received: from mail.postnewspapers.com.au ([127.0.0.1]) by localhost (access.postnewspapers.com.au [127.0.0.1]) (amavisd-new, port 10024) with LMTP id lS3dbF8EPm90; Mon, 29 Jun 2009 19:32:32 +0800 (WST) Received: from [10.1.1.2] (124-169-163-230.dyn.iinet.net.au [124.169.163.230]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "Craig Ringer", Issuer "POST Certificate Authority" (verified OK)) by mail.postnewspapers.com.au (Postfix) with ESMTPSA id A4D221E0456; Mon, 29 Jun 2009 19:32:32 +0800 (WST) Subject: Re: uniqueness constraint with NULLs From: Craig Ringer To: Robert Edwards Cc: pgsql-sql@postgresql.org In-Reply-To: <4A485431.3080707@cs.anu.edu.au> References: <4A485431.3080707@cs.anu.edu.au> Content-Type: text/plain Date: Mon, 29 Jun 2009 19:32:30 +0800 Message-Id: <1246275150.11346.27.camel@ayaki> Mime-Version: 1.0 X-Mailer: Evolution 2.26.1 Content-Transfer-Encoding: 7bit X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=0 tagged_above=0 required=5 tests=none X-Spam-Level: X-Archive-Number: 200906/120 X-Sequence-Number: 32725 On Mon, 2009-06-29 at 15:42 +1000, Robert Edwards wrote: > Can anyone suggest a way that I can impose uniqueness on a and b when > c is NULL? One way is to add an additional partial index on (a,b): CREATE INDEX bobtest_ab_unique ON bobtest(a,b) WHERE (c IS NULL); ... however, if you want to do the same sort of thing for all permutations (a, null, null), (b, null, null), (c, null, null), (a, b, null), (a, c, null), (b, c, null), (a, b, c)that'll be a LOT of indexes. In that case you might be better off just using a trigger function like (untested but should be about right): CREATE OR REPLACE FUNCTION bobtest_unique_trigger() RETURNS trigger AS $$ declare conflicting_id integer; begin if TG_OP = 'INSERT' or TG_OP = 'UPDATE' then select into conflicting_id from bobtest where (NOT new.a IS DISTINCT FROM a) and (NOT new.b IS DISTINCT FROM b) and (NOT new.c IS DISTINCT FROM c); if found then raise exception 'Unique violation in bobest: inserted row conflicts with row id=%',conflicting_id; end if; end if; end; $$ LANGUAGE 'plpgsql'; ... which enforces uniqueness considering nulls. > In the real app., c is a date field and I require it to be NULL for > some rows. Oh. Er, In that case, the partial unique index is your best bet (but 'a' and 'b' should ne NOT NULL, right). > in case I am missing some other solution that > doesn't involve the use of triggers etc. Sometimes a trigger is the right solution. -- Craig Ringer