18

Very often, I want to run a query on one of my users where I want a row stored and associated with that user, in a 1-to-1 relationship. So let's say (this is just an arbitrary example), that I have a table that keeps track of a user's car, along with some info about the car. Each user can have either 0 or 1 cars. If the user has no car, there is no entry in the table for that user.

cars table (again, just an example): id, user_id, car_make, car_model

So, when I update this table, I always end up doing something like this (pseudo-code):

result = SELECT * FROM cars WHERE user_id=5
if (num_rows(result)>0){
    UPDATE cars SET car_make='toyota', car_model='prius' WHERE user_id=5
}else{
    INSERT INTO cars (user_id, car_make, car_model) VALUES (5, 'toyota', 'prius')
}

How can I make this into one elegant statement that works "atomically"? What happens if, in another process, the row is REMOVED between the SELECT and UPDATE statements? My UPDATE statement will fail where the INSERT statement should have run. And I feel like I need to do two similar (but different) statements to accomplish the same thing! What I need is some statement that will assure me that the data I want exists in the table, especially when I only want 1 row that satisfies my requirement. For example, it might be something like (this is totally made-up of course):

MAKE SURE A ROW IN cars WHERE user_id=5 IS SET WITH car_make='toyota', car_model='prius'

That way, if user_id of 5 exists already, it will be updated, otherwise, it will be inserted. Also, if I changed the requirements, for example to say that each user can have zero or one cars of a given car_make, then I could further specify that:

MAKE SURE A ROW IN cars WHERE user_id=5 AND car_make='toyota' IS SET WITH car_model='prius'

I hope my question makes sense! How can I improve this basic insert-if-not-found or update-if-found operation that comes up so often? Thanks for any help!

Andrew Barnett
  • 5,066
  • 1
  • 22
  • 25
DivideByHero
  • 19,715
  • 24
  • 57
  • 64

7 Answers7

17

You can use "REPLACE INTO" or "INSERT… ON DUPLICATE KEY UPDATE". I believe the second is what you want, but there are situations where REPLACE INTO is convenient.

mishac
  • 3,288
  • 1
  • 21
  • 19
7

From my other Stack Overflow answer:

If you want to do this in a single statement, I would recommend using the INSERT ... ON DUPLICATE KEY UPDATE syntax, as follows:

INSERT INTO table (id, someothervalue) VALUES (1, 'hi mom')
  ON DUPLICATE KEY UPDATE someothervalue = 'hi mom';

The initial INSERT statement will execute if there is no existing record with the specified key value (either primary key or unique). If a record already exists, the following UPDATE statement (someothervalue = 3) is executed.

This is supported in all versions of MySQL. For more info, see the MySQL Reference Manual page for INSERT ... ON DUPLICATE KEY UPDATE

Community
  • 1
  • 1
defines
  • 10,229
  • 4
  • 40
  • 56
3

This is called an UPSERT (UPdate or inSERT). There are a number of SO questions about it you can search for. See Wikipedia

EDIT: MySQL 4.1+ supports INSATE (INSert or updATE), which should get you the same thing, as long as you have a primary key. MySQL Manual

bishop
  • 37,830
  • 11
  • 104
  • 139
Andrew Barnett
  • 5,066
  • 1
  • 22
  • 25
1

I think it's easier to switch it around. Try to insert, then update.

MySQL specifically has a clause 'ON DUPLICATE KEY'

INSERT INTO cars (fields) VALUES (values) ON DUPLICATE KEY UPDATE ...

This of course requires you to have proper unique keys setup.

Darryl E. Clarke
  • 7,537
  • 3
  • 26
  • 34
0

Set your column attributes to UNIQUE, otherwise will make a duplicate entry.

pingle60
  • 726
  • 7
  • 9
0

In Oracle you have Merge.

No idea on MySql, but the term might give you something else to search.

juan
  • 80,295
  • 52
  • 162
  • 195
0

an example of how I have used ON DUPLICATE KEY UPDATE: INSERT INTO registry (name, value) VALUES ('" . $key . "', '" . $val . "') ON DUPLICATE KEY UPDATE value= '" . $val . "'"