【问题标题】:Variable amount of columns returned in mysqli prepared statementmysqli准备好的语句中返回的可变数量的列
【发布时间】:2010-05-27 19:39:22
【问题描述】:

我有一种情况,正在生成一个动态查询,该查询可以跨多个表选择 1 到 300 多个不同的列。它目前仅在执行查询时就可以正常工作,但是我在使用准备好的语句时遇到的问题是我不知道如何处理这样一个事实,即我不知道每次要查询多少列并且因此不知道如何处理结果。 我相信绑定语句会有所帮助的原因是,一旦此查询运行一次,它将很可能(尽管并非总是)以完全相同的参数再次运行。

目前我有这样的事情:

$rows = array();
$this->statement = $this->db->prepare($query);
$this->statement->bind_param('i',$id);
$this->statement->execute();
$this->statement->bind_result($result);
while($this->statement->fetch())
{
   $rows[] = $result;
}

我知道这不能如我所愿,我的问题是如何从查询中取回数据。是否可以通过列名将列带回关联数组中,就像标准的 mysqli 查询一样?

【问题讨论】:

    标签: php mysqli prepared-statement


    【解决方案1】:

    我不希望使用eval,这是我的解决方案(类似于ashurexm):

    $md = $stmt -> result_metadata();
    $fields = $md -> fetch_fields();
    $result = new stdClass(); // Actual result object
    $params = array(); // Array of fields passed to the bind_result method
    foreach($fields as $field) {
        $result -> {$field -> name} = null;
        $params[] = &$result -> {$field -> name};
    }
    call_user_func_array(array($stmt, 'bind_result'), $params);
    

    【讨论】:

      【解决方案2】:

      使用 VolkerK 对 mysqli_statement->result_metadata() 的建议,我能够将以下代码组合在一起来完成我正在寻找的工作,尽管性能并不比使用标准查询快。我得到statement->result_metadata() 来构建一个关联数组来调用bind_result。我将一个 bind_result 语句构建为一个字符串和 eval 它。我知道这不是特别安全,但这是我的第一次通行证。

      public function executePreparedStatement()
      {
          if($this->statement->execute())
          {
              $this->record = array();
              $md = $this->statement->result_metadata();
              $fields = $md->fetch_fields();
      
              $bindResult = '$this->statement->bind_result(';
              foreach($fields as $field)
              {
                  $bindResult .= "\$this->record['" . $field->name . "'],";
              }
      
              $bindResult = substr($bindResult,0,strlen($bindResult) - 1) . ');';
      
              eval($bindResult);
              return true;
          }
          else
          {
              $this->error = $this->db->error;
              return false;
          }
      }
      
          ...
          $this->prepareStatement($query);
          $this->bindParameter('i',$runId);
          if($this->executePreparedStatement())
          {
              $report = new Report();
              while($this->statement->fetch())
              {
                  $row = $this->record;
                  $line = array();
                  foreach($row as $key => &$value)
                  {
                      array_push($line,$value);
                  }
                  $report->addLine($line);
              }
              return $report          
          }
      

      【讨论】:

      • 我很想知道这是否会被视为解决我的问题的“坏”方法?糟糕的不安全(我认为是因为评估,但如果上游有适当的卫生设施,这可以吗?),或者糟糕的表现不佳。查询本身是最多 15 个表的 JOIN,所有表都由一个列链接,并按它们共享的另一列排序。如问题中所述,请求的列可能多达 300 多个。数据库是 MySQL InnoDB,在连接上具有索引并按列排序。
      • 我在这一行$bindResult = "$stmt->statement->bind_result("; 上遇到了一个未定义的属性错误,必须在开头添加一个\,所以它是这样的:$bindResult = "\$stmt->statement->bind_result("; 而且我自己也没有使用它功能,所以也有一些其他的问题。我是 PHP 新手,我只是想显示表格的内容。这似乎比应该做的要难得多。有什么建议吗?
      【解决方案3】:

      这就是为什么 mysqli 不应该与准备好的语句一起使用的原因。
      因此,您必须改用 PDO,这将使您的 executePreparedStatement() 变为 行:

      function executePreparedStatement($sql,$params) {
          $stm = $this->db->prepare($sql);
          $stm->execute($params);
          return $stm->fetchAll();
      }
      

      这样使用

      $sql  = "SELECT * from news WHERE category=?";
      $data = $this->executePreparedStatement($sql,$_GET['category']);
      

      【讨论】:

        猜你喜欢
        • 2012-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-01
        • 2013-02-08
        • 1970-01-01
        • 2011-01-23
        相关资源
        最近更新 更多