在准备好的语句中执行SELECT查询时出现问题


Having trouble executing a SELECT query in a prepared statement

关于在准备好的语句中使用SELECT,我遵循了一系列不同的示例,但没有返回任何结果。编辑我把代码改成这样:

$date1 = 2012-01-01;
$date2 = 2012-01-31;
$sql_con = new mysqli('db', 'username', 'password', 'database');
if($stmt = $sql_con->prepare("SELECT eventLogID FROM Country WHERE countryCode=? AND date BETWEEN ? AND ?")){
   $stmt->bind_param("sss", $country_code, $date1,$date2); 
    $stmt->execute();
  $i=0;
  while ($stmt->fetch()){
  $stmt->bind_result($row[$i]);
  $i++;
  }
  $stmt->close();
$sql_con->close();

现在,除了第一个条目外,所有需要的条目都添加到$row[]中。为什么不添加第一个条目?提前感谢!

编辑2015年7月(问题自最初的答案以来已编辑,但基本原理相同)

NeverSELECT *在生产环境中,它只会以奇怪、不可预测和看似无关的方式反噬你。通过指定所需的列,您将确保列顺序、数据类型、约束和其他各种元素从长远来看不会给您带来问题。

这个答案仍然是有效的,所以我将把它保留在这里,但主要的方法是:使用PDO,它可以在同一个后端使用更干净、更简洁的API完成98%的工作。如果您需要一个更复杂的特定于RDBMS的API,那么您已经了解了您所面临的问题,以及为什么您需要mysqli等。


SELECT *不能很好地与MySQLi准备的语句配合使用。这是我推荐PDO的主要原因之一,也是将变量引用而不是值绑定到参数的荒谬要求。

$stmt->bind_result($row);

这不是将结果绑定到变量,而是只绑定一列。因为你已经使用了SELECT *,它不会做你想做的事。

如果你真的想在PDO上使用MySQLi(正如我所说,我建议你这样做),在bind_result()手册页面上的评论中有一些关于如何SELECT *的好例子。

或者,您可以指定要检索的列:

$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();

编辑基于您的新代码,您应该这样做:

// $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
}

我认为您必须像一样绑定到bind_results()中的列

/* 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);
}

这里$col1和$col2绑定到Country表的Code和Name列

(使用列名代替SELECT中的*)

进一步参考:http://php.net/manual/en/mysqli-stmt.bind-result.php

除了最简单的一行预期查询之外,完全不喜欢mysqli中的"bind_result"。

将整行填充到单个数组项中最好使用:

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

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

如果您不想要/不需要字段名称。