Insert, on duplicate update in PostgreSQL?

前端 未结 16 2276
别那么骄傲
别那么骄傲 2020-11-21 04:52

Several months ago I learned from an answer on Stack Overflow how to perform multiple updates at once in MySQL using the following syntax:

INSERT INTO table          


        
16条回答
  •  粉色の甜心
    2020-11-21 05:34

    Warning: this is not safe if executed from multiple sessions at the same time (see caveats below).


    Another clever way to do an "UPSERT" in postgresql is to do two sequential UPDATE/INSERT statements that are each designed to succeed or have no effect.

    UPDATE table SET field='C', field2='Z' WHERE id=3;
    INSERT INTO table (id, field, field2)
           SELECT 3, 'C', 'Z'
           WHERE NOT EXISTS (SELECT 1 FROM table WHERE id=3);
    

    The UPDATE will succeed if a row with "id=3" already exists, otherwise it has no effect.

    The INSERT will succeed only if row with "id=3" does not already exist.

    You can combine these two into a single string and run them both with a single SQL statement execute from your application. Running them together in a single transaction is highly recommended.

    This works very well when run in isolation or on a locked table, but is subject to race conditions that mean it might still fail with duplicate key error if a row is inserted concurrently, or might terminate with no row inserted when a row is deleted concurrently. A SERIALIZABLE transaction on PostgreSQL 9.1 or higher will handle it reliably at the cost of a very high serialization failure rate, meaning you'll have to retry a lot. See why is upsert so complicated, which discusses this case in more detail.

    This approach is also subject to lost updates in read committed isolation unless the application checks the affected row counts and verifies that either the insert or the update affected a row.

提交回复
热议问题