8

So I'm coming from MySQL where I could do INSERT on DUPLICATE UPDATE:

INSERT INTO table (a,b,c) 
VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;

But now I'm using PostgreSQL and there are efforts to add the UPSERT functionality, looks like MERGE might work for what I would like but wanted to see if this is the most optimal syntax. Example Syntax 1, I've also seen this but don't understand how to implement. I haven't tried this yet because I thought MERGE was used for merging data from table1 to Table2 or would something like this work?

MERGE
INTO    table
USING   table
ON      c = 1
WHEN MATCHED THEN
UPDATE
SET     c=c+1
WHEN NOT MATCHED THEN
INSERT  (a,b,c)
VALUES  (1,2,3)

Any other suggestions?

Community
  • 1
  • 1
Phill Pafford
  • 83,471
  • 91
  • 263
  • 383

4 Answers4

14

Until MERGE is available, use this robust approach: Insert, on duplicate update in PostgreSQL?

Community
  • 1
  • 1
Michael Buen
  • 38,643
  • 9
  • 94
  • 118
3

Until merge is supported the simplest way IMO is to just break it up into two queries:

BEGIN;
  INSERT INTO t (a,b,c) VALUES (1,2,3) WHERE id != 1;
  UPDATE t SET c=c+1 WHERE id = 1;
END;

where id would be changed to the appropriate condition.

nate c
  • 8,802
  • 2
  • 27
  • 28
0
MERGE INTO table
    USING (VALUES (1, 2, 3)) AS newvalues (a, b, c)
    ON table.c = newvalues.c  -- or whatever the PK is
    WHEN MATCHED THEN UPDATE SET c = c + 1
    WHEN NOT MATCHED THEN INSERT (a, b, c)
                              VALUES (newvalues.a, newvalues.b, newvalues.c)

The key here is that instead of merging in another table you create a constant table source using the VALUES construct in the USING clause. The exact merging rules you can obviously tailor to taste.

See also http://petereisentraut.blogspot.com/2010/05/merge-syntax.html.

Peter Eisentraut
  • 35,221
  • 12
  • 85
  • 90
  • 1
    patch is 'waiting on author' - https://commitfest.postgresql.org/action/commitfest_view/inprogress – nate c Dec 29 '10 at 23:10
0

I think "MERGE" is not yet in Postgres but is suposed to be in 9.1.

I like to use RULEs instead

CREATE OR REPLACE RULE "insert_ignore"
AS ON INSERT TO "table" WHERE
  NEW.id = OLD.id --whatever your conditions are
DO INSTEAD NOTHING;

What you have linked to ("Insert, on duplicate update (postgresql)") is basically some pgsql that you feed the data. I think the RULE is more elegant since you don't need to call them explicitly and they work transparent in the background without the need to call a procedure within your actual INSERT.

DrColossos
  • 12,656
  • 3
  • 46
  • 67
  • So would this be a INSERT else IGNORE/SKIP? – Phill Pafford Dec 29 '10 at 19:49
  • It's an IGNORE/SKIP since you check for existence and if so, skip it. The same will work for UPDATE actions. Consider RULEs as "a kind of trigger" that are able to modify the query itself by rewriting it or (as in this case) ignoring parts (or all) of it. – DrColossos Dec 30 '10 at 07:27
  • 1
    I did this but the OLD.id gave an error, didn't like the value. Any thoughts? – Phill Pafford Dec 30 '10 at 19:30
  • This was actually just an example. You could write any query you want into the where. Look through the manual to see the examples. – DrColossos Dec 31 '10 at 09:46
  • 1
    @PhillPafford Apparently the metarow "OLD" doesn't exist on INSERT rules, but does for UPDATE rules. Still haven't figured it out yet though... – Trey Stout Oct 11 '11 at 01:45