Capture which unique key was violated

0

I have a function that does insert in a table. This table has two columns that are unique 'email' and 'login'. In other tables there are also unique composite keys. Therefore, a UNIQUE_VIOLATION code: 23505 exception can happen if you try to insert repeated data into any of the columns that are constrained by unique keys.

Question:

  • How do I capture which of the unique keys were violated, when there is more than one in the same table, type to return the name of it, or do some procedure based on that?
asked by anonymous 09.11.2016 / 15:23

3 answers

2

As the version I am using is 9.5, the ideal solution is the GET STACKED DIAGNOSTICS command.

Example:

create table foo (a int not null, b int not null, unique(a), unique(b));
insert into foo (a,b) values(1,1);
insert into foo (a,b) values(2,2);
create function ffoo(x integer, y integer) returns void as $$
declare
    tabela text;
    restricao text;
begin
insert into foo (a,b) values(x,y);
exception when unique_violation then
    get stacked diagnostics tabela = TABLE_NAME,
                restricao = CONSTRAINT_NAME;
    raise notice 'tabela: % ; constraint: %', tabela, restricao;
end;
$$ language plpgsql;
select ffoo(2,3);
select ffoo(5,1);

Credits for Euler Taveira from the Brazilian PostgreSQL Community ([email protected])

    
09.11.2016 / 23:01
1

When an error occurs, next to the code representing the type of it, PostgreSQL also returns a text containing error message; in the case of unique constraints, the text of the error message itself contains which constraint has been violated.

    
09.11.2016 / 15:56
1
create table t (
    email text unique,
    login text unique
);

with d (email, login) as ( values
    ('[email protected]','fulano')
), e as (
    select
        exists (select 1 from t inner join d using(email)) as email,
        exists (select 1 from t inner join d using(login)) as login
), i as (
    insert into t (email, login)
    select email, login
    from d
    where not(select email or login from e)
    returning 'email inexistente' as email, 'login inexistente' as login
)
select
    case when email then 'violação de email único' else 'email inexistente' end as email,
    case when login then 'violação de login único' else 'login inexistente' end as login
from e
where email or login
union all
select email::text, login::text
from i

It may be easier to parse the error message if the driver used returns the message.

    
09.11.2016 / 19:36