Массовая вставка или обновление MySQL

есть ли способ выполнить массовый запрос, например INSERT OR UPDATE на сервере MySQL?

INSERT IGNORE ...

не будет работать, потому что если поле уже существует, оно просто проигнорирует его и ничего не вставит.

REPLACE ...

не будет работать, потому что если поле уже существует, он будет первым DELETE и затем INSERT это снова, а не обновлять его.

INSERT ... ON DUPLICATE KEY UPDATE

будет работать, но его нельзя использовать навалом.

поэтому я хотел бы знать, есть ли команду INSERT ... ON DUPLICATE KEY UPDATE это может быть выдано навалом (более одной строки одновременно).

5 ответов


вы can вставить / обновить несколько строк с помощью INSERT ... ПРИ ОБНОВЛЕНИИ ДУБЛИРУЮЩЕГО КЛЮЧА. The документация есть следующий пример:

INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6)
ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);

или я неправильно понял ваш вопрос?


один из возможных способов сделать это-создать временную таблицу, вставить в нее данные, а затем выполнить 1 запрос с соединением, чтобы вставить записи, которые не существуют, а затем обновить до существующих полей. Основы будут примерно такими.

CREATE TABLE MyTable_Temp LIKE MyTable

LOAD DATA INFILE..... INTO MyTable_Temp

UPDATE MyTable INNER JOIN 
MyTable_Temp
ON MyTable.ID=MyTable_Temp.ID
SET MyTable.Col1=MyTable_Temp.Col1, MyTable.Col2=MyTable_Temp.Col2.....

INSERT INTO MyTable(ID,Col1,Col2,...)
SELECT ID,Col1,Col2,... 
FROM MyTable_Temp
LEFT JOIN MyTable 
ON MyTable_Temp.ID = MyTable.ID
WHERE myTable.ID IS NULL

DROP TABLE MyTable_Temp

синтаксис может быть не точным, но это должно дать вам основы. Кроме того, я знаю, что это не очень красиво, но это делает работу.

обновление

Я поменял порядок вставка и обновление, потому что при выполнении вставки сначала обновляются все вставленные строки при вызове обновления. При первом обновлении обновляются только существующие записи. Это должно означать меньше работы для сервера, хотя результаты должны быть одинаковыми.


хотя на этот вопрос уже был дан правильный ответ (что MySQL поддерживает это через повторяющееся обновление с ожидаемым синтаксисом набора нескольких значений), я хотел бы расширить это, предоставив демонстрацию, что любой с MySQL может запустить:

CREATE SCHEMA IF NOT EXISTS `test`;
DROP TABLE IF EXISTS test.new_table;
CREATE TABLE test.new_table (`Key` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`Key`)) ENGINE=InnoDB AUTO_INCREMENT=106 DEFAULT CHARSET=utf8;

SELECT * FROM test.new_table;
INSERT INTO test.new_table VALUES (1),(2),(3),(4),(5) ON DUPLICATE KEY UPDATE `Key`=`Key`+100;
SELECT * FROM test.new_table;
INSERT INTO test.new_table VALUES (1),(2),(3),(4),(5) ON DUPLICATE KEY UPDATE `Key`=`Key`+100;
SELECT * FROM test.new_table;

вывод выглядит следующим образом:

Empty set (0.00 sec)

Query OK, 5 rows affected (0.00 sec)
Records: 5  Duplicates: 0  Warnings: 0

+-----+
| Key |
+-----+
|   1 |
|   2 |
|   3 |
|   4 |
|   5 |
+-----+
5 rows in set (0.00 sec)

Query OK, 10 rows affected (0.00 sec)
Records: 5  Duplicates: 5  Warnings: 0

+-----+
| Key |
+-----+
| 101 |
| 102 |
| 103 |
| 104 |
| 105 |
+-----+
5 rows in set (0.00 sec)

попробуйте добавить триггер вставки, который выполняет предполетную проверку и отменяет вставку на дублирующем ключе (после обновления существующей строки).

Не уверен, что он будет хорошо масштабироваться для массовых вставок, не говоря уже о работе с загрузкой данных, но это лучшее, что я могу придумать. :-)


Если вы используете Oracle или Microsoft SQL, вы можете использовать MERGE. Однако MySQL не имеет прямой корреляции с этим утверждением. Существует однорядное решение, которое вы упомянули, но, как вы указали, оно не очень хорошо работает. Вот сообщение в блоге, которое я нашел о разнице между Oracle и MySQL и как сделать то, что Oracle делает с MERGE in MySQL:

http://blog.mclaughlinsoftware.com/2009/05/25/mysql-merge-gone-awry/

это не красивое решение, и это, вероятно, не такое полное решение, как вам хотелось бы, но я считаю, что это лучшее, что есть для решения.