Your question is very important. This is a very common requirement. And most people make mistakes because of what MySQL offers.
- Requirement: Insert if the
PRIMARY key exists, otherwise it is updated . - General Approach:
ON DUPLICATE KEY UPDATE - The result of this approach is alarming: Insert if the
PRIMARY key or any UNIQUE exists, otherwise it is updated !
What could go horribly wrong with ON DUPLICATE KEY UPDATE ? You are inserting a supposedly new record with a new PRIMARY key value (for example, UUID), but you have a duplicate value for your UNIQUE key.
What you want is the correct exception, indicating that you are trying to insert a duplicate in a UNIQUE column.
But what you get is undesirable UPDATE ! MySQL will take an inconsistent record and begin to rewrite its values. If this happens unintentionally, you ruined the old record, and any incoming links to the old record now refer to the new record. And since you probably won't tell you to update the PRIMARY column, your new UUID will not be found anywhere. If you ever come across this data, it probably doesnβt make sense, and you wonβt understand where it came from.
We need a solution to actually insert if the PRIMARY key does not exist, otherwise an update .
We will use a query consisting of two operators:
- Refresh where the value of the
PRIMARY key matches (affects 0 or 1 row). - Insert if the
PRIMARY key value does not exist (inserts 1 or 0 rows).
This is the request:
UPDATE my_table SET unique_name = 'one', update_datetime = NOW() WHERE id = 1; INSERT INTO my_table SELECT 1, 'one', NOW() FROM my_table WHERE id = 1 HAVING COUNT(*) = 0;
Only one of these queries will have an effect. UPDATE easy. As for INSERT : WHERE id = 1 , the result is a string if id exists, or there is no row if it is not specified. HAVING COUNT(*) = 0 inverts, resulting in a string if the identifier is new, or no string if it already exists.
I explored other variations of the same idea, such as with LEFT JOIN and WHERE , but they all looked more confusing. Improvements are welcome.