2011-01-11 18 views
10

Estoy intentando cambiar algunas consultas codificadas para usar entradas parametrizadas, pero me he encontrado con un problema: ¿cómo formatea la entrada para inserciones a granel parametrizadas?Inserciones paramétricas a granel

Actualmente, el código es el siguiente:

$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 (modificado de How to insert an array into a single MySQL Prepared statement w/ PHP and 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 lograr una inserción masiva con parametrizado consultas?

+1

Una posible solución, específico para declaraciones preparadas , es "preparación única, ejecuciones múltiples" –

+0

Estaba tratando de evitar hacer eso para limitar la necesidad del manejo de transacciones. Si alguno de los insertos falla, toda la operación debería fallar. –

+0

¿qué transacción? –

Respuesta

5

Bueno, tienes tres opciones.

  1. Compilar una vez: ejecutar varias. Básicamente, preparas el inserto una vez para una fila, luego recorres las filas que lo ejecutan. Como la extensión SQLSERVER no admite el reencuadernación de una consulta una vez preparada (debe hacer dirty hacks with references), puede que no sea la mejor opción.

  2. Compilar una vez: ejecutar 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 referencias de la Opción 1, haría este. Creo que es más limpio construir una consulta gigante en lugar de depender de referencias variables.

  3. Compilar múltiples: ejecutar múltiples. Básicamente, toma el método que estás haciendo y ajústalo para volver a preparar la consulta en todos los registros. Esto evita consultas demasiado grandes y "lotes" las consultas. Así que algo como esto: será suficiente

    $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 métodos. Haga lo que crea que se ajusta mejor a sus necesidades ...

+1

Solo para aclarar: en ambas opciones 2 y 3, la instrucción SQL se vería así (si se imprimiera en la pantalla): 'INSERT INTO mytable (field1, field2, field3) VALUES (?,?,?) , (?,?,?), (?,?,?), etc.' a rellenar por la matriz que se le pasa. ¿Es eso correcto? –

+0

@Zac: Sí, eso es correcto. El tercero tendría como máximo 25 de los grupos (podría modificarlo según el tamaño de los datos). El segundo tendría tantas filas como tengas ... – ircmaxell

+0

Todos los valores se insertan como 'PDO :: PARAM_STR', ¿no es así? ¿Cómo especificar los tipos? –

2

¿Por qué no utiliza el método "prepare once, execute multiple"? Sé que usted quiere que sea todo falle o todo el trabajo, pero no es exactamente difícil de manejar que las transacciones:

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

+0

No es difícil, pero agrega un nivel de complejidad a este código que realmente no es necesario. Bulk Inserts es la solución más elegante a mi problema, es solo una cuestión de sintaxis de la que no estaba seguro. –

+0

Además, esto está utilizando la extensión nativa 'sqlsrv' que no es la cosa más sana del mundo (si él estaba usando PDO, posiblemente, pero la extensión nativa sqlsrv falta en algunas áreas) ... – ircmaxell

+1

si el punto de esto es pasar a consultas paramaterizadas, ¿por qué no pasar a PDO al mismo tiempo? en cuanto a la "complejidad", no es exactamente difícil agregar un cheque si falla una llamada a execute(), y si es así hacer un rollback() y luego cualquier otro manejo de errores que necesite. – Stephen

Cuestiones relacionadas