Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

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>";
}
share|improve this question
 
Why does it not work? Do you get an error? –  DaveRandom Aug 30 '11 at 9:13
 
Did you read my question at all? It works but does extra work. I want to decrease server load –  Tural Aliyev Aug 30 '11 at 9:15
 
Sorry, read it as "does not work", see answer below... –  DaveRandom Aug 30 '11 at 9:18
add comment

4 Answers

up vote 4 down vote accepted

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";
}
share|improve this answer
 
what does mean ``id`='".implode("' OR id='",$err)."` please explain –  Tural Aliyev Aug 30 '11 at 9:20
1  
 
IN would be more appropriate than repeated use of OR –  Jacco Aug 30 '11 at 9:25
 
Quite a lot OR clauses you have here. –  Tadeck Aug 30 '11 at 9:27
 
@Jacco Is the usage of IN faster, or is there another reason? (seriously, I didn't know) –  feeela Aug 30 '11 at 9:29
show 4 more comments

Check the SQL IN clause.

share|improve this answer
add comment

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.

share|improve this answer
 
+1 very clear answer imho –  Eamonn Jul 29 '12 at 13:36
add comment

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

share|improve this answer
 
If you provide $err = array('a', 'b', 'c');, the query will be: SELECT FROM err_msgs WHERE id IN ('a,b,c') (which is wrong and should be: SELECT FROM err_msgs WHERE id IN ('a','b','c'), not mentioning sanitization). –  Tadeck Aug 30 '11 at 9:27
1  
@Tadeck, I'm assuming the id to be an integer, and extra test for integerness of the array would be a good idea here, and take care of any sanitation issues. –  Johan Aug 30 '11 at 9:57
 
Assumption aside, your code is still incorrect because of the way it forms a query. You will create SELECT FROM err_msgs WHERE id IN ('1,2,3,4,5,6,7,8') when given array of integers, which will search for id equal to 1,2,3,4,5,6,7,8. See this codepad snippet. –  Tadeck Aug 30 '11 at 14:16
 
@Tadeck, fixed the code. –  Johan Aug 30 '11 at 14:17
 
@Tadeck, See: codepad.org/jFtoKM4m , codepad is pretty cool, thanks for that link. –  Johan Aug 30 '11 at 14:26
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.