Having trouble executing a SELECT query in a prepared statement

I think you have to bind to the columns in bind_results() like

/* prepare statement */
if ($stmt = $mysqli->prepare("SELECT Code, Name FROM Country ORDER BY Name LIMIT 5")) {
$stmt->execute();

/* bind variables to prepared statement */
$stmt->bind_result($col1, $col2);

/* fetch values */
while ($stmt->fetch()) {
    printf("%s %s\n", $col1, $col2);
}

Here $col1 and $col2 binds to Code and Name columns of Country table

(Instead of * in SELECT use the column names)

Further reference : http://php.net/manual/en/mysqli-stmt.bind-result.php


EDIT 07/2015 (question has been edited since original answer but underlying principles are the same)

Never SELECT * in a production environment, it will only come back to bite you in weird, unpredictable and seemingly unrelated ways. By specifying the columns you want, you will ensure that column ordering, data-type, constraint and all sorts of other elements won't cause you problems in the long run.

This answer is still mostly valid so I'll leave it here as-is, but the main take-away is: use PDO, it does 98% of the things you'll ever need with a much cleaner and more succinct API over the same back end. If you need a more complex RDBMS-specific API then you'll already understand the problems you have and why you need mysqli etc instead.


SELECT * doesn't work very well with MySQLi prepared statements. It's one of the major reasons I recommend PDO instead - that and the ridiculous requirement to bind variable references instead of values to the parameters.

$stmt->bind_result($row);

This is not binding the result row to a variable, it would just be binding a single column. And because you have used SELECT *, it doesn't do what you want it to.

If you do want to use MySQLi over PDO (which, as I say, I would recommend) there are a few good examples of how to SELECT * in the comments like this one on the bind_result() manual page.

Or you can just specify the columns you want to retrieve:

$sql_con = new mysqli('db', 'username', 'password', 'database');

if($stmt = $sql_con->prepare("SELECT name, countryCode FROM Country WHERE countryCode = ?")) {

   $stmt->bind_param("s", $country_code); 
   $stmt->execute(); 
   $stmt->bind_result($name, $countryCode);

   while ($stmt->fetch()) {
     // Because $name and $countryCode are passed by reference, their value
     // changes on every iteration to reflect the current row
     echo "<pre>";
     echo "name: $name\n";
     echo "countryCode: $countryCode\n";
     echo "</pre>";
   }

   $stmt->close();

EDIT based on your new code, you should be doing this:

// $date1 will be int(2010), $date2 will be int(1980) because you didn't
// quote the strings!
//$date1 = 2012-01-01;
//$date2 = 2012-01-31;

// Connect to DB
$sql_con = new mysqli('db', 'username', 'password', 'database');

// Check for connection errors here!

// The query we want to execute
$sql = "
  SELECT eventLogID
  FROM Country
  WHERE countryCode = ?
  AND date BETWEEN ? AND ?
";

// Attempt to prepare the query
if ($stmt = $sql_con->prepare($sql)) {

  // Pass the parameters
  $date1 = '2012-01-01';
  $date2 = '2012-01-31';
  $stmt->bind_param("sss", $country_code, $date1, $date2); 

  // Execute the query
  $stmt->execute();
  if (!$stmt->errno) {
    // Handle error here
  }

  // Pass a variable to hold the result
  // Remember you are binding a *column*, not a row
  $stmt->bind_result($eventLogID);

  // Loop the results and fetch into an array
  $logIds = array();
  while ($stmt->fetch()) {
    $logIds[] = $eventLogID;
  }

  // Tidy up
  $stmt->close();
  $sql_con->close();

  // Do something with the results
  print_r($logIds);

} else {
  // Handle error here
}

Not at all a fan of "bind_result" in mysqli beyond the simplest one-row-expected queries.

Stuffing a whole row into a single array item is better done with:

$stmt->execute();
$result = $stmt->get_result();
while ($data = $result->fetch_assoc())
    {
        $retvar[] = $data;
    }
$stmt->close();

or

while ($data = $result->fetch_row())

if you don't want/need the field names.