Inserciones paramétricas a granel

Estoy intentando cambiar algunas consultas codificadas para usar inputs parametrizadas, pero me he encontrado con un problema: ¿cómo formatear la input para inserciones masivas parametrizadas?

Actualmente, el código se ve así:

$data_insert = "INSERT INTO my_table (field1, field2, field3) "; $multiple_inserts = false; while ($my_condition) { if ($multiple_inserts) { $data_insert .= " UNION ALL "; } $data_insert .= " SELECT myvalue1, myvalue2, myvalue3 "; } $recordset = sqlsrv_query($my_connection, $data_insert); 

Una posible solución (modificada a partir de Cómo insert una matriz en una sola statement preparada de MySQL con PHP y PDO ) parece ser:

 $sql = 'INSERT INTO my_table (field1, field2, field3) VALUES '; $parameters = array(); $data = array(); while ($my_condition) { $parameters[] = '(?, ?, ?)'; $data[] = value1; $data[] = value2; $data[] = value3; } if (!empty($parameters)) { $sql .= implode(', ', $parameters); $stmt = sqlsrv_prepare($my_connection, $sql, $data); sqlsrv_execute($stmt); } 

¿Hay una mejor manera de realizar una inserción masiva con consultas parametrizadas?

Bueno, tienes tres opciones.

  1. Construye una vez – ejecuta múltiples. Básicamente, preparas el inserto una vez para una fila, luego recorres las filas que lo ejecutan. Dado que la extensión SQLSERVER no admite la reutilización de una consulta después de que ha sido preparada (debe hacer hacks sucios con references ) que puede no ser la mejor opción.

  2. Construye una vez – ejecuta una vez. Básicamente, construyes un inserto gigante como dijiste en tu ejemplo, lo vinculas una vez y lo ejecutas. Esto es un poco sucio y pasa por alto algunos de los beneficios que las consultas preparadas brindan. Sin embargo, debido al requisito de references de la Opción 1, haría este. Creo que es más limpio build una consulta gigante en lugar de depender de references variables.

  3. Build multiple – ejecuta multiple. Básicamente, toma el método que estás haciendo y ajústalo para volver a preparar la consulta en todos los loggings. Esto evita consultas demasiado grandes y "lotes" las consultas. Entonces algo como esto:

     $sql = 'INSERT INTO my_table (field1, field2, field3) VALUES '; $parameters = array(); $data = array(); $execute = function($params, $data) use ($my_connection, $sql) { $query = $sql . implode(', ', $parameters); $stmt = sqlsrv_prepare($my_connection, $query, $data); sqlsrv_execute($stmt); } while ($my_condition) { $parameters[] = '(?, ?, ?)'; $data[] = value1; $data[] = value2; $data[] = value3; if (count($parameters) % 25 == 0) { //Flush every 25 records $execute($parameters, $data); $parameters = array(); $data = array(); } } if (!empty($parameters)) { $execute($sql, $parameters, $data); } 

Cualquiera de los dos methods será suficiente. Haga lo que crea que se ajusta mejor a sus necesidades …

¿Por qué no usar el método "preparar una vez, ejecutar múltiples"? Sé que quiere que todos fallen o que todo funcione, pero no es exactamente difícil manejar eso con las transactions:

http://www.php.net/manual/en/pdo.begintransaction.php

http://www.php.net/manual/en/pdo.commit.php

http://www.php.net/manual/en/pdo.rollback.php