MySQL EN CLAVE DUPLICADA - último id de inserción?


Tengo la siguiente pregunta:

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

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

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

Author: Ken Wayne VanderLinde, 2009-04-22

6 answers

Echa un vistazo a esta página: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
En la parte inferior de la página explican cómo puede hacer que LAST_INSERT_ID sea significativo para las actualizaciones pasando una expresión a esa función MySQL.

Del ejemplo de documentación de MySQL:

Si una tabla contiene una columna AUTO_INCREMENT e INSERT ... UPDATE 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 es significativo. Sin embargo, puede solucionar esto usando LAST_INSERT_ID(expr). Supongamos que id es la columna AUTO_INCREMENT. Para hacer que LAST_INSERT_ID() tenga sentido para las actualizaciones, inserte filas 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;
 136
Author: fredrik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-05 22:39:44

Para ser exactos, si esta es la consulta original:

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

Y 'id' es la clave primaria de auto-incremento que esta sería la solución de trabajo:

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

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

Si una tabla contiene una columna AUTO_INCREMENT e INSERT ... ACTUALIZAR inserta una fila, la función LAST_INSERT_ID () devuelve Valor AUTO_INCREMENT. Si la instrucción actualiza una fila en su lugar, LAST_INSERT_ID() no es significativo. Sin embargo, usted puede trabajar alrededor de esto usando LAST_INSERT_ID (expr). Supongamos que id es el AUTO_INCREMENT columna.

 28
Author: Aleksandar Popovic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-12 09:06:51

Puede ver REEMPLAZAR, que es esencialmente un delete/insert 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.

 2
Author: Brent Baisley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-22 18:40:41

No se cual es tu versión de MySQL pero con InnoDB, hubo un bug con autoinc

Error en 5.1.20 y corregido en 5.1.23 http://bugs.mysql.com/bug.php?id=27405

Error en 5.1.31 y corregido en 5.1.33 http://bugs.mysql.com/bug.php?id=42714

 2
Author: Hugues Van Landeghem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-22 21:02:49

Vale la pena señalar, y esto podría ser obvio (pero lo diré de todos modos para mayor claridad aquí), que REEMPLAZAR eliminará la fila coincidente existente antes de insertar sus nuevos datos. EN LA ACTUALIZACIÓN DE CLAVE DUPLICADA solo actualizará las columnas que especifique y conservará la fila.

Del manual :

REEMPLAZAR funciona exactamente como INSERTAR, excepto que si una vieja fila en la tabla tiene el mismo valor que una nueva fila para CLAVE PRIMARIA o un índice ÚNICO, el antiguo la fila es eliminado antes de que la nueva fila sea insertar.

 0
Author: Greg K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-05 15:03:58

Las soluciones existentes funcionan si utiliza 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 inserciones. Lo resolví 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 el prefijo existe, lo incrementará y rellenará last_insert_id. Si el prefijo no existe, insertará el prefijo con el valor 3000 y rellenará last_insert_id con 3000.

 0
Author: Aaron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-02 00:24:02