2

I would really like to write a query like this:

INSERT INTO test_table (id, dt, amt)
VALUES(4, current_timestamp, 15)
ON CONFLICT (id)
DO UPDATE
    SET dt = VALUES(dt)
        amt = VALUES(amt)

The problem is, the version of Postgres I'm using (9.4.7) doesn't support the ON CONFLICT construct. Any ideas of how to achieve this without upgrading Postgres?

user3685285
  • 6,066
  • 13
  • 54
  • 95

2 Answers2

2

PostgreSQL 9.4 doesn't have any built-in UPSERT (or MERGE) facility, and doing it efficiently in the face of concurrent use is very difficult.

This article discusses the problem in useful detail.

In general you must choose between two options:

  • Individual insert/update operations in a retry loop; or
  • Locking the table and doing batch merge

For complete solution read this SO Answer

Durgpal Singh
  • 11,481
  • 4
  • 37
  • 49
-1

If you do it frequently. You can write a function to do it for you. You can do by two ways.

  1. Check first then insert or update.

    CREATE OR REPLACE FUNCTION insert_test_table(int, timestamp, varchar)
    RETURNS int AS
    $BODY$
    BEGIN
        IF (EXISTS(SELECT id FROM test_table WHERE id = $1)) THEN
            UPDATE test_table SET dt = $2, amt = $3 WHERE id = $1;
            RETURN 2;
        ELSE
            INSERT INTO test_table (id, dt, amt) VALUES($1, $2, $3);
            RETURN 1;
        END IF;
        RETURN 0;
        END;
    $BODY$
    LANGUAGE plpgsql;
  1. Use Exception:

    CREATE OR REPLACE FUNCTION insert_test_table(int, timestamp, varchar)
    RETURNS int AS
    $BODY$
    BEGIN
        INSERT INTO test_table (id, dt, amt) VALUES($1, $2, $3);
        RETURN 1;
        EXCEPTION WHEN unique_violation THEN 
                BEGIN
                    UPDATE test_table SET dt = $2, amt = $3 WHERE id = $1;  
                    RETURN 2
                END;
    END;
    $BODY$
    LANGUAGE plpgsql;

The second way maybe conflict with other unique constraint, so be careful.

Mabu Kloesen
  • 1,248
  • 7
  • 8
  • Both solutions are not totally correct, because they are subject to race conditions. Consult the PostgreSQL wiki for a solution. – Laurenz Albe Jan 20 '18 at 03:59
  • Sorry, I don't understand clearly. Could you please help me explain more if you don't mind? – Mabu Kloesen Jan 20 '18 at 04:41
  • I mean the example in [the documentation](https://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#PLPGSQL-ERROR-TRAPPING). The table could change between the first and the second SQL statement. – Laurenz Albe Jan 20 '18 at 05:18