2011-09-07 16 views
44

Normalmente puedo insertar una fila en una tabla MySQL y recuperar el last_insert_id. Ahora, sin embargo, quiero insertar a granel muchas filas en la tabla y obtener una serie de ID. ¿Alguien sabe cómo puedo hacer esto?¿Cómo puedo insertar muchas filas en una tabla MySQL y devolver las nuevas ID?

Hay algunas preguntas similares, pero no son exactamente lo mismo. No quiero insertar la nueva ID en ninguna tabla temporal; Solo quiero recuperar el conjunto de ID.

Can I retrieve the lastInsertId from a bulk insert?

Mysql mulitple row insert-select statement with last_insert_id()

+0

¿Por qué no puede insertarlos uno por uno? – sanmai

+0

Necesita simular la cláusula 'OUTPUT'. Creo que puedes hacer esto con un disparador en MySQL –

+0

No puedes usar la inserción masiva y luego una función lime last_insert_id(), no funciona. –

Respuesta

41

Hilo viejo, pero acabo de ver esto, así que aquí va: si está utilizando InnoDB en una versión reciente de MySQL, puede obtener la lista de ID utilizando LAST_INSERT_ID() y ROW_COUNT().

InnoDB garantiza números secuenciales para AUTO INCREMENT cuando se realizan inserciones masivas, siempre que innodb_autoinc_lock_mode se establezca en 0 (tradicional) o 1 (consecutiva). En consecuencia, puede obtener el primer ID de LAST_INSERT_ID() y el último agregando ROW_COUNT() - 1.

+2

¿Necesita una transacción? ¿Qué pasa si otras inserciones vinieron en el medio? – Mark

+3

Siempre que use el motor InnoDB y se asegure de que el bloqueo auto_increment está habilitado (lo que puede dar como resultado un rendimiento más lento) no se necesita una definición de transacción explícita. Como InnoDB realiza un bloqueo durante la inserción, otras inserciones deben esperar a que la inserción finalice. Eche un vistazo a http://dev.mysql.com/doc/refman/5.1/en/innodb-auto-increment-handling.html –

+0

¿Qué hay de MYISAM? – CMCDragonkai

9

La única manera que puedo pensar que podría hacerse es si almacena un identificador único para cada conjunto de filas insertadas (GUID) a continuación, seleccione los identificadores de fila. por ejemplo:

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'; 

También podría generar el GUID en la base de datos mediante el uso de 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

, no es una consulta de inserción masiva. – Peacemoon

0

creo que tendrá que o bien manejar la identificación de la transacción en su aplicación, o el ID de elemento en su aplicación para hacer esto sin problemas. (!)

Una manera de hacer esto que podría trabajar, asumiendo que todas sus inserciones tengan éxito, es el siguiente:

A continuación, puede obtener los insertos de identificación con un lazo para el número de filas afectadas, a partir de lastid (que es la primera identificación insertada de la inserción masiva). Y por lo tanto, comprobé que funciona perfectamente ... solo tenga cuidado de que HeidiSQL, por ejemplo, no devuelva el valor correcto para ROW_COUNT(), probablemente porque es una mala GUI haciendo mierda al azar, no se lo pedimos, sin embargo es perfectamente correcto de ya sea línea de comandos o mysqli PHP -

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

En PHP que tiene este aspecto (local_sqle es una llamada directamente a mysqli_query, local_sqlec es una llamada a mysqli_query + convertir conjunto de resultados de matriz 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++; 
} 

La razón por la cual las consultas están separadas es porque de lo contrario no obtendría mi resultado usando mis propias funciones, si Haga esto con funciones estándar, puede volver a colocarlo en una declaración y luego recuperar el resultado que necesita (debe ser el resultado número 2, suponiendo que utilice una extensión que maneje más de un conjunto de resultados/consulta).

1

Supongamos que tenemos una tabla llamada temptable con dos columnas uid, col1 donde uid es un campo de incremento automático. Hacer algo como a continuación devolverá todas las identificaciones insertadas en el conjunto de resultados. Puede recorrer el conjunto de resultados y obtener su identificación. Me doy cuenta de que esta es una publicación anterior y esta solución podría no funcionar en todos los casos. Pero para otros podría y por eso estoy respondiendo.

# 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; 
Cuestiones relacionadas