2

I have an array like this which contains a lot of row and I need to insert it into a MySQL database using PDO

array(3067) {
  [0]=>
  array(2) {
    ["order"]=>
    string(7) "2854811"
    ["consignment"]=>
    string(0) ""
  }
  [1]=>
  array(2) {
    ["blah"]=>
    string(7) "2854811"
    ["whatever"]=>
    string(2) "someval"
  }
  [4]=>
  array(2) {
    ["blah"]=>
    string(7) "2864412"
    ["whatever"]=>
    string(0) ""
  }

I have tried various combinations of suggestions made on here but each suggestion gets a different error message

php PDO insert batch multiple rows with placeholders

PDO MySQL: Insert multiple rows in one query

I have tried this

$db->beginTransaction();

$stmt = $db->prepare("INSERT INTO mytable (column1, column2) VALUES (:blah, :whatever)");

foreach($test as $insertRow){

    // now loop through each inner array to match binded values
    foreach($insertRow as $column => $value){
        $stmt->bindParam(":{$column}", $value);
        $stmt->execute();
    }
}

$db->commit();

but i get this error message

Uncaught exception 'PDOException' with message 'SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens

and I've also tried

$sql = 'INSERT INTO mytable (blah, whatever) VALUES ';
$insertQuery = array();
$insertData = array();
$n = 0;
foreach ($input as $row) {
    $insertQuery[] = '(:blah' . $n . ', :whatever' . $n . ')';
    $insertData['blah' . $n] = $row['blah'];
    $insertData['whatever' . $n] = $row['whatever'];
    $n++;
}

if (!empty($insertQuery)) {
    $sql .= implode(', ', $insertQuery);
    $stmt = $db->prepare($sql);
    $stmt->execute($insertData);
}

but i get this error message which makes no sense as each length of 'blah' are the same

Uncaught exception 'PDOException' with message 'SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'order_number' at row 1625'

How can i get my array to insert into the database? I'm not fussy if i have to execute a load of times or just once as long as I can get it to insert.

EDIT

What I am trying to do is read in a text file and insert it into an array which works perfectly so all i'm left with is an associative array with about 3000 rows and they each contain a field called 'blah' and 'whatever'.

After I get my array, i need to insert it into a MySQL database

CREATE TABLE IF NOT EXISTS `tracker` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `blah` varchar(8) NOT NULL,
  `whatever` varchar(25) NOT NULL,
  `input_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB

I should end up with about 3000 rows that was inserted from my array.

I hope this makes sense. If not I'll add some more

Community
  • 1
  • 1
AdRock
  • 2,959
  • 10
  • 66
  • 106

1 Answers1

5

I believe you almost had it with this example:

$db->beginTransaction();

$stmt = $db->prepare("INSERT INTO mytable (column1, column2) VALUES (:blah, :whatever)");

foreach($test as $insertRow){

   // now loop through each inner array to match binded values
   foreach($insertRow as $column => $value){
      $stmt->bindParam(":{$column}", $value);
      $stmt->execute();
   }
}

$db->commit();

The problem you are running into is you are calling execute() before you have bound the proper number of parameters. Instead, you need to bind all of your parameters first, then call execute().

$db->beginTransaction();

$stmt = $db->prepare("INSERT INTO mytable (column1, column2) VALUES (:blah, :whatever)");

foreach($test as $insertRow){

   // now loop through each inner array to match binded values
   foreach($insertRow as $column => $value){
      $stmt->bindParam(":{$column}", $value);
   }

}

// NOW DO EXECUTE
$stmt->execute();

$db->commit();

EDIT

In response to your comment, it's hard to tell exactly what you are trying to accomplish, but if you are only receiving one record, then it is because of what Gerald brought up, these are separate queries to all be transacted at once. Take a look at this revision:

// Start Transaction
$db->beginTransaction();

// Insert each record
foreach($test as $insertRow){

   // Prepare statement
   $stmt = $db->prepare("INSERT INTO mytable (column1, column2) VALUES (:blah, :whatever)");

   // now loop through each inner array to match binded values
   foreach($insertRow as $column => $value){
      $stmt->bindValue(":{$column}", $value);
   }

   // Execute statement to add to transaction
   $stmt->execute();

   // Clear statement for next record (not necessary, but good practice)
   $stmt = null;
}

// Commit all inserts
$db->commit();
Chuck Le Butt
  • 47,570
  • 62
  • 203
  • 289
Jeremy Harris
  • 24,318
  • 13
  • 79
  • 133
  • I think the `execute();`belongs inside of the outer foreach loop – Gerald Schneider Oct 10 '13 at 12:13
  • In that case, the outer foreach would need to wrap outside the `prepare()` statement as well. It's hard to tell when the parameters are ":blah" and ":whatever" so I can't really match it up with the array data. – Jeremy Harris Oct 10 '13 at 12:16
  • Thanks for your suggestion. I get no errors but I only get 1 record inserted instead of 3000 which i expect and just noticed it doesn't actually insert any data except the timestamp i have set in the database – AdRock Oct 10 '13 at 12:23
  • @cillosis Thanks for your help but now i get the error message as in my post about String data, right truncated:. I'll edit my post to try and explain what i want to do – AdRock Oct 10 '13 at 12:33
  • 1
    You will need to show your **actual** code in order for us to help any further because `VALUES (:blah, :whatever)` is pretty much useless. – Jeremy Harris Oct 10 '13 at 12:34