VillageSQL is a drop-in replacement for MySQL with extensions.
All examples in this guide work on VillageSQL. Install Now →
UPSERT keyword, but it has three ways to insert a row or handle a conflict: INSERT ... ON DUPLICATE KEY UPDATE, REPLACE INTO, and INSERT IGNORE. They behave very differently — picking the wrong one can silently corrupt data.
INSERT … ON DUPLICATE KEY UPDATE
When the insert would violate a unique constraint (primary key or unique index), MySQL runs theUPDATE instead:
VALUES(col) syntax also works but is deprecated — use row aliases instead:
REPLACE INTO
REPLACE deletes the conflicting row and inserts a new one. It looks like an upsert but behaves like a delete + insert:
BEFORE DELETE and AFTER DELETE triggers on the target table and resets the AUTO_INCREMENT counter for the new row. Because the delete is a real row delete, ON DELETE CASCADE and the other foreign key actions on referencing tables DO fire. Any columns not listed in the REPLACE get their default values — not the previous row’s values.
Use REPLACE only when you genuinely want to discard the old row entirely.
INSERT IGNORE
INSERT IGNORE downgrades errors to warnings. On a key conflict it skips the row; on a type mismatch or truncation it writes a coerced value instead:
INSERT IGNORE is that it suppresses all errors, not just duplicates — and the non-duplicate cases are worse than a skipped row. INSERT IGNORE INTO page_views VALUES ('/new', 'not_a_number') inserts ('/new', 0) with only a warning: a silent, corrupted write rather than a no-op. Use it only when you genuinely don’t care about the outcome.
Comparison
AUTO_INCREMENT Side Effect
ON DUPLICATE KEY UPDATE increments the AUTO_INCREMENT counter even when it takes the update path, not the insert path. Over time this creates gaps in the sequence:
Frequently Asked Questions
Is ON DUPLICATE KEY UPDATE atomic?
Yes — the insert attempt and the update happen in a single atomic operation. You don’t need to wrap it in a transaction to avoid a race condition between checking existence and inserting.What if multiple unique indexes conflict?
If an insert violates more than one unique constraint simultaneously, MySQL updates only one row — which one is undefined. Avoid designs where a single INSERT can conflict on multiple unique indexes. If your schema has overlapping unique constraints, test the behavior carefully.Can I use ON DUPLICATE KEY UPDATE with multi-row inserts?
Yes:VALUES for the multi-row case and AS new for the alias.
Troubleshooting
See also
- Transactions in MySQL — when to wrap UPSERT in a transaction
- Deadlocks in MySQL — INSERT … ON DUPLICATE KEY UPDATE can cause deadlocks under concurrency
- Bulk Inserts in MySQL — loading many rows fast, with or without conflict handling
- Common MySQL Errors and How to Fix Them — duplicate-key errors and what they mean

