153 votos

¿Cómo puedo actualizar si existe, insertar si no (también conocido como "upsert" o "merge") en MySQL?

¿Existe una manera fácil de INSERT una fila cuando no existe, o para UPDATE si existe, utilizando una consulta de MySQL?

193voto

chaos Puntos 69029

Utilice INSERT ... ON DUPLICATE KEY UPDATE . Por ejemplo:

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

0 votos

Vaya, eso es impresionante. ¿Tienen otros RDMS esta característica?

11 votos

Sí, creo que el equivalente de Sql Server se llama MERGE . En general, el concepto se suele denominar "UPSERT" .

0 votos

Pero esto no funciona cuando no hay prim.key presente. Mi tabla tiene el siguiente aspecto: geb | topic | visited Quiero insertar INSERT INTO table SET visited=NOW(), geb=1, topic=1 Pero si ya hay una combinación de geb=1 && topic=1 entonces debería actualizar la fila en lugar de insertar una nueva.

6voto

Armadillo Jim Puntos 241

Sé que esta es una pregunta antigua, pero el Google me condujo aquí recientemente, así que imagino que otros también vienen aquí.

@chaos tiene razón: existe el INSERT ... ON DUPLICATE KEY UPDATE sintaxis.

Sin embargo, la pregunta original se refería a MySQL específicamente, y en MySQL existe el REPLACE INTO ... sintaxis. En mi opinión, este comando es más fácil y sencillo de utilizar para los upserts. Del manual:

REPLACE funciona exactamente igual que INSERT, salvo que si una fila antigua de la tabla tiene el mismo valor que una fila nueva para una CLAVE PRIMARIA o un índice ÚNICO, la fila antigua se elimina antes de insertar la fila nueva.

Tenga en cuenta que esto no es un SQL estándar. Un ejemplo del 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)

Editar: Sólo un aviso de que REPLACE INTO no es como UPDATE . Como dice el manual, REPLACE borra la fila si existe, y luego inserta una nueva. (Obsérvese el gracioso "2 filas afectadas" en el ejemplo anterior). Es decir, sustituirá los valores de todo columnas de un registro existente (y no simplemente actualizar algunos columnas). El comportamiento de la función REPLACE INTO es muy parecido al de Sqlite INSERT OR REPLACE INTO . Ver esta pregunta para algunas soluciones si sólo quiere actualizar algunas columnas (y no todas) si el registro ya existe.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X