【问题标题】:Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in警告:PDOStatement::execute(): SQLSTATE[HY093]: 无效的参数号:绑定变量的数量与中的标记数量不匹配
【发布时间】:2010-04-26 12:59:53
【问题描述】:

我正在使用 PHP PDO,但遇到以下问题:

Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in /var/www/site/classes/enterprise.php on line 63

这是我的代码:

    public function getCompaniesByCity(City $city, $options = null) {
  $database = Connection::getConnection();

  if(empty($options)) {
   $statement = $database->prepare("SELECT * FROM `empresas` WHERE `empresas`.`cidades_codigo` = ?");
   $statement->bindValue(1, $city->getId());
  }
  else {
   $sql = "SELECT * FROM `empresas`
    INNER JOIN `prods_empresas` ON `prods_empresas`.`empresas_codigo` = `empresas`.`codigo` WHERE ";

   foreach($options as $option) {
    $sql .= '`prods_empresas`.`produtos_codigo` = ? OR ';
   }

   $sql = substr($sql, 0, -4);
   $sql .= ' AND `empresas`.`cidades_codigo` = ?';

   $statement = $database->prepare($sql);

   echo $sql;

   foreach($options as $i => $option) {
    $statement->bindValue($i + 1, $option->getId());
   }

   $statement->bindValue(count($options), $city->getId());
  }

  $statement->execute();

  $objects = $statement->fetchAll(PDO::FETCH_OBJ);
  $companies = array();

  if(!empty($objects)) {
   foreach($objects as $object) {
    $data = array(
     'id' => $object->codigo,
     'name' => $object->nome,
     'link' => $object->link,
     'email' => $object->email,
     'details' => $object->detalhes,
     'logo' => $object->logo
    );

    $enterprise = new Enterprise($data);
    array_push($companies, $enterprise);
   }

   return $companies;
  }
 }

【问题讨论】:

    标签: php database data-binding code-snippets


    【解决方案1】:

    您似乎正在尝试构建一长串(?)“或”比较:if (x=1) or (x=2) or (x=3) etc...。您可能会发现将其替换为:

    $cnt = count($options);
    if ($cnt > 0) {
       $placeholders = str_repeat(', ?', $cnt - 1);
       $sql .= 'WHERE '`prods_empresas`.`produtos_codigo` IN (?' . $placeholders . ')';
    }
    

    如果有 5 个选项,你会选择哪一个

     WHERE prods_empresas.produtos_condigo IN (?, ?, ?, ?, ?)
    

    然后将值绑定:

    $pos = 1;
    foreach ($options as $option) {
       $statement->bindValue($pos, $option->getId());
       $pos++
    }
    

    【讨论】:

      【解决方案2】:

      绑定参数的数量与 SQL 中的绑定数量不匹配。仔细检查?的数量和绑定参数的数量是否相同。

      此外,如果您尝试绑定不存在的参数,HY093 将显示:

      $stmt = "INSERT INTO table VALUES (:some_value)";
      $stmt->bindValue(':someValue', $someValue, PDO::PARAM_STR);
      

      看到:some_value:someValue 不匹配!解决方法是:

      $stmt = "INSERT INTO table VALUES (:some_value)";
      $stmt->bindValue(':some_value', $someValue, PDO::PARAM_STR);
      

      【讨论】:

        【解决方案3】:

        SQL 中的位置参数从 1 开始。您通过绑定到 $options 循环中的位置 $i+1 来处理这个问题。

        但是你将cidades_codigo 的最后一个参数绑定到count($options) 位置,这会覆盖$options 循环中的最后一个参数集。

        您需要将最后一个参数绑定到位置count($options)+1


        FWIW,你根本不需要bindValue()。将一组参数传递给execute() 会更容易。下面是我如何编写这个函数:

        public function getCompaniesByCity(City $city, $options = null) {
          $database = Connection::getConnection();
        
          $sql = "SELECT * FROM `empresas` WHERE `empresas`.`cidades_codigo` = ?"
        
          $params = array();
          $params[] = $city->getId();
        
          if ($options) {
            $sql .= " AND `prods_empresas`.`produtos_codigo` IN (" 
              . join(",", array_fill(1, count($options), "?") . ")";
            foreach ((array)$options as $option) {
              $params[] = $option->getId();
            }
          }
        
          $statement = $database->prepare($sql);
        
          echo $sql;
        
          $statement->execute($params);
          . . .
        

        另外一定要检查prepare()execute()的返回值,如果有错误会是false,你需要检查并报告错误。否则使 PDO 能够在出错时抛出异常。

        【讨论】:

          【解决方案4】:

          我遇到了这个问题,因为命名参数映射数组中有额外的条目传递给 PDO::Statement->execute()

          $args=array (":x" => 17 );
          $pdo->prepare("insert into foo (x) values (:x)");
          $pdo->execute($args); // success
          $args[':irrelevant']=23;
          $pdo->execute($args) // throws exception with HY093
          

          【讨论】:

          • 我不明白这是一个答案还是只是对 OP 的评论。你能改写一下吗?
          【解决方案5】:

          由于您在循环中创建了$i+1,因此count($options) 将等于最后一个$i+1,这会产生重复绑定。尝试

           foreach($options as $i => $option)
           { 
                $statement->bindValue($i + 1, $option->getId()); 
           }
          
           $statement->bindValue(count($options)+1, $city->getId()); 
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-04-27
            • 2012-08-10
            相关资源
            最近更新 更多