Как мне обновить, если существует, вставить, если нет (AKA "upsert" или "merge" ) в MySQL?

Есть ли простой способ INSERT строки, если она не существует, или UPDATE, если она существует, используя один запрос MySQL?

Ответ 1

Да, INSERT ... ON DUPLICATE KEY UPDATE. Например:

INSERT INTO `usage`
(`thing_id`, `times_used`, `first_time_used`)
VALUES
(4815162342, 1, NOW())
ON DUPLICATE KEY UPDATE
`times_used` = `times_used` + 1

Ответ 2

Я знаю, что это старый вопрос, но Google привел меня сюда недавно, поэтому я думаю, что другие тоже приходят сюда.

@chaos верен: существует синтаксис INSERT ... ON DUPLICATE KEY UPDATE.

Однако исходный вопрос задавался специально о MySQL, а в MySQL существует синтаксис REPLACE INTO .... IMHO, эта команда проще и проще использовать для upserts. Из руководства:

REPLACE работает точно так же, как INSERT, за исключением того, что если старая строка в таблице имеет то же значение, что и новая строка для PRIMARY KEY или UNIQUE, старая строка будет удалена до того, как будет вставлена ​​новая строка.

Обратите внимание, что это не стандартный SQL. Пример из руководства:

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)

Изменить: Просто справедливое предупреждение о том, что REPLACE INTO не похоже на UPDATE. Как говорится в руководстве, REPLACE удаляет строку, если она существует, а затем вставляет новую. (Обратите внимание на смешные "2 строки, затронутые" в приведенном выше примере). То есть он заменит значения всех столбцов существующей записи (а не просто обновит некоторые столбцы). Поведение MySQL REPLACE INTO очень похоже на то, что Sqlite INSERT OR REPLACE INTO. См. этот вопрос для некоторых обходных путей, если вы хотите обновить несколько столбцов (и не все столбцы), если запись уже существует.