¿Cómo obtener la identificación de la última fila actualizada en MySQL?

134

¿Cómo obtengo el ID de la última fila actualizada en MySQL usando PHP?

Avinash
fuente
2
mysqli_insert_id ($ link) devolverá exactamente la identificación de la última fila actualizada. Estoy usando esta función en mis proyectos con el mismo propósito. Puede usarlo tanto en consultas síncronas como asíncronas. Simplemente inserte $ lastupdated_row_id = mysqli_insert_id ($ link) en su código y funcionará para usted.
Naeem Ul Wahhab
1
¿No conoces el ID de la fila si actualizas? Supongo que debe haber algunos casos en los que no.
JCharette
1
Probablemente use una cláusula where en su consulta de actualización, ¿por qué no puede usar la misma cláusula where en la consulta de selección? UPDATE foo WHERE bar = 1; SELECT id FROM foo WHERE bar = 1?
Salman A

Respuestas:

236

He encontrado una respuesta a este problema :)

SET @update_id := 0;
UPDATE some_table SET column_name = 'value', id = (SELECT @update_id := id)
WHERE some_other_column = 'blah' LIMIT 1; 
SELECT @update_id;

EDITAR por aefxx

Esta técnica se puede ampliar aún más para recuperar el ID de cada fila afectada por una declaración de actualización:

SET @uids := null;
UPDATE footable
   SET foo = 'bar'
 WHERE fooid > 5
   AND ( SELECT @uids := CONCAT_WS(',', fooid, @uids) );
SELECT @uids;

Esto devolverá una cadena con todos los ID concatenados por una coma.

Pomyk
fuente
66
No puedo creer que esto haya tenido 0 votos a favor, y el comentario mysql_insert_id () que no es lo que el OP estaba pidiendo en absoluto tiene 13. ¡Gracias Pomyk, un truco inteligente!
Jaka Jančar
1
Como tiene una WHEREcláusula, simplemente puede usar la misma WHEREcláusula en su próxima consultaSELECT id FROM footable WHERE fooid > 5
Salman A
44
Quizás todos entiendan esto, pero si usas mysql_query (); tienes que dividir esto en tres llamadas diferentes, pero funcionará.
rael_kid
8
No hay necesidad de usar variables. LAST_INSERT_ID()puede aceptar un argumento que establecerá el valor devuelto por la próxima llamada a LAST_INSERT_ID(). Por ejemplo: UPDATE table SET id=LAST_INSERT_ID(id), row='value' WHERE other_row='blah';. Ahora, SELECT LAST_INSERT_ID();devolverá la identificación actualizada. Vea la respuesta de newtover para más detalles.
Joel
3
@SteveChilds Acabo de comentar la pregunta de newtover y quiero agregar una solución al problema que estás describiendo. Este conjuntos LAST_INSERT_ID a 0 si no hay nada para actualizar: UPDATE lastinsertid_test SET row='value' WHERE row='asd' AND LAST_INSERT_ID(id) OR LAST_INSERT_ID(0);. Sin embargo, no recupera múltiples identificadores, por lo que esta respuesta es superior.
martinczerwi
33

Hm, me sorprende que entre las respuestas no veo la solución más fácil.

Supongamos que item_ides una columna de identidad entera en la itemstabla y actualiza las filas con la siguiente instrucción:

UPDATE items
SET qwe = 'qwe'
WHERE asd = 'asd';

Luego, para conocer la última fila afectada justo después de la declaración, debe actualizar ligeramente la declaración en lo siguiente:

UPDATE items
SET qwe = 'qwe',
    item_id=LAST_INSERT_ID(item_id)
WHERE asd = 'asd';
SELECT LAST_INSERT_ID();

Si necesita actualizar solo una fila realmente cambiada, necesitaría agregar una actualización condicional del item_id a través de LAST_INSERT_ID comprobando si los datos van a cambiar en la fila.

nuevo
fuente
3
Es seguro para múltiples usuarios porque varios clientes pueden emitir la instrucción UPDATE y obtener su propio valor de secuencia con la instrucción SELECT (o mysql_insert_id ()), sin afectar ni verse afectados por otros clientes que generan sus propios valores de secuencia. Según dev.mysql.com/doc/refman/5.0/en/...
brutuscat
1
¿Esto no establecerá el item_id en el último registro insertado?
arleslie
2
@arleslie, si sigues el enlace a los documentos en el comentario anterior de brutuscat, verás que no lo hará. Este es el comportamiento previsto exactamente para el caso.
newtover
1
Esta es de hecho la respuesta correcta. Aunque la consulta parece un poco contra-intuitiva, esto es exactamente lo que dice hacer la documentación de MySQL.
Timothy Zorn
3
En caso de que la consulta lo confunda, ya que LAST_INSERT_ID (expr) devolverá el valor de expr para la llamada ACTUALIZAR, también puede usarlo así:UPDATE items SET qwe = 'qwe' WHERE asd = 'asd' AND LAST_INSERT_ID(item_id); SELECT LAST_INSERT_ID();
martinczerwi
14

Esto es oficialmente simple pero notablemente contra-intuitivo. Si estas haciendo:

update users set status = 'processing' where status = 'pending'
limit 1

Cámbialo a esto:

update users set status = 'processing' where status = 'pending'
and last_insert_id(user_id) 
limit 1

La adición de last_insert_id(user_id)en la wherecláusula le dice a MySQL que establezca su variable interna en la ID de la fila encontrada. Cuando pasas un valor alast_insert_id(expr) como este, termina devolviendo ese valor, que en el caso de ID como este siempre es un entero positivo y, por lo tanto, siempre se evalúa como verdadero, sin interferir nunca con la cláusula where. Esto solo funciona si se encontró alguna fila, así que recuerde verificar las filas afectadas. Luego puede obtener la identificación de varias maneras.

MySQL last_insert_id()

Puede generar secuencias sin llamar a LAST_INSERT_ID (), pero la utilidad de usar la función de esta manera es que el valor de ID se mantiene en el servidor como el último valor generado automáticamente. Es seguro para múltiples usuarios porque varios clientes pueden emitir la instrucción UPDATE y obtener su propio valor de secuencia con la instrucción SELECT (o mysql_insert_id ()), sin afectar ni verse afectados por otros clientes que generan sus propios valores de secuencia.

MySQL mysql_insert_id()

Devuelve el valor generado para una columna AUTO_INCREMENT por la instrucción INSERT o UPDATE anterior. Utilice esta función después de haber realizado una instrucción INSERT en una tabla que contiene un campo AUTO_INCREMENT, o haya utilizado INSERT o UPDATE para establecer un valor de columna con LAST_INSERT_ID (expr).

La razón de las diferencias entre LAST_INSERT_ID () y mysql_insert_id () es que LAST_INSERT_ID () se hace fácil de usar en scripts mientras mysql_insert_id () intenta proporcionar información más exacta sobre lo que sucede en la columna AUTO_INCREMENT.

PHP mysqli_insert_id()

Realizar una instrucción INSERT o UPDATE utilizando la función LAST_INSERT_ID () también modificará el valor devuelto por la función mysqli_insert_id ().

Poniendolo todo junto:

$affected_rows = DB::getAffectedRows("
    update users set status = 'processing' 
    where status = 'pending' and last_insert_id(user_id) 
    limit 1"
);
if ($affected_rows) {
    $user_id = DB::getInsertId();
}

(Para su información, la clase DB está aquí ).

Vladimir Kornea
fuente
Importante tener en cuenta: esto es seguro para múltiples conexiones, el valor persistente para last_insert_id o mysql_insert_id (y tal vez mysqli_insert_id, no lo comprobé), son por conexión. ¡Increíble!
Ryan S
10

Este es el mismo método que la respuesta de Salman A, pero aquí está el código que realmente necesita para hacerlo.

Primero, edite su tabla para que realice un seguimiento automático de cada vez que se modifique una fila. Elimine la última línea si solo desea saber cuándo se insertó inicialmente una fila.

ALTER TABLE mytable
ADD lastmodified TIMESTAMP 
    DEFAULT CURRENT_TIMESTAMP 
    ON UPDATE CURRENT_TIMESTAMP;

Luego, para averiguar la última fila actualizada, puede usar este código.

SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1;

Todo este código se ha eliminado de MySQL vs PostgreSQL: Agregar una columna de 'Última hora modificada' a una tabla y Manual de MySQL: Ordenar filas . Lo acabo de armar.

Chad von Nau
fuente
77
Este método puede obtener la identificación incorrecta si la segunda inserción se realiza justo después de la primera consulta de inserción. Sin embargo, si usamos 'WHERE' con esta consulta, es decir, SELECCIONE ID de mytable ORDER BY lastmodified DESC LIMIT 1 WHERE (algunas condiciones relacionadas con la última consulta de inserción), entonces puede evitar obtener la identificación incorrecta.
Naeem Ul Wahhab
1
@ TheNoble-Coder Esto es cierto. Si necesita que la identificación de una fila afecte a una consulta de actualización en particular, utilice la técnica de Pomyk. Esta técnica aquí es más útil cuando se usa de forma asíncrona, donde solo desea la última actualización absoluta.
Chad von Nau
5

Consulta :

$sqlQuery = "UPDATE 
            update_table 
        SET 
            set_name = 'value' 
        WHERE 
            where_name = 'name'
        LIMIT 1;";

Función PHP:

function updateAndGetId($sqlQuery)
{
    mysql_query(str_replace("SET", "SET id = LAST_INSERT_ID(id),", $sqlQuery));
    return mysql_insert_id();
}

Es trabajo para mí;)

GigolNet Guigolachvili
fuente
me gustó lo mismo pero funcionó de manera diferente ref: forums.mysql.com/read.php?52,390616,390619
3

Más allá de la respuesta aceptada arriba
para aquellos que se preguntaban sobre :=&=

Diferencia significativa entre :=y =, y es que :=funciona como un operador de asignación variable en todas partes, mientras= solo funciona de esa manera en las instrucciones SET, y es un operador de comparación en cualquier otro lugar.

Por SELECT @var = 1 + 1;lo tanto , dejará @varsin cambios y devolverá un valor booleano (1 o 0 según el valor actual de @var), mientras SELECT @var := 1 + 1;que cambiará @vara 2 y devolverá 2 . [Fuente]

Anon30
fuente
Hey gracias. Lo que quieren decir es en realidad más interesante que la respuesta aceptada anteriormente.
Verde
2

Oye, solo necesitaba un truco: lo resolví de una manera diferente, tal vez funcione para ti. Tenga en cuenta que esta no es una solución escalable y será muy mala para grandes conjuntos de datos.

Divida su consulta en dos partes:

primero, seleccione los identificadores de las filas que desea actualizar y guárdelos en una tabla temporal.

segundo, realice la actualización original con la condición en la declaración de actualización cambiada a where id in temp_table.

Y para garantizar la concurrencia, debe bloquear la tabla antes de estos dos pasos y luego liberar el bloqueo al final.

Nuevamente, esto funciona para mí, para una consulta que termina con limit 1, por lo que ni siquiera uso una tabla temporal, sino simplemente una variable para almacenar el resultado de la primeraselect .

Prefiero este método porque sé que siempre actualizaré solo una fila, y el código es sencillo.

olamundo
fuente
2
SET @uids := "";
UPDATE myf___ingtable
   SET id = id
   WHERE id < 5
  AND ( SELECT @uids := CONCAT_WS(',', CAST(id AS CHAR CHARACTER SET utf8), @uids) );
SELECT @uids;

Tuve que CASTAR la identificación (no sé por qué) ... o no puedo obtener el contenido de @uids (fue una gota) Por cierto, ¡muchas gracias por la respuesta de Pomyk!

Gromish
fuente
2

El ID de la última fila actualizada es el mismo ID que usa en 'updateQuery' para encontrar y actualizar esa fila. Por lo tanto, solo guarde (llame) esa ID de la forma que desee.

last_insert_id()depende de AUTO_INCREMENT, pero la última ID actualizada no.

Driada
fuente
3
¿Qué sucede si la actualización no se realiza desde una identificación, sino desde otro conjunto de atributos?
Sebas
2

Mi solución es, primero decidir el "id" (@uids) con el comando select y luego actualizar este id con @uids.

SET @uids := (SELECT id FROM table WHERE some = 0 LIMIT 1);
UPDATE table SET col = 1 WHERE id = @uids;SELECT @uids;

Funcionó en mi proyecto.

Ahmet Uğur
fuente
1

Si solo está haciendo inserciones y desea una de la misma sesión, hágalo según la respuesta de peirix. Si está realizando modificaciones, deberá modificar el esquema de su base de datos para almacenar qué entrada se actualizó más recientemente.

Si desea la identificación de la última modificación, que puede haber sido de una sesión diferente (es decir, no la que acaba de hacer el código PHP que se está ejecutando actualmente, sino una respuesta a una solicitud diferente), puede agregar un Columna TIMESTAMP en su tabla llamada last_modified (consulte http://dev.mysql.com/doc/refman/5.1/en/datetime.html para obtener información) y luego, cuando actualice, configure last_modified = CURRENT_TIME.

Una vez configurado esto, puede usar una consulta como: SELECCIONAR ID de la tabla ORDER BY last_modified DESC LIMIT 1; para obtener la fila modificada más recientemente.

a1kmm
fuente
-9

No es necesario tanto código Mysql. En PHP, la consulta debería verse así:

$updateQuery = mysql_query("UPDATE table_name SET row='value' WHERE id='$id'") or die ('Error');
$lastUpdatedId = mysql_insert_id();
Driada
fuente