A razão pela qual isso parece estranho para você é que você está pensando no incremento no contador como parte da operação de inserção e, portanto, "DO NOTHING" deve significar "não incremente nada". Você está imaginando isso:
- Verifique os valores a serem inseridos em relação à restrição
- Se a duplicata for detectada, cancele
- Sequência de incremento
- Inserir dados
Mas, na verdade, o incremento tem que acontecer antes que a inserção seja tentada . Um
SERIAL
coluna no Postgres é implementada como um DEFAULT
que executa o nextval()
função em uma SEQUENCE
vinculada . Antes que o DBMS possa fazer qualquer coisa com os dados, ele precisa ter um conjunto completo de colunas, então a ordem das operações é assim:- Resolva os valores padrão, incluindo o incremento da sequência
- Verifique os valores a serem inseridos em relação à restrição
- Se a duplicata for detectada, cancele
- Inserir dados
Isso pode ser visto intuitivamente se a chave duplicada estiver no próprio campo de incremento automático:
CREATE TABLE foo ( id SERIAL NOT NULL PRIMARY KEY, bar text );
-- Insert row 1
INSERT INTO foo ( bar ) VALUES ( 'test' );
-- Reset the sequence
SELECT setval(pg_get_serial_sequence('foo', 'id'), 0, true);
-- Attempt to insert row 1 again
INSERT INTO foo ( bar ) VALUES ( 'test 2' )
ON CONFLICT (id) DO NOTHING;
Claramente, isso não pode saber se há um conflito sem incrementar a sequência, então o "não fazer nada" tem que vir depois esse incremento.