18

I want to UPDATE or INSERT a column in PostgreSQL instead of doing INSERT or UPDATE using INSERT ... ON CONFLICT ... because there will be more updates than more inserts and also I have an auto incrementing id column that's defined using SERIAL so it increments the id column everytime it tries to INSERT or UPDATE and that's not what I want, I want the id column to increase only if it's an INSERT so that all ids would be in an order instead

The table is created like this

CREATE TABLE IF NOT EXISTS table_name (
    id SERIAL PRIMARY KEY,

    user_id varchar(30) NOT NULL,
    item_name varchar(50) NOT NULL,
    code_uses bigint NOT NULL,

    UNIQUE(user_id, item_name)
)

And the query I used was

INSERT INTO table_name
VALUES (DEFAULT, 'some_random_id', 'some_random_name', 1)
ON CONFLICT (user_id, item_name)
DO UPDATE SET code_uses = table_name.code_uses + 1;

Thanks :)

5
  • 2
    Auto-generated/Sequenced IDs in a table should not be expected to be sequential w/no gaps in all instances. But why don't you provide the statements you're already using? You've given us nothing to really help you other than a generic description. Ultimately you might need to utilize some PL/pgSQL (SQL Procedural Language) to achieve your goal. Commented Sep 19, 2020 at 14:45
  • 1
    I don't understand what exactly the problem with insert ... on conflict.. is Commented Sep 19, 2020 at 15:23
  • Added the query, you can look into that now and the problem with insert ... on conflict ... is that the ids are having a gap here and I thought like trying to insert many times is not a good idea when in the most cases it would just want to be updated Commented Sep 20, 2020 at 10:08
  • 2
    gaps in sequence generated values are nothing to worry about. The only job of a generated primary key value is to be unique. It does not matter if that value is 1,2, -34 or 48756485. Commented Sep 21, 2020 at 10:20
  • @user330315 maybe so, but some of us are a bit OCD and would like to avoid unnecessary gaps :) Commented May 21, 2024 at 9:25

1 Answer 1

22

Upserts in PostgreSQL do exactly what you described.

Consider this table and records

CREATE TABLE t (id SERIAL PRIMARY KEY, txt TEXT);
INSERT INTO t (txt) VALUES ('foo'),('bar');

SELECT * FROM t ORDER BY id;

 id | txt 
----+-----
  1 | foo
  2 | bar
(2 Zeilen)

Using upserts the id will only increment if a new record is inserted

INSERT INTO t VALUES (1,'foo updated'),(3,'new record')
ON CONFLICT (id) DO UPDATE SET txt = EXCLUDED.txt;

SELECT * FROM t ORDER BY id;

 id |     txt     
----+-------------
  1 | foo updated
  2 | bar
  3 | new record
(3 Zeilen)

EDIT (see coments): this is the expected behaviour of a serial column, since they're nothing but a fancy way to use sequences. Long story short: using upserts the gaps will be inevitable. If you're worried the value might become too big, use bigserial instead and let PostgreSQL do its job.

Related thread: serial in postgres is being increased even though I added on conflict do nothing

Sign up to request clarification or add additional context in comments.

3 Comments

I'm not sure whether it works here because of you inserting the id directly or not but in my case, I use DEFAULT to do it, it skipped a lot of ids and btw, I've added the query I used in the question, please look on that and let me know whether I'm doing something wrong
@AwesomeStickz I just added a comment to your message.
Alright, thanks for letting me know about it, I just worried that it may end up reaching max of bigserial too but it's just really really hard to do that so it's not a problem anymore

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.