MySQL insert on duplicate update for non-PRIMARY key

后端 未结 6 1249

I am little confused with insert on duplicate update query. I have MySQL table with structure like this:

  • record_id (PRIMARY, UNIQUE)
  • person_id (UNIQU
6条回答
  •  暖寄归人
    2020-12-14 04:47

    A flexible solution should retain the atomicity offered by INSERT ... ON DUPLICATE KEY UPDATE and work regardless of if it's autocommit=true and not depend on a transaction with an isolation level of REPEATABLE READ or greater.

    Any solution performing check-then-act across multiple statements would not satisfy this.

    Here are the options:

    If there tends to be more inserts than updates:

    INSERT INTO table (record_id, ..., some_text, some_other_text) VALUES (...);
    
    IF 
      UPDATE table SET some_text = ..., some_other_text = ... WHERE record_id = ...;
    
      IF affected-rows = 0
        -- retry from INSERT OR ignore this conflict and defer to the other session
    

    If there tends to be more updates than inserts:

    UPDATE table SET some_text = ..., some_other_text = ... WHERE record_id = ...;
    
    IF affected-rows = 0
      INSERT INTO table (record_id, ..., some_text, some_other_text) VALUES (...);
    
      IF 
        -- retry from UPDATE OR ignore this conflict and defer to the other session
    

    If you don't mind a bit of ugliness, you can actually use INSERT ... ON DUPLICATE KEY UPDATE and do this in a single statement:

    INSERT INTO table (record_id, ..., some_text, some_other_text) VALUES (...)
        ON DUPLICATE KEY UPDATE
          some_text = if(record_id = VALUES(record_id), VALUES(some_text), some_text),
          some_other_text = if(record_id = VALUES(record_id), VALUES(some_other_text), some_other_text)
    
    IF affected-rows = 0
      -- handle this as a unique check constraint violation
    

    Note: affected-rows in these examples mean affected rows and not found rows. The two can be confused because a single parameter switches which of these values the client is returned.

    Also note, if some_text and some_other_text are not actually modified (and the record is not otherwise changed) when you perform the update, those checks on affected-rows = 0 will misfire.

提交回复
热议问题