5

i have an array from a post:

//this are arrays
$name    = $_POST["name"];
$age     = $_POST["age"];
$date    = $_POST["date"];

i have an insert query in PDO:

$stmt = $db->prepare("INSERT INTO staff (name, age, address) VALUES (:name, :age, :address)");

my question how can i generate/or achieve a query using php that looks like:

INSERT INTO staff (name, age, address) VALUES
($name[0], $age[0], $address[0]), ($name[1], $age[1], $address[1])... etc

I try to keep server load low.

hakre
  • 193,403
  • 52
  • 435
  • 836
Viscocent
  • 2,024
  • 2
  • 19
  • 26
  • The number of queries are not actually that what produce server-load. Also from your question it is not clear which concrete problem you're trying to solve? IIRC the PHP manual has a code-example how that works already, so I wonder what exactly does not work for you? Maybe you can clarify a little into which concrete problem you run? – hakre May 05 '13 at 13:33

4 Answers4

4

You could prepare the appropriate statement, i.e. something like:

$sql = "INSERT INTO staff (name, age, address) VALUES ";
$values = array();

for ($i = 1; $i <= $count; $i++) {
  $values[] =  "(:name$i, :age$i, :address$i)"
}

$stmt = $db->prepare($sql . implode(', ', $values));

But, imho, you'll probably be just as well off lopping through each set of values. It's not much of a burden for the server, and your code will be simpler.

Denis de Bernardy
  • 75,850
  • 13
  • 131
  • 154
3

It is not possible with prepared statements.

If you want to insert a variable amount of records in one query then the SQL query must be generated dynamically, which makes it impossible to prepare it beforehand.

If you use the database driver's escape_string function (that would be quote() for MySQL) then you can build the query and still get the security that prepared statements give you.

$query = "INSERT INTO table (a, b, c) VALUES";
$tuple = " ('%s', '%s', '%s'),";
foreach ($items as $item) {
    $a = $db->quote($item['a']);
    $b = $db->quote($item['b']);
    $c = $db->quote($item['c']);
    $query .= sprintf($tuple, $a, $b, $c);
}
$query = rtrim($query, ","); // Remove trailing comma
// Use the query...

Addendum:

If you are using prepared statements then you can insert records separately and not have to worry about inserting them in one go. That is actually the whole point of prepared statement.

Unlike good old SQL queries, which are a one-step process and are just sent and then forgotten...

$db->query("INSERT INTO table (a, b, c) VALUES ('a', 'b', 'c')");

...prepared statements are a two-step process.

First, you create the prepared statement. This statement is then sent to the database, telling it that "this is what you should be expecting". The database will often also optimize the query to make it faster. This step then gives you back a statement handle (often called $stmt in PHP documentation).

$stmt = $db->prepare('INSERT INTO table (a, b, c) VALUES (:a, :b, :c)');

Second, with this handle you can then proceed to insert stuff:

foreach ($records as $record) {
    $stmt->execute(array(
        ':a' => $record['a'],
        ':b' => $record['b'],
        ':c' => $record['c'],
    ));
}

Because the database already knows what to expect it can optimize the speed of the INSERTs, meaning that you do not have to go through the stuff that I mentioned above this addendum.

Wikipedia actually has a quite nice writeup of prepared statements.

dotancohen
  • 30,064
  • 36
  • 138
  • 197
Sverri M. Olsen
  • 13,055
  • 3
  • 36
  • 52
1

If you are using PDO, you should prepare your statement, and execute it with different values:

$stmt = $db->prepare("INSERT INTO staff (name,age,address) VALUES (:name,:age,:address)");

for($i=0;$i<count($name);$i++)
{
    $stmt->execute(array(
        ":name" => $name[$i],
        ":age" => $age[$i],
        ":address" => $address[$i]));
}

However, if you would like to put it into a single query, you should use $db->exec():

$query = "INSERT INTO staff (name,age,address) VALUES ";
$values = array();

for($i=0;$i<count($names);$i++)
{
    array_push($values, "('" . $name[$i] . "','" . $age[$i] . "','" . $address . "')");
}

$db->exec($query . implode("," . $values));

Be warned this method, contrary to the prepare and execute method, is vulnerable since it does not validate the input

Opifexer
  • 176
  • 8
0

Add the delayed keyword to the insert (insert delayed ...) to reduce serverload, and just loop over the prepared statement with all values. MySQL will queue it internally anyway as separate insert statements if you do a big bunch of inserts, the extended syntax is just syntactic sugar.

Niels Keurentjes
  • 41,402
  • 9
  • 98
  • 136