开发者

MySQL query within foreach loop

I want to show all text messages from db where id=$e ($err is an array).

Inserted the query into the foreach loop, it works well but it does extra work (does query for every value of array).

Is there any other way to do it (i mean extract query from foreach loop)?

My code looks like this.

foreach ($err as $e) 
开发者_高级运维{
$result = $db -> query("SELECT * from err_msgs WHERE id='$e'");
$row = $result -> fetch_array(MYSQLI_BOTH);
echo "<li><span>".$row[1]."</span></li>";
}


It is much more efficient to do this with implode() because it will only result in one database query.

if (!$result = $db->query("SELECT * FROM `err_msgs` WHERE `id`='".implode("' OR `id`='",$err)."'")) {
  echo "Error during database query<br />\n";
  // echo $db->error(); // Only uncomment this line in development environments. Don't show the error message to your users!
}
while ($row = $result->fetch_array(MYSQLI_BOTH)) {
  echo "<li><span>".$row[1]."</span></li>\n";
}


Check the SQL IN clause.


Firstly, a bit of a lecture: embedding strings directly into your queries is going to cause you trouble at some point (SQL injection related trouble to be precise), try to avoid this if possible. Personally, I use the PDO PHP library which allows you to bind parameters instead of building up a string.

With regard to your question, I'm not sure I have understood. You say that it does extra work, do you mean that it returns the correct results but in an inefficient way? If so then this too can be addressed with PDO. Here's the idea.

Step 1: Prepare your statement, putting a placeholder where you currently have '$e' Step 2: Loop through $err, in the body of the loop you will set the place holder to be the current value of $e

By doing this you not only address the SQL injection issue, you can potentially avoid the overhead of having to parse and optimise the query each time it is executed (although bear in mind that this may not be a significant overhead in your specific case).

Some actual code would look as follows:

// Assume that $dbdriver, $dbhost and $dbname have been initialised
// somewhere. For a mysql database, the value for $dbdriver should be
// "mysql".

$dsn = "$dbdriver:host=$dbhost;dbname=$dbname";
$dbh = new PDO($dsn, $dbuser, $dbpassword); 

$qry = "SELECT * from err_msgs WHERE id = :e"
$sth = $dbh->prepare($qry);

foreach ($err as $e) {
    $sth->bindParam(":e", $e);
    $sth->execute();
    $row = $sth->fetch();

    // Prints out the *second* field of the record
    // Note that $row is also an associative array so if we
    // have a field called id, we could use $row["id"] to 
    // get its value
    echo "<li><span>".$row[1]."</span></li>";
}

One final point, if you want to simply execute the query once, instead of executing it inside the loop, this is possible but again, may not yield any performance improvement. This could be achieved using the IN syntax. For example, if I'm interested in records with id in the set {5, 7, 21, 4, 76, 9}, I would do:

SELECT * from err_msgs WHERE id IN (5, 7, 21, 4, 76, 9)

I don't think there's a clean way to bind a list using PDO so you would use the loop to build up the string and then execute the query after the loop. Note that a query formulated in this way is unlikely to give you any noticable performance improvment but it really does depend on your specific circumstances and you'll just have to try it out.


You can do this much simpler by doing

$err_csv = implode("','",$err);
$sql = "SELECT FROM err_msgs WHERE id IN ('$err_csv')";
$result = $db -> query($sql);
while ($row = $result -> fetch_array(MYSQLI_BOTH)) 
{
   echo "<li><span>".$row[1]."</span></li>";
}

That way you don't have to keep sending queries to the database.

Links:
http://php.net/manual/en/function.implode.php

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜