Come ottenere l'ID dell'ultima riga aggiornata in MySQL?


134

Come posso ottenere l'ID dell'ultima riga aggiornata in MySQL usando PHP?


2
mysqli_insert_id ($ link) restituirà esattamente l'id dell'ultima riga aggiornata. Sto usando questa funzione nei miei progetti per lo stesso scopo. Puoi usarlo sia in query sincrone che asincrone. Inserisci $ lastupdated_row_id = mysqli_insert_id ($ link) nel tuo codice e funzionerà per te.
Naeem Ul Wahhab,

1
Non conosci già l'ID della riga se aggiorni? Immagino che ci debbano essere alcuni casi in cui non lo fai.
JCharette,

1
Probabilmente usi una clausola where nella tua query di aggiornamento, perché non puoi usare la stessa clausola where nella query select? UPDATE foo WHERE bar = 1; SELECT id FROM foo WHERE bar = 1?
Salman A

Risposte:


236

Ho trovato una risposta a questo 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;

EDIT di aefxx

Questa tecnica può essere ulteriormente espansa per recuperare l'ID di ogni riga interessata da un'istruzione di aggiornamento:

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

Ciò restituirà una stringa con tutti gli ID concatenati da una virgola.


6
Non riesco a credere che questo abbia avuto 0 voti positivi e il commento mysql_insert_id () che non è affatto quello che l'OP stava chiedendo ha 13. Grazie Pomyk, un trucco intelligente!
Jaka Jančar,

1
Dato che hai una WHEREclausola puoi semplicemente usare la stessa WHEREclausola nella tua prossima querySELECT id FROM footable WHERE fooid > 5
Salman A

4
Forse tutti lo capiscono, ma se usi mysql_query (); devi dividerlo in tre diverse chiamate, ma funzionerà.
rael_kid,

8
Non è necessario nemmeno utilizzare le variabili. LAST_INSERT_ID()può accettare un argomento che imposterà il valore restituito dalla chiamata successiva a LAST_INSERT_ID(). Ad esempio: UPDATE table SET id=LAST_INSERT_ID(id), row='value' WHERE other_row='blah';. Ora SELECT LAST_INSERT_ID();restituirà l'id aggiornato. Vedi la risposta di newtover per maggiori dettagli.
Gioele,

3
@SteveChilds Stavo solo commentando la domanda di Newtover e voglio aggiungere una soluzione alla trappola che stai descrivendo. Questo imposta LAST_INSERT_ID a 0 se non c'è niente da UPDATE: UPDATE lastinsertid_test SET row='value' WHERE row='asd' AND LAST_INSERT_ID(id) OR LAST_INSERT_ID(0);. Tuttavia, non recupera più ID, quindi questa risposta è superiore.
martinczerwi,

33

Hm, sono sorpreso che tra le risposte non vedo la soluzione più semplice.

Supponiamo che item_idsia una colonna di identità intera nella itemstabella e aggiorni le righe con la seguente istruzione:

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

Quindi, per conoscere l'ultima riga interessata subito dopo l'istruzione, è necessario aggiornare leggermente l'istruzione nel modo seguente:

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

Se è necessario aggiornare solo la riga realmente modificata, è necessario aggiungere un aggiornamento condizionale di item_id tramite LAST_INSERT_ID verificando se i dati cambieranno nella riga.


3
È sicuro per più utenti perché più client possono emettere l'istruzione UPDATE e ottenere il proprio valore di sequenza con l'istruzione SELECT (o mysql_insert_id ()), senza influenzare o essere influenzati da altri client che generano i propri valori di sequenza. Secondo dev.mysql.com/doc/refman/5.0/en/…
brutuscat

1
Non imposterà item_id sull'ultimo record inserito?
Arleslie,

2
@arleslie, se segui il link ai documenti nel commento del brutuscat sopra, vedrai che non lo farà. Questo è il comportamento previsto esattamente per il caso.
Newtover

1
Questa è davvero la risposta corretta. Sebbene la query sembri un po 'contro-intuitiva, questo è esattamente ciò che dice la documentazione di MySQL.
Timothy Zorn,

3
Nel caso in cui la query ti confonda, poiché LAST_INSERT_ID (expr) restituirà il valore di expr per la chiamata UPDATE, è possibile utilizzarlo anche in questo modo:UPDATE items SET qwe = 'qwe' WHERE asd = 'asd' AND LAST_INSERT_ID(item_id); SELECT LAST_INSERT_ID();
martinczerwi

14

Questo è ufficialmente semplice ma straordinariamente controintuitivo. Se stai facendo:

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

Modificalo in questo:

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

L'aggiunta last_insert_id(user_id)nella whereclausola dice a MySQL di impostare la sua variabile interna sull'ID della riga trovata. Quando si passa un valore a last_insert_id(expr)questo, finisce per restituire quel valore, che nel caso di ID come qui è sempre un numero intero positivo e quindi viene sempre valutato come vero, senza mai interferire con la clausola where. Funziona solo se è stata effettivamente trovata una riga, quindi ricorda di controllare le righe interessate. È quindi possibile ottenere l'ID in più modi.

MySQL last_insert_id()

È possibile generare sequenze senza chiamare LAST_INSERT_ID (), ma l'utilità di utilizzare la funzione in questo modo è che il valore ID viene mantenuto nel server come ultimo valore generato automaticamente. È sicuro per più utenti perché più client possono emettere l'istruzione UPDATE e ottenere il proprio valore di sequenza con l'istruzione SELECT (o mysql_insert_id ()), senza influenzare o essere influenzati da altri client che generano i propri valori di sequenza.

MySQL mysql_insert_id()

Restituisce il valore generato per una colonna AUTO_INCREMENT dall'istruzione INSERT o UPDATE precedente. Utilizzare questa funzione dopo aver eseguito un'istruzione INSERT in una tabella che contiene un campo AUTO_INCREMENT o aver utilizzato INSERT o UPDATE per impostare un valore di colonna con LAST_INSERT_ID (expr).

Il motivo delle differenze tra LAST_INSERT_ID () e mysql_insert_id () è che LAST_INSERT_ID () è reso facile da usare negli script mentre mysql_insert_id () cerca di fornire informazioni più precise su ciò che accade alla colonna AUTO_INCREMENT.

PHP mysqli_insert_id()

L'esecuzione di un'istruzione INSERT o UPDATE mediante la funzione LAST_INSERT_ID () modificherà anche il valore restituito dalla funzione mysqli_insert_id ().

Mettere tutto insieme:

$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();
}

(Cordiali saluti che la classe DB è qui .)


Importante da notare: questo è multi-connessione sicura, il valore persistente per last_insert_id o mysql_insert_id (e forse mysqli_insert_id, non ho verificato), sono per connessione. Eccezionale!
Ryan S,

10

Questo è lo stesso metodo della risposta di Salman A, ma ecco il codice che devi effettivamente fare.

Innanzitutto, modifica la tabella in modo che tenga automaticamente traccia di ogni modifica di una riga. Rimuovere l'ultima riga se si desidera sapere solo quando è stata inizialmente inserita una riga.

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

Quindi, per scoprire l'ultima riga aggiornata, è possibile utilizzare questo codice.

SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1;

Questo codice è stato estratto da MySQL vs PostgreSQL: aggiunta di una colonna "Ora dell'ultima modifica" a una tabella e Manuale MySQL: Ordinamento delle righe . L'ho appena assemblato.


7
Questo metodo può recuperare l'ID errato se il secondo inserimento viene eseguito subito dopo la prima query di inserimento. Tuttavia, se utilizziamo "WHERE" con questa query, ad esempio SELEZIONA ID DA mytable ORDER BY DESCm LIMITE DESCODIFICATO 1 DOVE (alcune condizioni relative all'ultima query di inserimento), potrebbe impedire il recupero dell'ID errato.
Naeem Ul Wahhab,

1
@ TheNoble-Coder Questo è vero. Se è necessario che l'ID di una riga influisca su una particolare query di aggiornamento, utilizzare la tecnica di Pomyk. Questa tecnica qui è più utile se usata in modo asincrono, dove vuoi solo l'ultimo aggiornamento assoluto.
Chad von Nau,

5

Query:

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

Funzione PHP:

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

È lavoro per me;)


mi è piaciuto lo stesso ma ho funzionato in modo diverso

3

Ulteriori informazioni sulla risposta sopra accettata
per coloro che si chiedevano :=e=

Differenza significativa tra :=e =, e cioè che :=funziona come un operatore di assegnazione variabile ovunque, mentre =funziona così solo nelle istruzioni SET, ed è un operatore di confronto ovunque.

Quindi SELECT @var = 1 + 1;rimarrà @varinvariato e restituirà un valore booleano (1 o 0 a seconda del valore corrente di @var), mentre SELECT @var := 1 + 1;cambierà @varin 2 e restituirà 2 . [Fonte]


Ehi, grazie. Ciò che significano è in realtà più interessante della risposta accettata sopra.
Verde,

2

Ehi, avevo solo bisogno di un simile trucco - l'ho risolto in un modo diverso, forse funzionerà per te. Nota che questa non è una soluzione scalabile e sarà molto male per grandi set di dati.

Dividi la query in due parti:

in primo luogo, selezionare gli ID delle righe che si desidera aggiornare e archiviarli in una tabella temporanea.

in secondo luogo, eseguire l'aggiornamento originale con la condizione nell'istruzione di aggiornamento modificata in where id in temp_table.

E per garantire la concorrenza, è necessario bloccare la tabella prima di questi due passaggi e quindi rilasciare il blocco alla fine.

Ancora una volta, questo funziona per me, per una query che termina con limit 1, quindi non uso nemmeno una tabella temporanea, ma semplicemente una variabile per memorizzare il risultato del primo select.

Preferisco questo metodo poiché so che aggiornerò sempre solo una riga e il codice è semplice.


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;

Ho dovuto lanciare l'id (non so perché) ... o non riesco a ottenere il contenuto @uids (era un blob) Tra le molte grazie per la risposta di Pomyk!


2

L'ID dell'ultima riga aggiornata è lo stesso ID utilizzato in 'updateQuery' per trovare e aggiornare quella riga. Quindi, salva (chiama) quell'ID su come desideri.

last_insert_id()dipende da AUTO_INCREMENT, ma l'ultimo ID aggiornato no.


3
Cosa succede se l'aggiornamento non viene eseguito da un ID ma piuttosto da un altro set di attributi?
Sebas,

2

La mia soluzione è, prima di decidere "id" (@uids) con il comando select e dopo aggiornare questo id con @uids.

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

ha funzionato sul mio progetto.


1

Se stai facendo solo inserimenti e ne desideri uno dalla stessa sessione, fai come da risposta peirix. Se si stanno apportando modifiche, sarà necessario modificare lo schema del database per memorizzare la voce aggiornata più di recente.

Se vuoi l'ID dall'ultima modifica, che potrebbe essere stata da una sessione diversa (cioè non quella che è stata appena eseguita dal codice PHP attualmente in esecuzione, ma uno fatto in risposta a una richiesta diversa), puoi aggiungere un TIMESTAMP nella colonna della tabella denominata last_modified (vedere http://dev.mysql.com/doc/refman/5.1/en/datetime.html per informazioni), quindi quando si aggiorna, impostare last_modified = CURRENT_TIME.

Dopo aver impostato questo, è quindi possibile utilizzare una query come: SELEZIONARE ID DA tabella ORDER BY last_modified DESC LIMIT 1; per ottenere la riga modificata più di recente.


-9

Non è necessario un codice Mysql così lungo. In PHP, la query dovrebbe assomigliare a questa:

$updateQuery = mysql_query("UPDATE table_name SET row='value' WHERE id='$id'") or die ('Error');
$lastUpdatedId = mysql_insert_id();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.