Обсуждение: Catching unique_violation exception on specific column/index

Поиск
Список
Период
Сортировка

Catching unique_violation exception on specific column/index

От
Alexey Dokuchaev
Дата:
Hi there,

I have a table with several UNIQUE and CHECK constraints.  One of these
UNIQUE constraints actually *can* be violated -- not on the table level,
of course, but on the application level -- meaning, if the entry with
particular foo_key is already in there, do not throw an exception, just
silently do nothing.

The usual approach ("EXCEPTION WHEN unique_violation THEN ... END") does
not really cut it because I want to catch unique_violation only when it
happens on "foo_key", and still rightfully complain on others.  However,
there is no "EXCEPTION WHEN unique_violation ON (foo_key)" or something.
Is there a way to do this without using triggers and in a less ugly way
than the code below?

    IF SQLERRM = 'duplicate key value violates unique constraint' ||
          ' "foo_key"' THEN
        RAISE NOTICE '%: %', SQLSTATE, SQLERRM;
    ELSE
        RAISE EXCEPTION '%: %', SQLSTATE, SQLERRM;
    END IF;

./danfe


Re: Catching unique_violation exception on specific column/index

От
Thomas Kellerer
Дата:
Alexey Dokuchaev schrieb am 11.06.2018 um 12:10:
> I have a table with several UNIQUE and CHECK constraints.  One of these
> UNIQUE constraints actually *can* be violated -- not on the table level,
> of course, but on the application level -- meaning, if the entry with
> particular foo_key is already in there, do not throw an exception, just
> silently do nothing.
> 
> The usual approach ("EXCEPTION WHEN unique_violation THEN ... END") does
> not really cut it because I want to catch unique_violation only when it
> happens on "foo_key", and still rightfully complain on others.  However,
> there is no "EXCEPTION WHEN unique_violation ON (foo_key)" or something.
> Is there a way to do this without using triggers and in a less ugly way
> than the code below?
> 
>     IF SQLERRM = 'duplicate key value violates unique constraint' ||
>           ' "foo_key"' THEN
>         RAISE NOTICE '%: %', SQLSTATE, SQLERRM;
>     ELSE
>         RAISE EXCEPTION '%: %', SQLSTATE, SQLERRM;
>     END IF;
> 
> ./danfe
 
What's wrong  with: 

  INSERT ...
  ON CONFLICT (foo_key) DO NOTHING


 



Re: Catching unique_violation exception on specific column/index

От
Alexey Dokuchaev
Дата:
On Mon, Jun 11, 2018 at 05:10:33PM +0700, Alexey Dokuchaev wrote:
> The usual approach ("EXCEPTION WHEN unique_violation THEN ... END") does
> not really cut it because I want to catch unique_violation only when it
> happens on "foo_key", and still rightfully complain on others.  However,
> there is no "EXCEPTION WHEN unique_violation ON (foo_key)" or something.
> Is there a way to do this without using triggers and in a less ugly way
> than the code below?

Oh, I completely forgot about rules:

    CREATE OR REPLACE RULE ignore_duplicate_foo AS
      ON INSERT TO table_bar WHERE EXISTS (
        SELECT 1 FROM table_bar WHERE foo = NEW.foo)
      DO INSTEAD NOTHING;

Sorry for the noise.

./danfe


Re: Catching unique_violation exception on specific column/index

От
Andreas Kretschmer
Дата:

Am 11.06.2018 um 12:58 schrieb Alexey Dokuchaev:
>> What's wrong with:
>>
>>    INSERT ...
>>    ON CONFLICT (foo_key) DO NOTHING
> Nothing I guess, except that it is available since 9.5 (right?), and I try
> to stay compatible with 9.3.  Sorry for not saying this in the first place.
>
> ./danfe
>

... 9.3 will be out of support soon


Regards, Andreas

-- 
2ndQuadrant - The PostgreSQL Support Company.
www.2ndQuadrant.com



Re: Catching unique_violation exception on specific column/index

От
Alexey Dokuchaev
Дата:
On Mon, Jun 11, 2018 at 12:30:13PM +0200, Thomas Kellerer wrote:
> Alexey Dokuchaev schrieb am 11.06.2018 um 12:10:
> > I have a table with several UNIQUE and CHECK constraints.  One of these
> > UNIQUE constraints actually *can* be violated -- not on the table level,
> > of course, but on the application level -- meaning, if the entry with
> > particular foo_key is already in there, do not throw an exception, just
> > silently do nothing.
>  
> What's wrong with:
> 
>   INSERT ...
>   ON CONFLICT (foo_key) DO NOTHING

Nothing I guess, except that it is available since 9.5 (right?), and I try
to stay compatible with 9.3.  Sorry for not saying this in the first place.

./danfe


Re: Catching unique_violation exception on specific column/index

От
Thomas Kellerer
Дата:
Alexey Dokuchaev schrieb am 11.06.2018 um 12:58:
>>> I have a table with several UNIQUE and CHECK constraints.  One of these
>>> UNIQUE constraints actually *can* be violated -- not on the table level,
>>> of course, but on the application level -- meaning, if the entry with
>>> particular foo_key is already in there, do not throw an exception, just
>>> silently do nothing.
>>  
>> What's wrong with:
>>
>>   INSERT ...
>>   ON CONFLICT (foo_key) DO NOTHING
> 
> Nothing I guess, except that it is available since 9.5 (right?), and I try
> to stay compatible with 9.3.  Sorry for not saying this in the first place.

Andreas already mentioned that 9.3 will be EOL soon (3 months from now), but 
the performance and efficiency for concurrent execution of ON CONFLICT is 
much better than anything you can implement yourself. 

If that functionality is an important part of your code, you should consider 
upgrading to 10 (or 9.6 if your are really conservative) rather sooner
than later. 




Re: Catching unique_violation exception on specific column/index

От
Alexey Dokuchaev
Дата:
On Mon, Jun 11, 2018 at 01:26:16PM +0200, Thomas Kellerer wrote:
> If that functionality is an important part of your code, you should
> consider upgrading to 10 (or 9.6 if your are really conservative)
> rather sooner than later.

Oh well, fair enough.  As much as I'd love to stick to the lowest
supported (and sometimes even unsupported) versions, ON CONFLICT is
indeed very handy, esp. since I have a few UPSERT's implemented the
old way already (via catching the "unique_violation" exception).

Shall I update to 9.6/10, I have a bit off-topic (to the original
subject) question: right now, when I need to get the length of an
array (never multidimensional), I do this:

    coalesce(array_length(foo, 1), 0);

In 9.4+, I can call cardinality().  I'm a bit hesitant: is doing so
semantically correct, or should I still do coalesce(..., 0) in this
case?  This is not about the outcome, it's whether cardinality() is
semantically correct to obtain the number of the array items, or it
was introduced for other means?

./danfe


Re: Catching unique_violation exception on specific column/index

От
Adrian Klaver
Дата:
On 06/11/2018 11:21 AM, Alexey Dokuchaev wrote:
> On Mon, Jun 11, 2018 at 01:26:16PM +0200, Thomas Kellerer wrote:
>> If that functionality is an important part of your code, you should
>> consider upgrading to 10 (or 9.6 if your are really conservative)
>> rather sooner than later.
> 
> Oh well, fair enough.  As much as I'd love to stick to the lowest
> supported (and sometimes even unsupported) versions, ON CONFLICT is
> indeed very handy, esp. since I have a few UPSERT's implemented the
> old way already (via catching the "unique_violation" exception).
> 
> Shall I update to 9.6/10, I have a bit off-topic (to the original
> subject) question: right now, when I need to get the length of an
> array (never multidimensional), I do this:
> 
>      coalesce(array_length(foo, 1), 0);
> 
> In 9.4+, I can call cardinality().  I'm a bit hesitant: is doing so
> semantically correct, or should I still do coalesce(..., 0) in this
> case?  This is not about the outcome, it's whether cardinality() is
> semantically correct to obtain the number of the array items, or it
> was introduced for other means?

https://www.postgresql.org/docs/10/static/arrays.html

8.15.3. Accessing Arrays

"... cardinality returns the total number of elements in an array across 
all dimensions. It is effectively the number of rows a call to unnest 
would yield: ..."


> 
> ./danfe
> 


-- 
Adrian Klaver
adrian.klaver@aklaver.com