INSERT INTO ... SELECT FROM ... ON DUPLICATE KEY UPDATE

116

Estoy haciendo una consulta de inserción en la que la mayoría de las columnas deberían actualizarse a los nuevos valores si ya existiera una clave única. Es algo parecido a esto:

INSERT INTO lee(exp_id, created_by, 
                location, animal, 
                starttime, endtime, entct, 
                inact, inadur, inadist, 
                smlct, smldur, smldist, 
                larct, lardur, lardist, 
                emptyct, emptydur)
SELECT id, uid, t.location, t.animal, t.starttime, t.endtime, t.entct, 
       t.inact, t.inadur, t.inadist, 
       t.smlct, t.smldur, t.smldist, 
       t.larct, t.lardur, t.lardist, 
       t.emptyct, t.emptydur 
FROM tmp t WHERE uid=x
ON DUPLICATE KEY UPDATE ...; 
//update all fields to values from SELECT, 
//       except for exp_id, created_by, location, animal, 
//       starttime, endtime

No estoy seguro de cuál UPDATEdebería ser la sintaxis de la cláusula. ¿Cómo me refiero a la fila actual de la SELECTcláusula?

dnagirl
fuente

Respuestas:

172

MySQL asumirá que la parte anterior a los iguales hace referencia a las columnas nombradas en la cláusula INSERT INTO, y la segunda parte hace referencia a las columnas SELECT.

INSERT INTO lee(exp_id, created_by, location, animal, starttime, endtime, entct, 
                inact, inadur, inadist, 
                smlct, smldur, smldist, 
                larct, lardur, lardist, 
                emptyct, emptydur)
SELECT id, uid, t.location, t.animal, t.starttime, t.endtime, t.entct, 
       t.inact, t.inadur, t.inadist, 
       t.smlct, t.smldur, t.smldist, 
       t.larct, t.lardur, t.lardist, 
       t.emptyct, t.emptydur 
FROM tmp t WHERE uid=x
ON DUPLICATE KEY UPDATE entct=t.entct, inact=t.inact, ...
Marcus Adams
fuente
6
@dnagirl: SUGERENCIA: no intente actualizar ninguna de las columnas PK, solo aquellas que necesitan actualizarse entran en la lista
lexu
45
Su sintaxis sugerida funciona y t.es obligatorio. También encontré un artículo sobre xaprb ( xaprb.com/blog/2006/02/21/flexible-insert-and-update-in-mysql ) que utiliza esta sintaxis: on duplicate key update b = values(b), c = values(c). Esto también funciona.
dnagirl
9
Nota: Esto no funcionará cuando la instrucción SELECT tenga una cláusula GROUP BY
juan
11
@john Qué hacer si la instrucción SELECT tiene una cláusula GROUP BY
Kathir
2
dev.mysql.com/doc/refman/5.6/en/insert-on-duplicate.html dice `en MySQL 5.6.4 y posterior, INSERT ... SELECT ON DUPLICATE KEY UPDATE las declaraciones se marcan como inseguras para la replicación basada en declaraciones ... Además, comenzando con MySQL 5.6.6, una instrucción INSERT ... ON DUPLICATE KEY UPDATE contra una tabla que tiene más de una clave única o primaria también se marca como insegura
Abdul Muneer
51

Aunque llegué muy tarde a esto, pero después de ver algunas preguntas legítimas para aquellos que querían usar la INSERT-SELECTconsulta con GROUP BYcláusula, se me ocurrió la solución para esto.

Llevando más lejos la respuesta de Marcus Adams y contando GROUP BYen ella, así es como resolvería el problema usandoSubqueries in the FROM Clause

INSERT INTO lee(exp_id, created_by, location, animal, starttime, endtime, entct, 
                inact, inadur, inadist, 
                smlct, smldur, smldist, 
                larct, lardur, lardist, 
                emptyct, emptydur)
SELECT sb.id, uid, sb.location, sb.animal, sb.starttime, sb.endtime, sb.entct, 
       sb.inact, sb.inadur, sb.inadist, 
       sb.smlct, sb.smldur, sb.smldist, 
       sb.larct, sb.lardur, sb.lardist, 
       sb.emptyct, sb.emptydur
FROM
(SELECT id, uid, location, animal, starttime, endtime, entct, 
       inact, inadur, inadist, 
       smlct, smldur, smldist, 
       larct, lardur, lardist, 
       emptyct, emptydur 
FROM tmp WHERE uid=x
GROUP BY location) as sb
ON DUPLICATE KEY UPDATE entct=sb.entct, inact=sb.inact, ...
iCurioso
fuente
8
Esta es la respuesta correcta para consultas con COUNT, GROUP, etc. Gracias.
Kostanos
¡Muchas Gracias amigo! Me gustó mucho este enfoque, especialmente porque me permite crear un mecanismo como Continuous Query, algo que hace InfluxDB.
Miere
1
También puede usar field = VALUES (field) en la actualización duplicada como en la respuesta en stackoverflow.com/questions/16935896/…
Erik Melkersson