php PDO inserir lotes de várias linhas com espaços reservados

Estou procurando fazer inserções múltiplas usando o PHP DOP.

A resposta mais próxima que encontrei é essa

instrução how-to-insert-an-array-into-a-single-mysql-prepared-statement

No entanto, o exemplo que foi dado usa ?? em vez de espaços reservados reais.

Eu examinei os exemplos no site do doc PHP para os detentores de lugar

php.net pdo.prepared-statements

$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)"); $stmt->bindParam(':name', $name); $stmt->bindParam(':value', $value); 

Agora, digamos que eu queria alcançar o acima, mas com uma matriz

 $valuesToInsert = array( 0 => array('name' => 'Robert', 'value' => 'some value'), 1 => array('name' -> 'Louise', 'value' => 'another value') ); 

Como eu iria sobre isso com PDO e várias inserções por transação?

Imagino que começaria com um loop?

 $stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)"); foreach($valuesToInsert as $insertRow){ // now loop through each inner array to match binded values foreach($insertRow as $column => value){ $stmt->bindParam(":{$column}", value); } } $stmt->execute(); 

No entanto, o acima não funciona, mas espero demonstrar o que estou tentando alcançar

Em primeiro lugar ? Os símbolos são lugares reais (a maioria dos drivers permite usar ambas as syntaxs, posições e titulares nomeados). Em segundo lugar, as declarações preparadas não são mais que uma ferramenta para injetar input bruta em instruções SQL – a syntax da própria declaração SQL não é afetada. Você já possui todos os elementos que você precisa:

  • Como inserir várias linhas com uma única consulta
  • Como gerar SQL dinamicamente
  • Como usar declarações preparadas com os titulares nomeados.

É bastante trivial combiná-los todos:

 $sql = 'INSERT INTO table (memberID, programID) VALUES '; $insertQuery = array(); $insertData = array(); $n = 0; foreach ($data as $row) { $insertQuery[] = '(:memberID' . $n . ', :programID' . $n . ')'; $insertData['memberID' . $n] = $memberid; $insertData['programID' . $n] = $row; $n++; } if (!empty($insertQuery)) { $sql .= implode(', ', $insertQuery); $stmt = $db->prepare($sql); $stmt->execute($insertData); } 

Estou assumindo que você está usando o InnoDB, portanto, esta resposta só é válida para esse mecanismo (ou qualquer outro mecanismo compatível com transactions, o que significa que o MyISAM não está incluído).

Por padrão, o InnoDB é executado no modo de confirmação automática. Isso significa que cada consulta é tratada como sua própria transação contida.

Para traduzir isso para algo que os mortais podem entender, isso significa que cada consulta INSERT que você emitirá forçará o disco rígido a confirmá-lo, anotando as informações da consulta. Considerando como os discos rígidos mecânicos são super lentos, pois sua operação de input e saída por segundo é baixa (se eu não estou enganado, a média é 300 EO), isso significa que suas 50 000 consultas serão – bem, super lentas.

Então, o que você faz? Você envolve todas as suas consultas de 50k em uma única transação. Pode não ser a melhor solução para várias finalidades, mas será rápido.

Você faz isso assim:

 $dbh->beginTransaction(); $stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)"); foreach($valuesToInsert as $insertRow) { // now loop through each inner array to match bound values foreach($insertRow as $column => value) { $stmt->bindParam(":$column", value); $stmt->execute(); } } $dbh->commit(); 

Algumas modificações na solução fornecidas pelo NB
$ stmt-> execute () deve estar fora do loop interno porque você pode ter uma ou mais colunas que precisam se ligar antes de chamar $ stmt-> execute () senão você obterá exceção “Número de parâmetro inválido: número de variables ​​vinculadas faz não corresponde a número de token “.
A segunda variável “valor” estava faltando sinais de dólar.

 function batchinsert($sql,$params){ try { db->beginTransaction(); $stmt = db->prepare($sql); foreach($params as $row) { // now loop through each inner array to match bound values foreach($row as $column => $value) { $stmt->bindParam(":$column", $value); } $stmt->execute(); } db->commit(); } catch(PDOExecption $e) { $db->rollback(); } } 

Teste:

 $sql = "INSERT INTO `test`(`name`, `value`) VALUES (:name, :value)" ; $data = array(); array_push($data, array('name'=>'Name1','value'=>'Value1')); array_push($data, array('name'=>'Name2','value'=>'Value2')); array_push($data, array('name'=>'Name3','value'=>'Value3')); array_push($data, array('name'=>'Name4','value'=>'Value4')); array_push($data, array('name'=>'Name5','value'=>'Value5')); batchinsert($sql,$data); 

Seu código estava realmente ok, mas teve um problema em $stmt->bindParam(":$column", value); Deve ser $stmt->bindValue(":{$column}", $value); e funcionará perfeitamente. Isso ajudará os outros no futuro.

Código completo:

 foreach($params as $row) { // now loop through each inner array to match bound values foreach($row as $column => $value) { $stmt->bindValue(":{$column}", $value); //EDIT } // Execute statement to add to transaction $stmt->execute(); } 

Mover executar dentro do loop.

 $stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)"); foreach($valuesToInsert as $insertRow) { $stmt->execute($insertRow); } 

Se você tiver algum problema com essa maneira recomendada, você deve fazer uma pergunta descrevendo esses problemas.