问题
duplicate of this question
Say I have the following table things. I want unique names in the table so there are no duplicates. The process that inserts a thing shouldn't need to check if a thing with this name is already there.
CREATE TABLE things(
id SMALLSERIAL PRIMARY KEY,
name varchar UNIQUE
);
When I insert values like this it works. If 'desk' is already in things it won't be inserted.
INSERT INTO things (name)
VALUES ('desk')
ON CONFLICT DO NOTHING;
Tho only problem is ON CONFLICT DO NOTHING does not really do nothing. It still increments the sequence for the id field.
If this happens too often the id sequence eventually gets too big for the field type.
Is there a way to prevent this from happening?
回答1:
Using insert ... on conflict
, you can't prevent the serial
to auto-increment on conflicts. Postgres (just like other databases) does not guarantees that serials are sequential, as explained in the documentation:
Because
smallserial
,serial
andbigserial
are implemented using sequences, there may be "holes" or gaps in the sequence of values which appears in the column, even if no rows are ever deleted. A value allocated from the sequence is still "used up" even if a row containing that value is never successfully inserted into the table column. This may happen, for example, if the inserting transaction rolls back.
If you are running a lots of insert
that end up in conflict, one way to limit the bleading would be to change the syntax to 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)
Note that this still does not guarantee that serials will be sequential (refer to the above quote from the documentation).
来源:https://stackoverflow.com/questions/63720340/postgres-prevent-serial-incrementation-with-on-conflict-do-nothing