Insertar en una tabla MySQL o actualizar si existe

875

Quiero agregar una fila a una tabla de base de datos, pero si existe una fila con la misma clave única, quiero actualizar la fila.

Por ejemplo:

insert into table (id, name, age) values(1, "A", 19)

Digamos que la clave única es id, y en mi Base de datos , hay una fila con id = 1. En ese caso, quiero actualizar esa fila con estos valores. Normalmente esto da un error.
Si lo uso insert IGNORE, ignoraré el error, pero aún así no se actualizará.

Keshan
fuente
66
SQL necesita una sintaxis oficial para este caso de uso que no fuerce la duplicación de valores en la sintaxis y conserve la clave primaria.
Pete Alvin el
Para obtener la identificación influenciada, consulte MySQL EN LA LLAVE DUPLICADA: ¿última inserción de identificación?
Kris Roofe
Advertencia: a partir de la versión 5.7, este enfoque no admite directamente la cláusula WHERE como parte de la operación INSERT / UPDATE. Además, una ACTUALIZACIÓN realmente cuenta como dos operaciones separadas (ELIMINAR e INSERTAR) ... en caso de que sea importante para fines de auditoría. (Learnbit)
dreftymac

Respuestas:

1600

Utilizar INSERT ... ON DUPLICATE KEY UPDATE

CONSULTA:

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name="A", age=19
Donnie
fuente
86
+1 Por lo que he encontrado, este método es menos problemático para las teclas de incremento automático y otras colisiones de teclas únicas que REPLACE INTO, y es más eficiente.
Andrew Ensley
46
Sé que todos ustedes aluden a esto, pero quiero ser explícito para los demás. Si la ID que inserta NO ES LA CLAVE PRIMARIA o ÚNICA, entonces esto no funcionará. Inicialmente, esto no funcionó para mí porque mi ID no era única.
Keven
77
Me pregunto por qué se affected row countproduce la 2actualización exitosa (en clave duplicada) de una sola fila. ¿Alguien más tuvo este resultado? (Los datos se actualizan correctamente: lo que significa que solo se actualiza 1 fila)
Dimitry K
15
Esto es un poco tarde, pero de todos modos: se indica en el manual que las actualizaciones ON DUPLICATE KEY UPDATEaumentan las filas afectadas en 2. Informa 0 si nada se actualiza realmente (igual que el normal UPDATE).
Vatev
61
También tenga en cuenta que puede usar VALUES (nombre) para hacer referencia al valor que intenta insertar, por ejemplo, INSERT INTO en la tabla (id, nombre, edad) VALUES (1, "A", 19) EN ACTUALIZACIÓN DE CLAVE DUPLICADA name = VALUES (nombre) , age = VALUES (age)
Curious Sam
246

Echa un vistazo a REPLACE

http://dev.mysql.com/doc/refman/5.0/en/replace.html

REPLACE into table (id, name, age) values(1, "A", 19)
Martin Schapendonk
fuente
11
@Piontek Debido a que este es más corto y más fácil de entender y nadie explicó por qué "insertar en duplicado" es mejor.
Mr_Chimp
77
cambia las ID del registro y, por lo tanto, puede destruir referencias extranjeras.
Boh
102
El otro problema con REPLACE INTO es que debe especificar valores para TODOS los campos ... de lo contrario, los campos se perderán o se reemplazarán con los valores predeterminados. REPLACE INTO esencialmente elimina la fila si existe e inserta la nueva fila. En el ejemplo, si hizo 'REEMPLAZAR EN los valores de la tabla (id, edad) (1, 19), el campo de nombre quedaría nulo.
Dale
33
Esto es realmente BORRAR toda la fila y realizar una nueva INSERTAR.
mjb
8
@mjb Por lo tanto, debe tener privilegios DELETE, que es mejor no tener si no los necesita. El usuario de la base de datos de mi entorno solo tiene permisos INSERT y UPDATE, por lo que REPLACE no funcionará.
ndm13
54

Cuando use la inserción por lotes, use la siguiente sintaxis:

INSERT INTO TABLE (id, name, age) VALUES (1, "A", 19), (2, "B", 17), (3, "C", 22)
ON DUPLICATE KEY UPDATE
    name = VALUES (name),
    ...
Fabiano Souza
fuente
Muy útil si quieres manipular el nuevo valor
Hambre
Si VALUES(name)no funciona, puedes intentarloname = 'name_value',...;
Son Pham
26

Probar esto:

INSERT INTO table (id, name, age) VALUES (1, 'A', 19) ON DUPLICATE KEY UPDATE id = id + 1;

Espero que esto ayude.

Luis Reyes
fuente
66
en realidad no necesito agregar los nuevos valores a otra fila con una nueva ID, sino que quiero reemplazar los valores existentes de id = 1 con estos valores. (Según tengo entendido, esto aumenta la identificación y agrega los datos)
Keshan
49
No creo que quiera aumentar la identificación por uno en duplicados.
Donnie
77
"transgredir" no es la palabra que está buscando :) Por desgracia, ahora que he visto "transgredir", ya no puedo visualizar la palabra real ..
mwfearnley
1
¿Estaba buscando "travesías" o "cubiertas"?
Chris Dev
44
@mwfearnley La palabra que intentabas visualizar es "trasciende". Solo tomó un año y medio :-)
Michael Krebs
20

Prueba esto:

INSERT INTO table (id,name,age) VALUES('1','Mohammad','21') ON DUPLICATE KEY UPDATE name='Mohammad',age='21'

Nota:
Aquí, si id es la clave principal, luego de la primera inserción, id='1'cada vez que intente insertar id='1'actualizará el nombre y la edad, y la edad del nombre anterior cambiará.

Rasel
fuente
Quiero trabajar sin usar id . ¿Has probado sin clave principal?
ersks
@ersks ven la pregunta. usuario preguntó cuándo hay una clave única
Rasel
Lo entendí, pero estoy tratando de resolver mi problema en el que se conocen estos únicos valores. Entonces, en tal situación, escribí el comentario anterior esperando la solución correcta.
ersks
15
INSERT IGNORE INTO table (id, name, age) VALUES (1, "A", 19);

INSERT INTO TABLE (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE NAME = "A", AGE = 19;

REPLACE INTO table (id, name, age) VALUES(1, "A", 19);

Todas estas soluciones funcionarán con respecto a su pregunta.

Si desea conocer los detalles de estas declaraciones, visite este enlace.

Dilraj Singh
fuente
REPLACEno está documentado en el documento vinculado.
Ray Baxter
consultas sql llenas de errores tipográficos, sus ejemplos no funcionarán. Es INSERTAR EN LA TABLA (no EN LA TABLA) y EN LA ACTUALIZACIÓN DE LA LLAVE DUPLICADA (no EN EL JUEGO DE ACTUALIZACIÓN DUPLICADA). No estoy seguro de quién está votando esto
Robert Sinclair
1
Perdón por el error tipográfico. Gracias por corregirme
Dilraj Singh
11

Cuando se usa SQLite:

REPLACE into table (id, name, age) values(1, "A", 19)

Siempre que esa idsea ​​la clave principal. O bien, simplemente inserta otra fila. Ver INSERTAR (SQLite).

DawnSong
fuente
Lo que replace intohace es exactamente "insertar o actualizar cuando exista". @Owl
DawnSong
+1 (1 de 3) Encontré que esto funcionaba para mi situación: necesitaba reemplazar una fila existente con una clave única o, si no, agregar la fila. La más simple de las soluciones aquí.
therobyouknow
(2 de 3) Mi consulta:CREATE TRIGGER worklog_update AFTER INSERT ON worklog FOR EACH ROW REPLACE INTO support_time_monthly_hours ( ProjectID, monthTotalTime, Year, Month ) SELECT jiraissue.PROJECT, SUM(worklog.timeworked), YEAR(CURRENT_DATE()), MONTH(CURRENT_DATE()) FROM worklog, jiraissue WHERE worklog.issueid = jiraissue.ID AND jiraissue.PROJECT = (SELECT PROJECT FROM jiraissue WHERE NEW.issueid = jiraissue.ID ) AND worklog.startdate BETWEEN DATE_FORMAT(NOW() ,'%Y-%m-01 00:00:00') AND NOW();
therobyouknow
(3 de 3) Preguntas / respuestas relacionadas stackoverflow.com/questions/41767517/…
therobyouknow
2
El problema con esto en mysql es que reemplazar eliminará otros valores en caso de que no se proporcionen. Sin embargo, la solución @ fabiano-souza es más apropiada
Quamber Ali
11

Solo porque estaba buscando esta solución, pero para actualizar desde otra tabla idénticamente estructurada (en mi caso, prueba de sitio web DB para vivir DB):

INSERT  live-db.table1
SELECT  *
FROM    test-db.table1 t
ON DUPLICATE KEY UPDATE
        ColToUpdate1 = t.ColToUpdate1,
        ColToUpdate2 = t.ColToUpdate2,
        ...

Como se mencionó en otra parte, solo las columnas que desea actualizar deben incluirse después ON DUPLICATE KEY UPDATE.

No es necesario enumerar las columnas en INSERTo SELECT, aunque estoy de acuerdo en que probablemente sea una mejor práctica.

SteveCinq
fuente
4

En caso de que desee crear un non-primarycampo como criterio / condición ON DUPLICATE, puede hacer una UNIQUE INDEXclave en esa tabla para activar el DUPLICATE.

ALTER TABLE `table` ADD UNIQUE `unique_index`(`name`);

Y en caso de que desee combinar dos campos para que sea único en la tabla, puede lograr esto agregando más en el último parámetro.

ALTER TABLE `table` ADD UNIQUE `unique_index`(`name`, `age`);

Tenga en cuenta que solo asegúrese de eliminar primero todos los datos que tengan el mismo valor namey en agetodas las demás filas.

DELETE table FROM table AS a, table AS b WHERE a.id < b.id 
AND a.name <=> b.name AND a.age <=> b.age;

Después de eso, debería desencadenar el ON DUPLICATEevento.

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name = VALUES(name), age = VALUES(age)
Rico
fuente
2

En mi caso, creé las consultas a continuación, pero en la primera consulta si id1 ya existe y la edad ya está allí, después de eso, si crea la primera consulta sin, ageel valor de ageno será ninguno

REPLACE into table SET `id` = 1, `name` = 'A', `age` = 19

para evitar el problema anterior, cree una consulta como la siguiente

INSERT INTO table SET `id` = '1', `name` = 'A', `age` = 19 ON DUPLICATE KEY UPDATE `id` = "1", `name` = "A",`age` = 19

que te ayude ...

Renote Gotecha
fuente
2
¿Alguien sabe por qué debemos asignar los valores dos veces? ¿Por qué MySQL no nos permite finalizar la consulta en ON DUPLICATE KEY UPDATE sin duplicar todas las declaraciones de asignación? Algunas tablas de la base de datos tienen muchas columnas, y esto parece redundante / gratuito. Entiendo por qué tenemos la opción de tareas alternativas, pero ¿por qué no tener la opción de omitirlas también? Solo curiosidad si alguien lo sabe.
Blue Water
2

En el caso, desea mantener el campo antiguo (por ejemplo: nombre). La consulta será:

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name=name, age=19;
Xman Classical
fuente