Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can the INSERT ... ON CONFLICT (id) DO UPDATE... syntax be used with a sequence ID?

In postgresql 9.5 how can the INSERT ... ON CONFLICT (id) DO UPDATE... syntax be used with a sequence ID?

In a table tbltest that has the following columns:

  • tbltest_ID
  • tbltest_Name
  • tbltest_Description

Where tbltest_ID has a sequence in the db that does auto increment.

The following works fine for updates, eg; updating the record with an ID of 4:

INSERT INTO tbltest (
    tbltest_ID,
    tbltest_Name,
    tbltest_Description) 
VALUES 
(4, 'test name','test description')
ON CONFLICT (tbltest_ID) DO UPDATE SET (
    tbltest_Name,
    tbltest_Description) = (
    excluded.tbltest_Name,
    excluded.tbltest_Description) RETURNING *;

But in order to get the DB to create the sequence ID for inserts I need to remove the ID column from the statement:

INSERT INTO tbltest (
    tbltest_Name,
    tbltest_Description) 
VALUES 
('test name','test description')
ON CONFLICT (tbltest_ID) DO UPDATE SET (
    tbltest_Name,
    tbltest_Description) = (
    excluded.tbltest_Name,
    excluded.tbltest_Description) RETURNING *;

This becomes a problem if I want to update multiple records some new and some existing. As if I remove the ID column, they all be come inserts, and if I leave it in there, I have to provide an ID value in the VALUES array for each row, and when I define an ID, the sequence (db's auto increment) is no longer used.

How is the INSERT ... ON CONFLICT (id) DO UPDATE... syntax spost to be used with a sequence ID to insert/update an set of records that will contain both new records and existing records?

For example, the following does not work:

INSERT INTO tbltest (
    tbltest_ID,
    tbltest_Name,
    tbltest_Description) 
VALUES 
(NULL, 'new record','new record description'),
(4, 'existing record name','existing record description')
ON CONFLICT (tbltest_ID) DO UPDATE SET (
    tbltest_Name,
    tbltest_Description) = (
    excluded.tbltest_Name,
    excluded.tbltest_Description) RETURNING *;

It throws an error:

ERROR: null value in column "tbltest_ID" violates not-null constraint

Thanks for your time.

like image 665
user2109254 Avatar asked Sep 24 '16 02:09

user2109254


1 Answers

Ok just worked it out. I read this great article from Neil Conway: http://www.neilconway.org/docs/sequences/

Where he shows the use of the DEFAULT keyword to tell the DB to use the sequence value for the column.

So here is the updated example that now works:

INSERT INTO tbltest (
    tbltest_ID,
    tbltest_Name,
    tbltest_Description) 
VALUES 
(DEFAULT, 'new record','new record description'),
(4, 'existing record name','existing record description')
ON CONFLICT (tbltest_ID) DO UPDATE SET (
    tbltest_Name,
    tbltest_Description) = (
    excluded.tbltest_Name,
    excluded.tbltest_Description) RETURNING *;

Hope this helps someone ;-)

like image 68
user2109254 Avatar answered Sep 20 '22 23:09

user2109254