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

116

Estou fazendo uma consulta de inserção onde a maioria das muitas colunas precisariam ser atualizadas para os novos valores se uma chave exclusiva já existisse. É mais ou menos assim:

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

Não tenho certeza de qual UPDATEdeve ser a sintaxe da cláusula. Como me refiro à linha atual da SELECTcláusula?

dnagirl
fonte

Respostas:

172

O MySQL assumirá que a parte antes de igual faz referência às colunas nomeadas na cláusula INSERT INTO, e a segunda parte faz referência às colunas 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
fonte
6
@dnagirl: DICA: não tente atualizar nenhuma das colunas PK, apenas aquelas que precisam ser atualizadas vão para a lista
lexu
45
Sua sintaxe sugerida funciona e t.é obrigatório. Eu também encontrei um artigo sobre xaprb ( xaprb.com/blog/2006/02/21/flexible-insert-and-update-in-mysql ) que utiliza esta sintaxe: on duplicate key update b = values(b), c = values(c). Isso também funciona.
dnagirl
9
Observação: isso não funcionará quando a instrução SELECT tiver uma cláusula GROUP BY
joHN
11
@john O que fazer se a instrução SELECT tiver uma cláusula GROUP BY
Kathir
2
dev.mysql.com/doc/refman/5.6/en/insert-on-duplicate.html diz `no MySQL 5.6.4 e posterior, INSERT ... SELECT ON DUPLICATE KEY UPDATE instruções são sinalizadas como inseguras para replicação baseada em instrução ... Além disso, a partir do MySQL 5.6.6, uma instrução INSERT ... ON DUPLICATE KEY UPDATE em uma tabela com mais de uma chave única ou primária também é marcada como insegura.
Abdul Muneer
51

Embora eu esteja muito atrasado para isso, mas depois de ver algumas perguntas legítimas para aqueles que queriam usar INSERT-SELECTconsulta com GROUP BYcláusula, eu vim com a solução para isso.

Aprofundando a resposta de Marcus Adams e contando GROUP BYcom ela, é assim que eu resolveria o 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, ...
iCurious
fonte
8
Esta é a resposta certa para dúvidas com COUNT, GROUP etc. Obrigado.
Kostanos
Muito obrigado, cara! Gostei muito dessa abordagem, principalmente porque me permite criar um mecanismo como o Continuous Query, algo que o InfluxDB faz.
Miere
1
Você também pode usar field = VALUES (field) na atualização duplicada como na resposta em stackoverflow.com/questions/16935896/…
Erik Melkersson