982

I want to add a row to a database table, but if a row exists with the same unique key I want to update the row.

For example:

INSERT INTO table_name (ID, NAME, AGE) VALUES(1, "A", 19);

Let’s say the unique key is ID, and in my Database, there is a row with ID = 1. In that case, I want to update that row with these values. Normally this gives an error.
If I use INSERT IGNORE it will ignore the error, but it still won’t update.

informatik01
  • 15,174
  • 9
  • 67
  • 100
Keshan
  • 12,589
  • 10
  • 44
  • 71
  • 10
    SQL needs an official syntax for this use case that doesn't force duplication of values in the syntax and preserves the primary key. – Pete Alvin Jan 26 '18 at 13:02
  • To get the influenced id refer to [MySQL ON DUPLICATE KEY - last insert id?](https://stackoverflow.com/q/778534/6521116) – LF00 Apr 24 '19 at 06:30
  • 1
    **Caveat:** as of version 5.7 this approach does not directly support WHERE clause as part of the INSERT/UPDATE operation. Also, an UPDATE actually counts as two separate operations (DELETE and INSERT) ... in case that matters for audit purposes. (Learnbit) – dreftymac Jul 10 '19 at 21:01

11 Answers11

1790

Use INSERT ... ON DUPLICATE KEY UPDATE

QUERY:

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name="A", age=19
Donnie
  • 41,533
  • 8
  • 62
  • 82
  • 103
    +1 From what I've found, this method is less problematic for auto-increment keys and other unique key collisions than REPLACE INTO, and it is more efficient. – Andrew Ensley May 11 '12 at 21:27
  • 2
    Great answer and link. This method is best since it checks `PRIMARY` keys, `UNIQUE` indexes and auto increment columns. So `INSERT INTO table (a,b,c) VALUES (NULL, "A", 19)` will still cause an update event. – The Thirsty Ape Jul 17 '13 at 17:06
  • 54
    I know all of you allude to this, but I want to be explicit for others. If the ID you insert is NOT the PRIMARY KEY or UNIQUE, then this will not work. This didn't initially work for me because my ID was not unique. – Keven Dec 04 '13 at 21:12
  • 7
    I wonder why `affected row count` results in `2` when successfully updating (on duplicate key) single row? Anyone else had this result? (The data is updated correctly: meaning only 1 row is updated) – Dimitry K Feb 20 '14 at 15:17
  • 1
    Dimitry K - confirmed. On an update the result sometimes reports affecting two queries (even though I had only one in the table). Sometimes it reports 0 (!) affected rows. Insert always affects one row. I don't understand why this is however. – ılǝ Mar 31 '14 at 05:05
  • 18
    This is a bit late, but anyway: it is stated in the [manual](https://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html]) that updates in `ON DUPLICATE KEY UPDATE` increase the affected rows by 2. It reports 0 if nothing is actually updated (same as the regular `UPDATE`). – Vatev Mar 31 '14 at 11:53
  • 1
    Is there any way to combine this with multiple inserts (using one INSERT statement) ? MSSQL allows for up to 1000 rows to be inserted using 1 statement, and I really need to do that but using this answer. – dominicbri7 Jul 18 '14 at 19:59
  • Is there a way to find out which query was run? I want to save it in a boolean and process accordingly. Set the insert boolean to true if Duplicate key was not found false other wise. – harishannam Feb 12 '15 at 08:02
  • Perfect! Thanks! I used in transaction UPDATE first, if 0 row affected INSERT before see this! – LINKeRxUA May 27 '15 at 08:43
  • How to check(IF NOT EXIST) two column in same time? – Iman Marashi Sep 25 '15 at 06:59
  • 5
    The reason that it sometimes says 2 rows affected is so that you can tell whether an insert or update was performed. 1 row affected = insert, 2 rows affected = update. http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html – Mikhail Janowski Nov 23 '15 at 10:53
  • hmm, not working for me.. "syntax error near 'ON'".. setting the field to unique & deleting / recreating provides the same result for my <50 datasets :) – Martin Pfeffer Dec 29 '15 at 19:24
  • I have a few fields, so it looks like this method is going to result in a huge binding call (PHP / mysqli). I'm going to investigate REPLACE - the comments flag a few caveats, but all look to be okay for my application. – winwaed Jan 29 '16 at 22:12
  • 76
    Also note that you can use VALUES (name) to reference to the value you attempt to insert e.g. INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE name=VALUES(name) , age=VALUES(age) – Curious Sam Mar 01 '16 at 10:07
  • 1
    @Donnie and others, I want to use this query, but I want to check if there is a record against project_id = pId and expert_id = eId then UPDATE ml_match else INSERT project_id, expert_id, ml_match and ignore the other columns. Can you write query? Is ON DUPLICATE KEY UPDATE work only on primary key or any field name? – Khalid Usman Nov 26 '16 at 06:34
  • Nicely done for flexibility on queries, just concating at the end of an insert. – Dadan Dec 01 '16 at 01:21
  • hey, friends i want to check name is available in database and is available then replace age otherwise insert record – Pankaj Talaviya Jan 05 '17 at 06:43
  • 2
    Bear in mind there is a problem with "On Duplicate Key update". If it fails for any reason the autocomplete id is still automatically incremented even if no data is added. For this reason I do not use this. I just check if there is a current id. If there is I update, and if there is no id I insert. – Thomas Williams Jan 09 '17 at 10:40
  • @Keven Great point, altough if your ID is not unique, it is not ID, is it ? :D You can say its occurance in table is not unique, but you can't really say ID is not unique x) ... – jave.web Jan 30 '17 at 09:16
  • 2
    @ersks- This is explicitly a MySQL construct. If it's not working, your table schema is wrong for what you were attempting, or you're using it wrong. – Donnie Jul 31 '17 at 15:56
  • @Donnie, Working fine. Thanks. – Ram Apr 20 '18 at 10:40
  • @abdullahbd This is incorrect. On dupblicate key UPDATE updates, not deletes. Otherwise the primary key would change (REPLACE INTO deletes and inserts). The affected rows is just a return code. 1 row means you inserted, 2 means you updated, 0 means nothing happend. (This is also documented in the mysql documentation) – Donnie May 18 '20 at 17:05
  • powerful solution just saved for a few weeks, i think :) – spetsnaz Sep 08 '20 at 03:32
272

Check out REPLACE

http://dev.mysql.com/doc/refman/5.0/en/replace.html

REPLACE into table (id, name, age) values(1, "A", 19)
Konerak
  • 37,118
  • 11
  • 93
  • 114
Martin Schapendonk
  • 11,049
  • 3
  • 16
  • 24
  • 13
    @Piontek Because this one is shorter and easier to understand and no-one explained why "insert on duplicate" is better. – Mr_Chimp Jun 13 '13 at 13:55
  • 89
    it changes the IDs of the record and thus may destroy foreign references. – boh Sep 13 '13 at 05:32
  • 114
    The other problem with REPLACE INTO is that you _must_ specify values for ALL fields...otherwise fields will get lost or replaced with default values. REPLACE INTO essentially **deletes** the row if it exists, and inserts the new row. In the example, if you did 'REPLACE INTO table (id, age) values (1, 19) then the name field would become null. – Dale Dec 08 '13 at 08:05
  • 38
    This is actually DELETE the entire row and perform new INSERT. – mjb Jun 12 '14 at 04:05
  • 9
    @mjb Hence you need to have DELETE privileges, which it's best not to have if you don't need them. My environment's database user only has INSERT and UPDATE permissions, so REPLACE won't work. – ndm13 Jun 05 '15 at 00:42
  • 6
    It doesn't change the ID of the record, but it deletes the record then re-inserts it on match, which MySQL takes as violating foreign keys. – Thomas Andrews Feb 04 '16 at 15:13
61

When using batch insert use the following syntax:

INSERT INTO TABLE (id, name, age) VALUES (1, "A", 19), (2, "B", 17), (3, "C", 22)
ON DUPLICATE KEY UPDATE
    name = VALUES (name),
    ...
user247702
  • 21,902
  • 13
  • 103
  • 146
Fabiano Souza
  • 771
  • 6
  • 4
27

Any of these solution will work regarding your question:

INSERT IGNORE INTO table (id, name, age) VALUES (1, "A", 19);

or

INSERT INTO TABLE (id, name, age) VALUES(1, "A", 19) 
    ON DUPLICATE KEY UPDATE NAME = "A", AGE = 19;  

or

REPLACE INTO table (id, name, age) VALUES(1, "A", 19);

If you want to know in details regarding these statement visit this link

SherylHohman
  • 12,507
  • 16
  • 70
  • 78
Dilraj Singh
  • 600
  • 7
  • 9
  • `REPLACE` is not documented in the linked document. – Ray Baxter Mar 12 '18 at 22:04
  • sql queries full of typos, your examples won't work. It's INSERT INTO TABLE (not INTO TABLE) and ON DUPLICATE KEY UPDATE (not ON DUPLICATE UPDATE SET). Not sure who's upvoting this – Robert Sinclair Nov 02 '18 at 03:49
  • 1
    Sorry for the typos error. Thanks for correcting me – Dilraj Singh Nov 29 '18 at 09:48
  • 2
    How `INSERT IGNORE` will work here? It just ignores the insertion error and does NOT do the update, so in no way can be treated as an answer to the OP question. – RAM237 Feb 25 '21 at 08:04
25

Try this out:

INSERT INTO table (id, name, age) VALUES (1, 'A', 19) ON DUPLICATE KEY UPDATE id = id + 1;

Hope this helps.

Luis Reyes
  • 358
  • 2
  • 7
  • 6
    actually i don't need to add the new values to another row with a new ID instead i want to replace the existing values of id = 1 with this values. (as i understand this increments the id and add the data) – Keshan Nov 17 '10 at 14:21
  • 54
    I don't think he wants to increase the id by one on duplicates. – Donnie Nov 17 '10 at 14:22
  • This is a better answer IMO, as it transgress all flavours of SQL and not just MySQL – Fandango68 Oct 28 '15 at 00:45
  • 7
    "transgress" is not the word you're looking for :) Unfortunately, now I've seen "transgress", I can no longer visualise the actual word.. – mwfearnley Apr 13 '17 at 07:47
  • 1
    Were you looking for "traverses" or "covers"? – Chris Dev Jun 28 '17 at 13:52
  • 4
    @mwfearnley The word you were trying to visualise is "transcends". Only took a year and a half :-) – Michael Krebs Sep 03 '18 at 16:11
24

Try this:

INSERT INTO table (id,name,age) VALUES('1','Mohammad','21') ON DUPLICATE KEY UPDATE name='Mohammad',age='21'

Note:
Here if id is the primary key then after first insertion with id='1' every time attempt to insert id='1' will update name and age and previous name age will change.

Atur
  • 1,392
  • 6
  • 26
  • 37
Rasel
  • 4,555
  • 3
  • 26
  • 35
  • I want to work without using *id*. Have you tried without primary key? – ersks Jul 06 '17 at 06:41
  • @ersks see the question. user asked about when there is an unique key – Rasel Jul 09 '17 at 08:44
  • I got that, but I am trying to solve my problem in which these only values are know. So, in such situation I wrote above comment hoping correct solution. – ersks Jul 13 '17 at 08:33
16

When using SQLite:

REPLACE into table (id, name, age) values(1, "A", 19)

Provided that id is the primary key. Or else it just inserts another row. See INSERT (SQLite).

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
DawnSong
  • 3,232
  • 1
  • 26
  • 35
  • What `replace into` does is exactly "insert into, or update when existing". @Owl – DawnSong Nov 17 '16 at 15:38
  • +1 ( 1 of 3 ) I found this to work for my situation - I needed to replace an existing row with a unique key or if not there then add the row. Simplest of solutions here. – therobyouknow Jan 30 '17 at 01:21
  • ( 2 of 3 ) My query: `CREATE TRIGGER worklog_update AFTER INSERT ON worklog FOR EACH ROW REPLACE INTO support_time_monthly_hours ( ProjectID, monthTotalTime, Year, Month ) SELECT jiraissue.PROJECT, SUM(worklog.timeworked), YEAR(CURRENT_DATE()), MONTH(CURRENT_DATE()) FROM worklog, jiraissue WHERE worklog.issueid = jiraissue.ID AND jiraissue.PROJECT = (SELECT PROJECT FROM jiraissue WHERE NEW.issueid = jiraissue.ID ) AND worklog.startdate BETWEEN DATE_FORMAT(NOW() ,'%Y-%m-01 00:00:00') AND NOW();` – therobyouknow Jan 30 '17 at 01:22
  • ( 3 of 3 ) Related question/answer http://stackoverflow.com/questions/41767517/insert-row-into-mysql-table-result-from-query-into-one-field-and-sql-function-re – therobyouknow Jan 30 '17 at 01:23
  • 2
    The problem with this in mysql is that replace will remove other values in case they are not provided. However @fabiano-souza solution is more appropriate – Quamber Ali Mar 21 '18 at 13:37
14

Just because I was here looking for this solution but for updating from another identically-structured table (in my case website test DB to live DB):

INSERT  live-db.table1
SELECT  *
FROM    test-db.table1 t
ON DUPLICATE KEY UPDATE
        ColToUpdate1 = t.ColToUpdate1,
        ColToUpdate2 = t.ColToUpdate2,
        ...

As mentioned elsewhere, only the columns you want to update need to be included after ON DUPLICATE KEY UPDATE.

No need to list the columns in the INSERT or SELECT, though I agree it's probably better practice.

SteveCinq
  • 1,696
  • 1
  • 12
  • 19
9

In case that you wanted to make a non-primary fields as criteria/condition for ON DUPLICATE, you can make a UNIQUE INDEX key on that table to trigger the DUPLICATE.

ALTER TABLE `table` ADD UNIQUE `unique_index`(`name`);

And in case you want to combine two fields to make it unique on the table, you can achieve this by adding more on the last parameter.

ALTER TABLE `table` ADD UNIQUE `unique_index`(`name`, `age`);

Note, just make sure to delete first all the data that has the same name and age value across the other rows.

DELETE table FROM table AS a, table AS b WHERE a.id < b.id 
AND a.name <=> b.name AND a.age <=> b.age;

After that, it should trigger the ON DUPLICATE event.

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name = VALUES(name), age = VALUES(age)
Rich
  • 3,094
  • 1
  • 23
  • 52
  • I have tried that, I am gettting an error that says "BLOB/TEXT column 'column_name' used in key specification without a key length" – Natalia Oct 21 '20 at 14:32
  • @Natalia kindly create a [dbfiddle](https://dbfiddle.uk/) so I can check – Rich Oct 21 '20 at 14:34
  • 1
    I will try, but basically, you can not make text type of a column unique in MySQL. I made it varchar. – Natalia Oct 21 '20 at 15:22
6

In my case i created below queries but in the first query if id 1 is already exists and age is already there, after that if you create first query without age than the value of age will be none

REPLACE into table SET `id` = 1, `name` = 'A', `age` = 19

for avoiding above issue create query like below

INSERT INTO table SET `id` = '1', `name` = 'A', `age` = 19 ON DUPLICATE KEY UPDATE `id` = "1", `name` = "A",`age` = 19

may it will help you ...

Renish Gotecha
  • 1,226
  • 13
  • 11
  • 4
    Does anyone know why we must assign the values twice? Why doesn't MySQL allow us to end the query at ON DUPLICATE KEY UPDATE without duplicating all the assignment statements? Some database tables have many columns, and this seems redundant / gratuitous. I understand why we have the option for alternate assignments, but why not have the option to omit them as well? Just curious if anyone knows. – Blue Water May 15 '19 at 13:50
4

In case, you want to keep old field (For ex: name). The query will be:

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name=name, age=19;
Xman Classical
  • 4,362
  • 1
  • 22
  • 25