ERROR 1062 (23000): Duplicate entry
Error Message
ERROR 1062 (23000): Duplicate entry '123' for key 'PRIMARY'
Or variations such as:
ERROR 1062 (23000): Duplicate entry 'example@email.com' for key 'users.email'
ERROR 1062 (23000): Duplicate entry 'product-slug' for key 'products.UQ_slug'
Description
This error occurs when you attempt to insert or update a record with a value that already exists in a field that has a unique constraint. The unique constraint could be a primary key, unique index, or unique key.
Causes
- Attempting to insert a record with a primary key that already exists
- Inserting data that would violate a unique index constraint
- Loading data from external sources without checking for duplicates
- Explicitly setting auto-increment values that already exist
- Conflicts arising from concurrent writes to different master servers
- Application code not checking for existing records before insertion
- Expecting INSERT IGNORE to handle a different kind of error
Solutions
-
Use INSERT ... ON DUPLICATE KEY UPDATE:
INSERT INTO users (id, name, email, last_login) VALUES (1, 'John Doe', 'john@example.com', NOW()) ON DUPLICATE KEY UPDATE name = VALUES(name), last_login = VALUES(last_login);
-
Use REPLACE INTO:
REPLACE INTO users (id, name, email) VALUES (1, 'John Doe', 'john@example.com');
-
Check if records exist before inserting:
-- Using INSERT ... SELECT with NOT EXISTS INSERT INTO users (name, email) SELECT 'John Doe', 'john@example.com' FROM dual WHERE NOT EXISTS ( SELECT 1 FROM users WHERE email = 'john@example.com' );
-
Use INSERT IGNORE:
INSERT IGNORE INTO users (id, name, email) VALUES (1, 'John Doe', 'john@example.com');
Prevention
-
Use auto-increment keys properly:
-- Don't specify the auto-increment column INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com');
-
Implement proper validation in application code before database operations
-
Handle batch imports with de-duplication:
-- Insert only non-duplicates INSERT INTO users (id, name, email) SELECT t.id, t.name, t.email FROM temp_import t LEFT JOIN users u ON t.email = u.email WHERE u.email IS NULL;
-
Use transactions when performing multiple related inserts