Як оновити, якщо існує, вставити, якщо ні (AKA "upsert" або "spage") в MySQL?


Відповіді:


191

Використовуйте 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

10
Так, я вважаю, еквівалент SQL Server називається MERGE. Загалом, поняття часто називають "UPSERT".
хаос

3
@blub: Якщо ви створюєте унікальний ключ на gebі topicвін буде працювати ( ALTER TABLE table ADD UNIQUE geb_by_topic (geb, topic)).
хаос

1
@Brian: Еквівалент Oracle також називається, MERGEале я не впевнений, чи його синтаксис ідентичний синтаксису SQL Server.
Кен Кінан

1
@Brooks: Якщо ви передасте його 0, воно фактично використовуватиме 0 як значення. Тож не робіть цього. Не передавайте нічого і не передайте його NULL, щоб дозволити auto_incrementповедінці працювати (що в іншому випадку, так, працює, як ви припускаєте; див. Dev.mysql.com/doc/refman/5.5/uk/example-auto-increment). html ).
хаос

3
Дякуємо, і ви можете скористатися VALUES(col)для отримання значення з аргументу insert у разі дублювання. Напр .:ON DUPLICATE UPDATE b = VALUES(b), c = VALUES(c)
геррітан

5

Я знаю, що це давнє запитання, але Google останнім часом мене привів сюди, тому я думаю, що сюди також приходять інші.

@chaos правильний: є INSERT ... ON DUPLICATE KEY UPDATEсинтаксис.

Однак оригінальне питання, яке задають саме про MySQL, а в MySQL є REPLACE INTO ...синтаксис. ІМХО, цю команду легше і простіше використовувати для поновлення. З посібника:

REPLACE працює точно так само, як INSERT, за винятком випадків, коли старий рядок у таблиці має те саме значення, що й новий рядок для PRIMARY KEY або UNIQUE index, старий рядок видаляється перед тим, як вставити новий рядок.

Зауважте, це не стандартний 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. Перегляньте це питання для деяких обхідних шляхів, якщо ви хочете оновити лише кілька стовпців (а не всіх стовпців), якщо запис уже існує.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.