0

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>";
}
3
  • Why does it not work? Do you get an error? Commented Aug 30, 2011 at 9:13
  • Did you read my question at all? It works but does extra work. I want to decrease server load Commented Aug 30, 2011 at 9:15
  • Sorry, read it as "does not work", see answer below... Commented Aug 30, 2011 at 9:18

4 Answers 4

4

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";
}
Sign up to request clarification or add additional context in comments.

8 Comments

what does mean ``id='".implode("' OR id='",$err)." please explain
IN would be more appropriate than repeated use of OR
Quite a lot OR clauses you have here.
@Jacco Is the usage of IN faster, or is there another reason? (seriously, I didn't know)
@Dave, your quoting is incorrect, the query will translate to: ... WHERE id = '' OR id = '1'' OR ... So you have an extra test id = '' (no biggy), but on the first real test you have one quote too many. Anyway fixed it.
|
1

Check the SQL IN clause.

Comments

1

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.

Comments

0

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

4 Comments

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, 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.
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, See: codepad.org/jFtoKM4m , codepad is pretty cool, thanks for that link.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.