MySQL bulk INSERT o UPDATE

¿Hay alguna manera de realizar a granel una consulta como INSERT OR UPDATE en el server MySQL?

 INSERT IGNORE ... 

no funcionará, porque si el campo ya existe, simplemente lo ignorará y no insertá nada.

 REPLACE ... 

no funcionará, porque si el campo ya existe, primero lo DELETE y luego lo INSERT nuevamente, en lugar de actualizarlo.

 INSERT ... ON DUPLICATE KEY UPDATE 

funcionará, pero no se puede usar a granel.

Así que me gustaría saber si hay algún command como INSERT ... ON DUPLICATE KEY UPDATE que pueda emitirse a granel (más de una fila al mismo time).

Puede insert / actualizar varias filas usando INSERTAR … EN ACTUALIZACIÓN DE LLAVE DUPLICADA. La documentation tiene el siguiente ejemplo:

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

¿O estoy malentendiendo su pregunta?

Una forma posible de hacerlo es crear una tabla temporal, insert los datos en eso y luego hacer 1 consulta con una combinación para insert los loggings que no existen seguidos por y actualizar a los campos que sí existen. Lo básico sería algo como esto.

 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 

La syntax puede no ser exacta, pero esto debería darle los conceptos básicos. Además, sé que no es bonita, pero hace el trabajo bien.

Actualizar

Cambié el order de la inserción y la actualización, porque hacer insert primero hace que todas las filas insertadas se actualicen cuando se llama la actualización. Si primero se actualiza, solo se actualizan los loggings existentes. Esto debería significar un poco less de trabajo para el server, aunque los resultados deberían ser los mismos.

Aunque esta pregunta ya se ha respondido correctamente (que MySQL sí lo admite a través de ON DUPLICATE UPDATE con la syntax del set de valores múltiples esperado), me gustaría ampliar esto al proporcionar una demostración que cualquier persona con MySQL puede ejecutar:

 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; 

El resultado es el siguiente:

 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) 

Intente agregar un activador de inserción que haga una comprobación previa al vuelo y cancele la inserción en la key duplicada (después de actualizar la fila existente).

No estoy seguro de que escale bien para inserciones masivas, y mucho less trabaje para cargar datos de carga, pero es lo mejor que se me ocurre. 🙂

Si usaba Oracle o Microsoft SQL, podría usar MERGE . Sin embargo, MySQL no tiene una correlación directa con esa statement. Existe la solución de una sola fila que mencionas pero, como dijiste, no hace mucho a granel. Aquí hay una publicación de blog que encontré sobre la diferencia entre Oracle y MySQL y cómo hacer lo que Oracle hace con MERGE en MySQL:

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

No es una solución bonita y probablemente no es una solución tan completa como te gustaría, pero creo que es lo mejor que hay para encontrar una solución.