2

I have an empty table with one bigserial id column and one unique text column, and do this:

INSERT INTO tab (col) VALUES ($1) ON CONFLICT DO NOTHING; -- $1 = test
INSERT INTO tab (col) VALUES ($1) ON CONFLICT DO NOTHING; -- $1 = test
INSERT INTO tab (col) VALUES ($1) ON CONFLICT DO NOTHING; -- $1 = test2

The table now has two rows:

1, test
3, test2

I expect and want:

1, test
2, test2

Why is the bigserial id column being increased even when "NOTHING" is happening for the second row due to the uniqueness of the text column?

More like "ON CONFLICT DO SOMETHING".

I doubt that this is related to the real error I'm having and which has been eluding me for months, but I need to straighten this out first as it seems like it could be related.

I could not find any mention in the manual on how to make it not increase the id when it doesn't INSERT any row.

1
  • 1
    What exactly is your problem? The value for a generated primary key has exactly one job: to be unique. It's completely irrelevant whether that value is -56, 3, 42, 4637 or 4387648326438
    – user1822
    Aug 26, 2020 at 15:55

2 Answers 2

3

This is Working As Designed™.

Firstly, serial data types are not "real" types, they are just syntactic sugar for integer columns populated from sequences.

Then about sequences the manual says so:

To avoid blocking concurrent transactions that obtain numbers from the same sequence, a nextval operation is never rolled back; that is, once a value has been fetched it is considered used and will not be returned again. This is true even if the surrounding transaction later aborts, or if the calling query ends up not using the value. For example an INSERT with an ON CONFLICT clause will compute the to-be-inserted tuple, including doing any required nextval calls, before detecting any conflict that would cause it to follow the ON CONFLICT rule instead. Such cases will leave unused “holes” in the sequence of assigned values.

Subsequently (no pun intended), you cannot "stop PG from wasting ids" (even if you stop using Postgres altogether, because all other DBMSes behave in the same manner).

0

The table now has two rows: ( 1, 'test' ), ( 3, 'test2' ) ... I expect and want ( 1, 'test' ), ( 2, 'test2' )

Your expectation is incorrect.

Your desire requires explanation.

Sequence-generated values are guaranteed to be unique, not sequential.

Further, you should not care what their actual, numerical value is, merely that each is different from every other.

If you want to have any innate "order" to your rows, you need to supply that for yourself.

Also, de-duplicating your values before performing the inserts might help. You could do this in the source, or using a temporary table without constraints on uniqueness.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.