2011-09-07 10 views
44

Normalmente posso inserire una riga in una tabella MySQL e ottenere il last_insert_id indietro. Ora, però, voglio inserire in massa molte righe nella tabella e recuperare un array di ID. Qualcuno sa come posso fare questo?Come posso inserire molte righe in una tabella MySQL e restituire i nuovi ID?

Ci sono alcune domande simili, ma non sono esattamente le stesse. Non voglio inserire il nuovo ID su nessuna tabella temporanea; Voglio solo recuperare l'array di ID.

Can I retrieve the lastInsertId from a bulk insert?

Mysql mulitple row insert-select statement with last_insert_id()

+0

Perché non è possibile inserirli uno per uno? – sanmai

+0

È necessario simulare la clausola 'OUTPUT'. Credo che si possa fare questo con un trigger in MySQL –

+0

Non è possibile utilizzare l'inserimento di massa e quindi una funzione lime last_insert_id(), non funziona. –

risposta

41

Vecchio thread, ma ho appena esaminato questo, quindi ecco qui: se si utilizza InnoDB su una versione recente di MySQL, è possibile ottenere l'elenco degli ID utilizzando LAST_INSERT_ID() e ROW_COUNT().

InnoDB garantisce i numeri sequenziali per AUTO INCREMENT quando si eseguono inserimenti di massa, purché innodb_autoinc_lock_mode sia impostato su 0 (tradizionale) o 1 (consecutivo). Di conseguenza è possibile ottenere l'ID primo da LAST_INSERT_ID() e lo ultimo aggiungendo ROW_COUNT() - 1.

+2

Hai bisogno di una transazione? Cosa succederebbe se altri inserti fossero nel mezzo? – Mark

+3

Finché si utilizza il motore InnoDB e si assicura che il blocco auto_increment sia abilitato (il che può comportare prestazioni più lente) non è necessaria una definizione di transazione esplicita. Poiché InnoDB esegue un blocco durante l'inserimento, altri inserti devono attendere la fine dell'inserimento. Dai un'occhiata a http://dev.mysql.com/doc/refman/5.1/en/innodb-auto-increment-handling.html –

+0

Che mi dici di MYISAM? – CMCDragonkai

9

L'unico modo che posso pensare che potrebbe essere fatto è che se si memorizza un identificatore univoco per ogni set di righe inserite (GUID) quindi selezionare gli ID di riga. esempio:

INSERT INTO t1 
(SELECT col1,col2,col3,'3aee88e2-a981-1027-a396-84f02afe7c70' FROM a_very_large_table); 
COMMIT; 

SELECT id FROM t1 
WHERE guid='3aee88e2-a981-1027-a396-84f02afe7c70'; 

Si potrebbe anche generare il GUID nel database utilizzando uuid()

-8
$query = "INSERT INTO TABLE (ID,NAME,EMAIL) VALUES (NULL,VALUE1, VALUE2)"; 
$idArray = array(); 
foreach($array as $key) { 
mysql_query($query); 
array_push($idArray, mysql_insert_id()); 
} 
print_r($idArray); 
+2

non è una query di inserimento bulk. – Peacemoon

0

penso che si dovrà o gestire l'ID della transazione nella vostra applicazione, o l'id articolo nel vostro applicazione per farlo in modo impeccabile. (!)

Un modo per fare questo, che potrebbe funzionare, partendo dal presupposto che tutti i vostri inserti successo, è la seguente:

È quindi possibile ottenere l'ID inseriti di con un ciclo per il numero di righe interessate, a partire da lastid (che è il primo ID inserito dell'inserto di massa). E così, ho verificato che funziona perfettamente .. basta fare attenzione che HeidiSQL per esempio non restituirà il valore corretto per ROW_COUNT(), probabilmente perché è una schifosa interfaccia grafica che fa casuali merda noi non lo chiediamo - tuttavia è perfettamente corretto da o riga di comando o PHP mysqli -

START TRANSACTION; 
BEGIN; 
INSERT into test (b) VALUES ('1'),('2'),('3'); 
SELECT LAST_INSERT_ID() AS lastid,ROW_COUNT() AS rowcount; 
COMMIT; 

In PHP sembra che questo (local_sqle è una chiamata direttamente al mysqli_query, local_sqlec è una chiamata a mysqli_query + conversione di risultati di array PHP):

local_sqle("START TRANSACTION; 
BEGIN; 
INSERT into test (b) VALUES ('1'),('2'),('3');"); 
$r=local_sqlec("SELECT LAST_INSERT_ID() AS lastid,ROW_COUNT() AS rowcount;"); 
local_sqle(" 
COMMIT;"); 
$i=0; 
echo "last id =".($r[0]['lastid'])."<br>"; 
echo "Row count =".($r[0]['rowcount'])."<br>"; 

while($i<$r[0]['rowcount']){ 
    echo "inserted id =".($r[0]['lastid']+$i)."<br>"; 
    $i++; 
} 

Il motivo per cui le query sono separate è perché altrimenti non otterrei il mio risultato usando le mie funzioni, se lo sei Lo fai con le funzioni standard, puoi rimetterlo in una dichiarazione e poi recuperare il risultato che ti serve (dovrebbe essere il risultato numero 2 - assumendo che tu usi un'estensione che gestisce più di una serie di risultati/query).

1

Supponiamo di avere una tabella chiamata temptable con due cols uid, col1 dove uid è un campo di incremento automatico. Fare qualcosa come sotto restituirà tutti gli ID inseriti nel set di risultati. Puoi scorrere il set di risultati e ottenere i tuoi id. Mi rendo conto che questo è un vecchio post e questa soluzione potrebbe non funzionare per tutti i casi. Ma per altri potrebbe ed è per questo che sto rispondendo ad esso.

# lock the table 
lock tables temptable write; 

#bulk insert the rows; 
insert into temptable(col1) values(1),(2),(3),(4); 

#get the value of first inserted row. when bulk inserting last_insert_id() #should give the value of first inserted row from bulk op. 
set @first_id = last_insert_id(); 

#now select the auto increment field whose value is greater than equal to #the first row. Remember since you have write lock on that table other #sessions can't write to it. This resultset should have all the inserted #id's 
select uid from temptable where uid >[email protected]_id; 

#now that you are done don't forget to unlock the table. 
unlock tables; 
Problemi correlati