I have stock_price_alert
table with 3 columns. stock_price_id
is PRIMARY KEY
& also FOREIGN KEY
to other table. Table definition as below:
create table stock_price_alert (
stock_price_id integer references stock_price (id) on delete cascade not null,
fall_below_alert boolean not null,
rise_above_alert boolean not null,
primary key (stock_price_id)
);
I need to either:
1) INSERT
record if not exist
-- query 1
INSERT INTO stock_price_alert (stock_price_id, fall_below_alert, rise_above_alert)
VALUES (1, true, false);
2) UPDATE
record if exist
-- query 2
UPDATE stock_price_alert SET
fall_below_alert = true,
rise_above_alert = false
WHERE stock_price_id = 1;
First I need to issue SELECT
query on stock_price_alert
table, in order to decide whether to perform query (1) or (2).
Postgres supports INSERT INTO TABLE .... ON CONFLICT DO UPDATE ...
:
-- query 3
INSERT INTO stock_price_alert (stock_price_id, fall_below_alert, rise_above_alert)
VALUES (1, true, false)
ON CONFLICT (stock_price_id) DO UPDATE SET
fall_below_alert = EXCLUDED.fall_below_alert,
rise_above_alert = EXCLUDED.rise_above_alert;
Instead of using query (1) or (2), can I always use query (3)? Then I don't need to issue SELECT
query in prior & it helps to simplify the code.
But I am wondering, which is the best practice? Will query (3) cause performance issue or unwanted side effect? Thanks.
EXCLUDED is the name the DBMS gives to a special table where we have all the rows proposed for INSERTION present. These rows may be inserted to this table as soon as the INSERT operation runs. This is mostly preceded by the ON CONFLICT DO UPDATE clause, specifically targeting this table.
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.
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).
There is a nice way of doing conditional INSERT in PostgreSQL: INSERT INTO example_table (id, name) SELECT 1, 'John' WHERE NOT EXISTS ( SELECT id FROM example_table WHERE id = 1 );
Query 3 is the Postgres syntax for "UPSERT" (= UPDATE or INSERT), introduced in Postgres 9.5.
From the documentation:
ON CONFLICT DO UPDATE
guarantees an atomicINSERT
orUPDATE
outcome; provided there is no independent error, one of those two outcomes is guaranteed, even under high concurrency. This is also known asUPSERT
– “UPDATE
orINSERT
”.
This is the best practice for what you are trying to achieve.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With