Как мне обновить, если существует, вставить, если нет (AKA "upsert" или "объединить") в MySQL? - PullRequest
149 голосов
/ 02 августа 2009

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

Ответы [ 2 ]

188 голосов
/ 02 августа 2009

Да, 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
4 голосов
/ 21 мая 2017

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

@ хаос правильный: есть синтаксис INSERT ... ON DUPLICATE KEY UPDATE.

Тем не менее, оригинальный вопрос задавался именно о MySQL, а в MySQL есть синтаксис REPLACE INTO .... ИМХО, эта команда проще и проще в использовании для 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. См. этот вопрос , чтобы найти некоторые обходные пути, если вы хотите обновить только несколько столбцов (и не все столбцы), если запись уже существует.

...