Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in

最后都变了- 提交于 2019-11-26 07:48:31

问题


I\'m working with PHP PDO and I have the following problem:

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

Here is my code:

    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;
  }
 }

回答1:


You have a mismatch between the amount of bound parameters and the amount of binds in the SQL. Double check that the amount of ? and the amount of bound parameters is the same.

Additionally, HY093 will show up if you have tried to bind a parameter that does not exist:

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

See that :some_value does not match :someValue! The fix is:

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



回答2:


It looks like you're trying to build a long(?) series of 'or' comparisons: if (x=1) or (x=2) or (x=3) etc.... You may find it easier to replace it with:

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

which, if there were 5 options, would give you

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

And then do the values binding with:

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



回答3:


Positional parameters in SQL start at 1. You're handling this by binding to position $i+1 in your $options loop.

But then you bind the last parameter for cidades_codigo to position count($options), which overwrites the last parameter set in the $options loop.

You need to bind the last parameter to position count($options)+1.


FWIW, you don't need to bindValue() at all. It's easier to just pass an array of parameters to execute(). Here's how I'd write this function:

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);
  . . .

Also be sure to check the return value of prepare() and execute(), it will be false if there's an error, and you need to check for that and report the error. Or else enable PDO to throw exceptions on error.




回答4:


I was running into this problem due to having extra entries in the named parameter mapping array passed to 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



回答5:


Since you have made $i+1 in the loop so count($options) would equal the last $i+1 which makes a duplicate binding.Try

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

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


来源:https://stackoverflow.com/questions/2713566/warning-pdostatementexecute-sqlstatehy093-invalid-parameter-number-num

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!