Como faço para atualizar se existe, insira se não (AKA “upsert” ou “merge”) no MySQL?

Existe uma maneira fácil de INSERT uma linha quando ela não existe, ou de UPDATE se ela existe, usando uma consulta MySQL?

   

Sim, INSERT ... ON DUPLICATE KEY UPDATE . Por exemplo:

 INSERT INTO `usage` (`thing_id`, `times_used`, `first_time_used`) VALUES (4815162342, 1, NOW()) ON DUPLICATE KEY UPDATE `times_used` = `times_used` + 1 

Eu sei que essa é uma pergunta antiga, mas o Google me levou até aqui recentemente, então imagino que os outros também estejam aqui.

@chaos está correto: há a syntax INSERT ... ON DUPLICATE KEY UPDATE .

No entanto, a pergunta original perguntada sobre o MySQL especificamente, e no MySQL, há a syntax REPLACE INTO ... IMHO, este comando é mais fácil e mais simples de usar para upserts. Do manual:

REPLACE funciona exatamente como INSERT, exceto que se uma linha antiga na tabela tiver o mesmo valor de uma nova linha para uma PRIMARY KEY ou um índice UNIQUE, a linha antiga será excluída antes que a nova linha seja inserida.

Observe que isso não é SQL padrão. Um exemplo do manual:

 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) 

Edit: Apenas um aviso justo que REPLACE INTO não é como UPDATE . Como diz o manual, REPLACE exclui a linha, se existir, e insere uma nova. (Note o engraçado “2 linhas afetadas” no exemplo acima). Ou seja, ele replaceá os valores de todas as colunas de um registro existente (e não apenas atualizará algumas colunas). O comportamento do REPLACE INTO do MySQL é muito parecido com o de Sqlite INSERT OR REPLACE INTO . Veja esta pergunta para algumas soluções alternativas se você quiser apenas atualizar algumas colunas (e não todas as colunas) se o registro já existir.