【MySQL】Insert and Update

Posted by 西维蜀黍 on 2021-10-23, Last Modified on 2022-02-19

Situation

Often you have the situation that you need to check if an table entry exists, before you can make an update. If it does not exist, you have to do an insert first.

The simple straightforward approach is this:

(The example is for an entry in the WordPress wp_postmeta table)
SELECT meta_id FROM wp_postmeta
WHERE post_id = ?id AND meta_key = page_title

If ResultCount == 0

INSERT INTO wp_postmeta (post_id, meta_key, meta_value)
VALUES (?id, page_title, ?page_title)

Else

UPDATE wp_postmeta SET meta_value = ?page_title
WHERE post_id = ?id AND meta_key = page_title

Solution

This is not too bad, but we could actually combine everything into one query. I found different solutions on the internet. The simplest, but MySQL only solution is this:

INSERT INTO users (username, email) VALUES (Jo, jo@email.com)
ON DUPLICATE KEY UPDATE email = 'jo@email.com'

Note that this the ‘ON DUPLICATE KEY’ statement only works on PRIMARY KEY and UNIQUE columns.

ON DUPLICATE KEY UPDATE

Basically INSERT with an ON DUPLICATE KEY UPDATE clause enables existing rows to be updated if a row to be inserted would cause a duplicate value in a UNIQUE index or PRIMARY KEY.

INSERT IGNORE

Using INSERT IGNORE effectively causes MySQL to ignore execution errors while attempting to perform INSERT statements. This means that an INSERT IGNORE statement which contains a duplicate value in a UNIQUE index or PRIMARY KEY field does not produce an error, but will instead simply ignore that particular INSERT command entirely. The obvious purpose is to execute a large number of INSERT statements for a combination of data that is both already existing in the database as well as new data coming into the system.

mysql> INSERT INTO users (user_id, username,nickname,`password`,salt,avatar_url) VALUES (1, "1","sw_nickname","sw_password","sw_salt","aaa");
ERROR 1062 (23000): Duplicate entry '1' for key 'users.PRIMARY'

mysql> INSERT IGNORE INTO users (user_id, username,nickname,`password`,salt,avatar_url) VALUES (1, "1","sw_nickname","sw_password","sw_salt","aaa");
Query OK, 0 rows affected, 1 warning (0.00 sec)

REPLACE

In the event that you wish to actually replace rows where INSERT commands would produce errors due to duplicate UNIQUE or PRIMARY KEY values as outlined above, one option is to opt for the REPLACE statement.

When issuing a REPLACE statement, there are two possible outcomes for each issued command:

  • No existing data row is found with matching values and thus a standard INSERT statement is performed.
  • A matching data row is found, causing that existing row to be deleted with the standard DELETE statement, then a normal INSERT is performed afterward.

For example, we can use REPLACE to swap out our existing record of id = 1 of In Search of Lost Time by Marcel Proust with Green Eggs and Ham by Dr. Seuss:

mysql> REPLACE INTO books
    (id, title, author, year_published)
VALUES
    (1, 'Green Eggs and Ham', 'Dr. Seuss', 1960);
Query OK, 2 rows affected (0.00 sec)

Notice that even though we only altered one row, the result indicates that two rows were affected because we actually DELETED the existing row then INSERTED the new row to replace it.

Reference