Concept Flow - ON DUPLICATE KEY UPDATE
Attempt INSERT row
Check for duplicate key
Insert row
Finish
When inserting a row, MySQL checks if a duplicate key exists. If no duplicate, it inserts. If yes, it updates the existing row instead.
INSERT INTO users (id, name, age) VALUES (1, 'Alice', 30) ON DUPLICATE KEY UPDATE age = age + 1;
| Step | Action | Duplicate Key Check | Result | Table State |
|---|---|---|---|---|
| 1 | Insert (id=1, name='Alice', age=30) | No duplicate | Row inserted | [{id:1, name:'Alice', age:30}] |
| 2 | Insert (id=1, name='Alice', age=30) | Duplicate on id=1 | Update age = age + 1 | [{id:1, name:'Alice', age:31}] |
| 3 | Insert (id=2, name='Bob', age=25) | No duplicate | Row inserted | [{id:1, name:'Alice', age:31}, {id:2, name:'Bob', age:25}] |
| 4 | Insert (id=2, name='Bob', age=25) | Duplicate on id=2 | Update age = age + 1 | [{id:1, name:'Alice', age:31}, {id:2, name:'Bob', age:26}] |
| 5 | Insert (id=3, name='Carol', age=22) | No duplicate | Row inserted | [{id:1, name:'Alice', age:31}, {id:2, name:'Bob', age:26}, {id:3, name:'Carol', age:22}] |
| 6 | Insert (id=3, name='Carol', age=22) | Duplicate on id=3 | Update age = age + 1 | [{id:1, name:'Alice', age:31}, {id:2, name:'Bob', age:26}, {id:3, name:'Carol', age:23}] |
| 7 | Insert (id=4, name='Dave', age=40) | No duplicate | Row inserted | [{id:1, name:'Alice', age:31}, {id:2, name:'Bob', age:26}, {id:3, name:'Carol', age:23}, {id:4, name:'Dave', age:40}] |
| 8 | Insert (id=4, name='Dave', age=40) | Duplicate on id=4 | Update age = age + 1 | [{id:1, name:'Alice', age:31}, {id:2, name:'Bob', age:26}, {id:3, name:'Carol', age:23}, {id:4, name:'Dave', age:41}] |
| 9 | Insert (id=5, name='Eve', age=28) | No duplicate | Row inserted | [{id:1, name:'Alice', age:31}, {id:2, name:'Bob', age:26}, {id:3, name:'Carol', age:23}, {id:4, name:'Dave', age:41}, {id:5, name:'Eve', age:28}] |
| 10 | Insert (id=5, name='Eve', age=28) | Duplicate on id=5 | Update age = age + 1 | [{id:1, name:'Alice', age:31}, {id:2, name:'Bob', age:26}, {id:3, name:'Carol', age:23}, {id:4, name:'Dave', age:41}, {id:5, name:'Eve', age:29}] |
| 11 | Attempt Insert (id=6, name='Frank', age=35) | No duplicate | Row inserted | [{id:1, name:'Alice', age:31}, {id:2, name:'Bob', age:26}, {id:3, name:'Carol', age:23}, {id:4, name:'Dave', age:41}, {id:5, name:'Eve', age:29}, {id:6, name:'Frank', age:35}] |
| 12 | Attempt Insert (id=6, name='Frank', age=35) | Duplicate on id=6 | Update age = age + 1 | [{id:1, name:'Alice', age:31}, {id:2, name:'Bob', age:26}, {id:3, name:'Carol', age:23}, {id:4, name:'Dave', age:41}, {id:5, name:'Eve', age:29}, {id:6, name:'Frank', age:36}] |
| 13 | Stop | N/A | All inserts processed | Final table state as above |
| Variable | Start | After 1 | After 2 | After 3 | After 4 | After 5 | After 6 | After 7 | After 8 | After 9 | After 10 | After 11 | After 12 | Final |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Table rows count | 0 | 1 | 1 | 2 | 2 | 3 | 3 | 4 | 4 | 5 | 5 | 6 | 6 | 6 |
| Alice age | N/A | 30 | 31 | 31 | 31 | 31 | 31 | 31 | 31 | 31 | 31 | 31 | 31 | 31 |
| Bob age | N/A | N/A | N/A | 25 | 26 | 26 | 26 | 26 | 26 | 26 | 26 | 26 | 26 | 26 |
| Carol age | N/A | N/A | N/A | N/A | N/A | 22 | 23 | 23 | 23 | 23 | 23 | 23 | 23 | 23 |
| Dave age | N/A | N/A | N/A | N/A | N/A | N/A | N/A | 40 | 41 | 41 | 41 | 41 | 41 | 41 |
| Eve age | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | 28 | 29 | 29 | 29 | 29 |
| Frank age | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | 35 | 36 | 36 |
INSERT INTO table (columns) VALUES (values) ON DUPLICATE KEY UPDATE column = value; - Tries to insert a row. - If duplicate key exists, runs UPDATE instead. - Useful to avoid errors and update existing rows. - Can use expressions like column = column + 1.