La razón por la que esto le resulta extraño es que está pensando en el incremento en el contador como parte de la operación de inserción y, por lo tanto, "NO HACER NADA" debería significar "no incrementar nada". Te estás imaginando esto:
- Verifique los valores para insertar contra la restricción
- Si se detecta duplicado, cancelar
- Secuencia de incremento
- Insertar datos
Pero, de hecho, el incremento tiene que ocurrir antes de que se intente la inserción . Un SERIAL
la columna en Postgres se implementa como DEFAULT
que ejecuta nextval()
función en una SEQUENCE
enlazada . Antes de que DBMS pueda hacer algo con los datos, debe tener un conjunto completo de columnas, por lo que el orden de las operaciones es así:
- Resolver valores predeterminados, incluido el incremento de la secuencia
- Verifique los valores para insertar contra la restricción
- Si se detecta duplicado, cancelar
- Insertar datos
Esto se puede ver intuitivamente si la clave duplicada está en el propio campo de autoincremento:
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, esto no puede saber si hay un conflicto sin incrementar la secuencia, por lo que el "no hacer nada" tiene que venir después ese incremento.