How do I update if exists, insert if not (AKA "upsert" or "merge") in MySQL?
I know this is an old question, but the Google lead me here recently so I imagine others come here, too.
@chaos is correct: there is the INSERT ... ON DUPLICATE KEY UPDATE
syntax.
However, the original question asked about MySQL specifically, and in MySQL there is the REPLACE INTO ...
syntax. IMHO, this command is easier and more straightforward to use for upserts. From the manual:
REPLACE works exactly like INSERT, except that if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted.
Note this is not standard SQL. An example from the manual:
CREATE TABLE test (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
data VARCHAR(64) DEFAULT NULL,
ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
mysql> REPLACE INTO test VALUES (1, 'Old', '2014-08-20 18:47:00');
Query OK, 1 row affected (0.04 sec)
mysql> REPLACE INTO test VALUES (1, 'New', '2014-08-20 18:47:42');
Query OK, 2 rows affected (0.04 sec)
mysql> SELECT * FROM test;
+----+------+---------------------+
| id | data | ts |
+----+------+---------------------+
| 1 | New | 2014-08-20 18:47:42 |
+----+------+---------------------+
1 row in set (0.00 sec)
Edit: Just a fair warning that REPLACE INTO
isn't like UPDATE
. As the manual says, REPLACE
deletes the row if it exists, then inserts a new one. (Note the funny "2 rows affected" in the example above.) That is, it will replace the values of all columns of an existing record (and not merely update some columns.) The behavior of MySQL's REPLACE INTO
is much like that of Sqlite's INSERT OR REPLACE INTO
. See this question for some workarounds if you only want to update a few columns (and not all columns) if the record already exists.
Use INSERT ... ON DUPLICATE KEY UPDATE
. For example:
INSERT INTO `usage`
(`thing_id`, `times_used`, `first_time_used`)
VALUES
(4815162342, 1, NOW())
ON DUPLICATE KEY UPDATE
`times_used` = `times_used` + 1