POSTGRES - evita incremento serial com ON CONFLICT DO NOTHING [duplicar]
duplicata desta questão
Digamos que eu tenha as seguintes coisas da tabela. Quero nomes exclusivos na tabela para que não haja duplicatas. O processo que insere algo não deve precisar verificar se algo com esse nome já existe.
CREATE TABLE things(
id SMALLSERIAL PRIMARY KEY,
name varchar UNIQUE
);
Quando eu insiro valores como este, funciona. Se 'mesa' já estiver nas coisas, não será inserido.
INSERT INTO things (name)
VALUES ('desk')
ON CONFLICT DO NOTHING;
Tho único problema é ON CONFLICT DO NOTHING não faz realmente nada. Ele ainda incrementa a sequência para o campo id.
Se isso acontecer com muita freqüência, a sequência de id eventualmente ficará muito grande para o tipo de campo.
Tem algum jeito de prevenir que isso aconteça?
Respostas
Usando insert ... on conflict, você não pode evitar o serialincremento automático em conflitos. Postgres (assim como outros bancos de dados) não garante que as séries sejam sequenciais, conforme explicado na documentação :
Porque
smallserial,serialebigserialsão implementados usando sequências, pode haver "buracos" ou lacunas na sequência de valores que aparecem na coluna, mesmo que nenhuma linha seja excluída. Um valor alocado da sequência ainda é "usado", mesmo se uma linha que contém esse valor nunca for inserida com êxito na coluna da tabela. Isso pode acontecer, por exemplo, se a transação de inserção for revertida.
Se você estiver executando muitos desses insertacabamentos em conflito, uma maneira de limitar o bleading seria alterar a sintaxe para not exists:
insert into things (name)
select name
from (values ('desk')) v(name)
where not exists (select 1 from things t1 where t1.name = v.name)
Observe que isso ainda não garante que as publicações em série serão sequenciais (consulte a citação acima da documentação).