2009-04-22 4 views
104

Ho la seguente query:MySQL ON DUPLICATE KEY - ultimo ID inserto?

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

voglio l'ID sia del inserimento o l'aggiornamento. Di solito eseguo una seconda query per ottenere questo, poiché credo che insert_id() restituisca solo l'ID 'inserito' e non l'ID aggiornato.

C'è un modo per INSERIRE/AGGIORNARE e recuperare l'ID della riga senza eseguire due query?

+3

Invece di supporre, perché non lo testate da soli? L'SQL nella modifica di cui sopra funziona, e attraverso il mio test è più veloce di un errore di inserimento, utilizzando INSERIMENTO IGNORA, o selezionando per vedere se c'è un duplicato prima. –

+1

AVVISO: la soluzione proposta funziona, ma il valore auto_increment continua ad aumentare, anche se non è presente alcun inserto. Se la chiave duplicata si verifica spesso, è consigliabile eseguire 'alter table nome tableau AUTO_INCREMENT = 0;' dopo la query precedente, per evitare grandi lacune nei valori id. –

risposta

125

controllare questa pagina out: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
nella parte inferiore della pagina che spiega come si può fare LAST_INSERT_ID significativo di aggiornamenti passando un'espressione da th alla funzione MySQL.

Dall'esempio documentazione MySQL:

Se una tabella contiene una colonna AUTO_INCREMENT e INSERTO ... UPDATE inserisce una riga, il LAST_INSERT_ID() restituisce il valore AUTO_INCREMENT. Se invece l'istruzione aggiorna una riga, LAST_INSERT_ID() non è significativo. Tuttavia, puoi ovviare a questo problema utilizzando LAST_INSERT_ID (expr). Supponi che id sia la colonna AUTO_INCREMENT. Per rendere LAST_INSERT_ID() significativa per gli aggiornamenti, Inserisci righe come segue:

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

In qualche modo mi sono perso quando ho visto quella pagina. Così la parte di aggiornamento appare come: UPDATE id = LAST_INSERT_ID (id) E che le grandi opere. Grazie! – thekevinscott

+1

Contento di aver potuto aiutare! – fredrik

+6

Si dice che la funzione php mysql_insert_id() restituisca il valore corretto in entrambi i casi: http://www.php.net/manual/en/function.mysql-insert-id.php#59718. – jayarjo

2

Si potrebbe guardare REPLACE, che è essenzialmente un delete/insert se il record esiste. Ma questo cambierebbe il campo di incremento automatico se presente, che potrebbe rompere le relazioni con altri dati.

+1

Ah sì - Sto cercando qualcosa che non si sbarazzi degli ID precedenti – thekevinscott

+0

Questo potrebbe essere pericoloso anche perché questo potrebbe anche causare la cancellazione di un altro dato correlato (da vincoli). – Serge

0

Vale la pena notare, e questo potrebbe essere ovvio (ma lo dirò comunque per chiarezza qui), che sostituiscono sarà soffiare via la riga corrispondente esistente prima di inserire i nuovi dati. ON DUPLICATE KEY UPDATE aggiornerà solo le colonne specificate e conserverà la riga.

Dal manual:

REPLACE funziona esattamente come INSERT, tranne che se una vecchia riga nella tabella ha lo stesso valore come una nuova riga per una chiave primaria o un indice univoco, il la vecchia riga viene cancellata prima che la nuova riga sia inserita.

25

Per essere precisi, se questa è la query originale:

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

e 'id' è la chiave primaria di incremento automatico di questa sarebbe la soluzione di lavoro:

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

È tutto qui: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

Se una tabella contiene un AUTO_INCREMENT colonna e INSERT ... UPDATE inserisce una riga, la funzione LAST_INSERT_ID() restituisce il valore AUTO_INCREMENT . Se invece l'estratto aggiorna una riga, LAST_INSERT_ID() non è significativo. Tuttavia, puoi aggirare questo utilizzando LAST_INSERT_ID (expr). Supponi che id sia la colonna AUTO_INCREMENT .

+3

Sì, vedere la risposta accettata per lo stesso cosa hai detto. Non c'è bisogno di rianimare i post di 3 anni. Grazie comunque per il tuo impegno. – fancyPants

+1

@tombom l'unica ragione per cui ho postato questa risposta è perché la risposta accettata non è corretta - non funzionerà se non c'è nulla da aggiornare. –

+0

+1 anche se penso che la risposta accettata menzioni che :) – fancyPants

0

Le soluzioni esistenti funzionano se si utilizza l'autoincremento. Ho una situazione in cui l'utente può definire un prefisso e dovrebbe riavviare la sequenza a 3000. A causa di questo prefisso variegato, non posso usare l'autoincremento, il che rende last_insert_id vuoto per gli inserti. Ho risolto con il seguente:

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

Se esiste il prefisso, sarà incrementarlo e popolare LAST_INSERT_ID. Se il prefisso non esiste, inserirà il prefisso con il valore 3000 e popolerà last_insert_id con 3000.