Insert, on duplicate update in PostgreSQL?

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

    I use this function merge

    CREATE OR REPLACE FUNCTION merge_tabla(key INT, data TEXT)
      RETURNS void AS
    $BODY$
    BEGIN
        IF EXISTS(SELECT a FROM tabla WHERE a = key)
            THEN
                UPDATE tabla SET b = data WHERE a = key;
            RETURN;
        ELSE
            INSERT INTO tabla(a,b) VALUES (key, data);
            RETURN;
        END IF;
    END;
    $BODY$
    LANGUAGE plpgsql
    
    0 讨论(0)
  • 2020-11-21 05:53

    For merging small sets, using the above function is fine. However, if you are merging large amounts of data, I'd suggest looking into http://mbk.projects.postgresql.org

    The current best practice that I'm aware of is:

    1. COPY new/updated data into temp table (sure, or you can do INSERT if the cost is ok)
    2. Acquire Lock [optional] (advisory is preferable to table locks, IMO)
    3. Merge. (the fun part)
    0 讨论(0)
  • 2020-11-21 05:54

    With PostgreSQL 9.1 this can be achieved using a writeable CTE (common table expression):

    WITH new_values (id, field1, field2) as (
      values 
         (1, 'A', 'X'),
         (2, 'B', 'Y'),
         (3, 'C', 'Z')
    
    ),
    upsert as
    ( 
        update mytable m 
            set field1 = nv.field1,
                field2 = nv.field2
        FROM new_values nv
        WHERE m.id = nv.id
        RETURNING m.*
    )
    INSERT INTO mytable (id, field1, field2)
    SELECT id, field1, field2
    FROM new_values
    WHERE NOT EXISTS (SELECT 1 
                      FROM upsert up 
                      WHERE up.id = new_values.id)
    

    See these blog entries:

    • Upserting via Writeable CTE
    • WAITING FOR 9.1 – WRITABLE CTE
    • WHY IS UPSERT SO COMPLICATED?

    Note that this solution does not prevent a unique key violation but it is not vulnerable to lost updates.
    See the follow up by Craig Ringer on dba.stackexchange.com

    0 讨论(0)
  • 2020-11-21 05:55

    UPDATE will return the number of modified rows. If you use JDBC (Java), you can then check this value against 0 and, if no rows have been affected, fire INSERT instead. If you use some other programming language, maybe the number of the modified rows still can be obtained, check documentation.

    This may not be as elegant but you have much simpler SQL that is more trivial to use from the calling code. Differently, if you write the ten line script in PL/PSQL, you probably should have a unit test of one or another kind just for it alone.

    0 讨论(0)
提交回复
热议问题