【问题标题】:Having trouble executing a SELECT query in a prepared statement在准备好的语句中执行 SELECT 查询时遇到问题
【发布时间】:2012-07-19 11:58:31
【问题描述】:

我遵循了一堆关于在准备好的语句中使用 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[]。为什么没有添加第一个条目? 提前致谢!

【问题讨论】:

  • 您在查询中使用 *,但在 bind_result($row) 中使用 $row。 bind_result 应该包含我认为的列。在此处阅读更多信息:nl3.php.net/manual/en/mysqli-stmt.bind-result.php 因此,您的 $row 变量包含 * 表示的第一列。 (在所有查询中避免 *,但这是另一回事。)

标签: php mysqli prepared-statement


【解决方案1】:

编辑 07/2015(问题自原始答案以来已被编辑,但基本原则相同)

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

这个答案大部分仍然有效,所以我将其原样留在这里,但主要的收获是:使用 PDO,它可以完成 98% 的事情,而且更简洁、更简洁API 在同一个后端。如果您需要更复杂的特定于 RDBMS 的 API,那么您将已经了解您遇到的问题以及为什么需要 mysqli 等。


SELECT * 不适用于 MySQLi 准备好的语句。这是我推荐 PDO 的主要原因之一 - 以及将变量引用而不是值绑定到参数的荒谬要求。

$stmt->bind_result($row);

这不是将结果 row 绑定到变量,它只是绑定单个列。而且因为你使用了SELECT *,所以它并没有达到你想要的效果。

如果您确实想在 PDO 上使用 MySQLi(正如我所说,我会推荐),在 bind_result() 手册页上的 this one 等 cmets 中有一些很好的示例说明如何使用 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();

EDIT 根据您的新代码,您应该这样做:

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

【讨论】:

  • 感谢您的回复。我取得了一些进展,但请检查我的编辑以了解后续问题。
  • 我也在为此苦苦挣扎,做一个选择准备好的语句是行不通的,你到底做了什么?
【解决方案2】:

我认为您必须像绑定到 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

【讨论】:

  • 感谢您的回复。我取得了一些进展,但请检查我的编辑以了解后续问题。
【解决方案3】:

除了最简单的单行预期查询之外,根本不喜欢 mysqli 中的“bind_result”。

将整行填充到单个数组项中更好:

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

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

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

【讨论】:

  • 仅供参考,$result->fetch_all().
猜你喜欢
  • 2011-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-13
  • 2020-03-15
  • 1970-01-01
  • 2018-12-11
相关资源
最近更新 更多