Insert, on duplicate update in PostgreSQL?

前端 未结 16 2234
别那么骄傲
别那么骄傲 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:52

    Personally, I've set up a "rule" attached to the insert statement. Say you had a "dns" table that recorded dns hits per customer on a per-time basis:

    CREATE TABLE dns (
        "time" timestamp without time zone NOT NULL,
        customer_id integer NOT NULL,
        hits integer
    );
    

    You wanted to be able to re-insert rows with updated values, or create them if they didn't exist already. Keyed on the customer_id and the time. Something like this:

    CREATE RULE replace_dns AS 
        ON INSERT TO dns 
        WHERE (EXISTS (SELECT 1 FROM dns WHERE ((dns."time" = new."time") 
                AND (dns.customer_id = new.customer_id)))) 
        DO INSTEAD UPDATE dns 
            SET hits = new.hits 
            WHERE ((dns."time" = new."time") AND (dns.customer_id = new.customer_id));
    

    Update: This has the potential to fail if simultaneous inserts are happening, as it will generate unique_violation exceptions. However, the non-terminated transaction will continue and succeed, and you just need to repeat the terminated transaction.

    However, if there are tons of inserts happening all the time, you will want to put a table lock around the insert statements: SHARE ROW EXCLUSIVE locking will prevent any operations that could insert, delete or update rows in your target table. However, updates that do not update the unique key are safe, so if you no operation will do this, use advisory locks instead.

    Also, the COPY command does not use RULES, so if you're inserting with COPY, you'll need to use triggers instead.

提交回复
热议问题