2009-04-22 13 views
104

Tengo la siguiente consulta:MySQL ON DUPLICATE KEY - ¿la última identificación de inserción?

INSERT INTO table (a) VALUES (0) 
    ON DUPLICATE KEY UPDATE a=1 

Quiero que el ID de cualquiera de la inserción o la actualización. Por lo general, ejecuto una segunda consulta para obtener esto, ya que creo que insert_id() solo devuelve el ID "insertado" y no el ID actualizado.

¿Hay alguna manera de INSERTAR/ACTUALIZAR y recuperar el ID de la fila sin ejecutar dos consultas?

+3

En lugar de suponer, ¿por qué no lo prueba usted mismo? El SQL en la edición anterior funciona, y mediante mis pruebas es más rápido que detectar un error de inserción, usando INSERT IGNORE, o seleccionando para ver si hay un duplicado primero. –

+1

ADVERTENCIA: la solución propuesta funciona, pero el valor de auto_increment continúa incrementándose, incluso si no hay ninguna inserción. Si la clave duplicada ocurre con frecuencia, es posible que desee ejecutar 'alter table tablename AUTO_INCREMENT = 0;' después de la consulta anterior, para evitar grandes diferencias en los valores de su id. –

Respuesta

125

Marque esta página impresa: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
en la parte inferior de la página se explica cómo se puede hacer LAST_INSERT_ID significativo para actualizaciones pasando una expresión a th en la función MySQL

A partir del ejemplo de documentación de MySQL:

Si una tabla contiene una columna AUTO_INCREMENT y INSERT ... ACTUALIZACIÓN inserta una fila, la LAST_INSERT_ID() devuelve el valor AUTO_INCREMENT. Si la instrucción actualiza una fila en su lugar, LAST_INSERT_ID() no tiene sentido. Sin embargo, puede solucionar esto utilizando LAST_INSERT_ID (expr). Supongamos que id es la columna AUTO_INCREMENT. Para hacer LAST_INSERT_ID() significativo para las actualizaciones, las filas de inserción de la siguiente manera:

INSERT INTO table (a,b,c) VALUES (1,2,3) 
    ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3; 
+2

De alguna manera me lo perdí al mirar esa página. Así que la porción de actualización aparece como: UPDATE id = LAST_INSERT_ID (id) Y eso funciona genial. ¡Gracias! – thekevinscott

+1

¡Me alegro de poder ayudar! – fredrik

+6

Se dice que la función php mysql_insert_id() devuelve el valor correcto en ambos casos: http://www.php.net/manual/en/function.mysql-insert-id.php#59718. – jayarjo

2

Puede mirar REEMPLAZAR, que es esencialmente un eliminar/insertar si el registro existe. Pero esto cambiaría el campo de incremento automático, si está presente, lo que podría romper las relaciones con otros datos.

+1

Ah, sí, estoy buscando algo que no elimine las identificaciones anteriores – thekevinscott

+0

Esto también puede ser peligroso porque también puede causar la eliminación de otros datos relacionados (por restricciones). – Serge

0

Vale la pena señalar, y esto podría ser obvia (pero lo diré de todos modos para mayor claridad aquí), que reemplazan se lleve el aire la fila de coincidencia existente antes de insertar sus nuevos datos. ON DUPLICATE KEY UPDATE solo actualizará las columnas que especifique y conservará la fila.

Desde el manual:

REEMPLAZAR funciona exactamente igual que INSERT, excepto que si un viejo fila de la tabla tiene el mismo valor que una nueva fila para una PRIMARY KEY o un índice único, La fila anterior se elimina antes de que se inserte la nueva fila .

25

Para ser exactos, si este es el la consulta original:

INSERT INTO table (a) VALUES (0) 
ON DUPLICATE KEY UPDATE a=1 

y 'id' es la clave principal incremento automático que esto sería la solución de trabajo:

INSERT INTO table (a) VALUES (0) 
    ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), a=1 

Es todo aquí: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

Si una tabla contiene una AUTO_INCREMENT columna e INSERTAR ... ACTUALIZAR inserta una fila, la función LAST_INSERT_ID() devuelve el valor AUTO_INCREMENT. Si la instrucción actualiza una fila en su lugar, LAST_INSERT_ID() no tiene sentido. Sin embargo, puede evitar este utilizando LAST_INSERT_ID (expr). Supongamos que id es la columna AUTO_INCREMENT .

+3

Sí, vea la respuesta aceptada por el mismo mensaje que usted dijo. No es necesario revivir publicaciones de 3 años. Gracias por tu esfuerzo de todos modos. – fancyPants

+1

@tombom la única razón por la que publiqué esta respuesta es porque la respuesta aceptada no es correcta; no funcionará si no hay nada que actualizar. –

+0

+1 aunque creo que la respuesta aceptada menciona que :) – fancyPants

0

Las soluciones existentes funcionan si usa autoincrement. Tengo una situación en la que el usuario puede definir un prefijo y debe reiniciar la secuencia en 3000. Debido a este prefijo variado, no puedo usar autoincrement, lo que hace que last_insert_id esté vacío para las inserciones. Lo resuelto con lo siguiente:

INSERT INTO seq_table (prefix, id) VALUES ('$user_prefix', LAST_INSERT_ID(3000)) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id + 1); 
SELECT LAST_INSERT_ID(); 

Si existe el prefijo, se incrementará y poblar LAST_INSERT_ID. Si el prefijo no existe, insertará el prefijo con el valor 3000 y rellenará last_insert_id con 3000.

Cuestiones relacionadas