Anledningen till att detta känns konstigt för dig är att du tänker på inkrementet på disken som en del av insättningsoperationen, och därför borde "GÖR INGENTING" betyda "öka inte upp någonting". Du föreställer dig detta:
- Kontrollera värden som ska infogas mot begränsningar
- Om dubblett upptäcks, avbryt
- Öka sekvens
- Infoga data
Men i själva verket måste ökningen ske innan infogningen görs . En SERIAL
kolumn i Postgres är implementerad som en DEFAULT
som kör nextval()
funktion på en bunden SEQUENCE
. Innan DBMS kan göra något med datan måste den ha en komplett uppsättning kolumner, så operationsordningen är så här:
- Lös standardvärden, inklusive ökning av sekvensen
- Kontrollera värden som ska infogas mot begränsningar
- Om dubblett upptäcks, avbryt
- Infoga data
Detta kan ses intuitivt om dupliceringsnyckeln finns i själva autoinkrementfältet:
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;
Uppenbarligen kan detta inte veta om det finns en konflikt utan att öka sekvensen, så "gör ingenting" måste komma efter den ökningen.