Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do INSERT INTO SELECT and ON DUPLICATE UPDATE in PostgreSQL 9.5?

I'm trying to to do the following in PostgreSQL

INSERT INTO blog_sums ( blog_id, date, total_comments)
    SELECT blog_id, '2016-09-22', count(comment_id) as total_comments_update
    FROM blog_comments
    WHERE date = '2016-09-22'
    GROUP BY blog_id         
ON CONFLICT (blog_id ,date)
DO UPDATE SET blog_sums.total_comments = total_comments_update;

I have unique key on date + blog_id and I keep getting Error:

ERROR: column "total_comments_update" does not exist

I'm looking for the "right" way and the most efficient way to do update on duplicate/conflict in this case

my tables are

blog_comments (blog_id, comment_id, comment, date)
blog_sums ( blog_id, date, total_comments) . unique on blog_id+date

Thanks

like image 277
Yuval Kaufman Avatar asked Sep 23 '16 14:09

Yuval Kaufman


People also ask

Does update insert in Postgres?

Introduction to the PostgreSQL upsert The idea is that when you insert a new row into the table, PostgreSQL will update the row if it already exists, otherwise, it will insert the new row. That is why we call the action is upsert (the combination of update or insert).

What is needed for an insert on conflict update to work?

You must have INSERT privilege on a table in order to insert into it. If ON CONFLICT DO UPDATE is present, UPDATE privilege on the table is also required. If a column list is specified, you only need INSERT privilege on the listed columns.

How do I use upsert?

The UPSERT is an atomic operation that means it is an operation that completes in a single-step. For example, if a record is new, it will trigger an INSERT command. But, if it already exists in the table, then this operation will perform an UPDATE statement.


1 Answers

You cannot access the column aliases from the select in the DO UPDATE SET clause. You can use the excluded table alias which includes all rows that failed to insert because of conflicts:

INSERT INTO blog_sums ( blog_id, date, total_comments)
    SELECT blog_id, '2016-09-22', count(comment_id) as total_comments_update
    FROM blog_comments
    WHERE date = '2016-09-22'
    GROUP BY blog_id         
ON CONFLICT (blog_id ,date)
DO UPDATE SET total_comments = excluded.total_comments;

So excluded.total_comments in the last line refers to the value of total_comments that we tried to insert but we couldn't, because of the conflict.

like image 68
redneb Avatar answered Sep 22 '22 13:09

redneb