Я работаю с 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; } }
Похоже, вы пытаетесь построить длинную (?) Серию «или» сравнений: if (x=1) or (x=2) or (x=3) etc...
. 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++ }
У вас есть несоответствие между количеством связанных параметров и количеством привязок в 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);
Позиционные параметры в SQL начинаются с 1. Вы обрабатываете это путем привязки к позиции $i+1
в вашем цикле $ options.
Но затем вы привязываете последний параметр для cidades_codigo
к count($options)
позиции count($options)
, который перезаписывает последний набор параметров в цикле $ options.
Вам нужно привязать последний параметр к count($options)+1
позиции 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 для исключения исключений при ошибке.
Я столкнулся с этой проблемой из-за наличия дополнительных записей в массиве сопоставления именованных параметров, переданных в 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
Так как вы сделали $i+1
в цикле, поэтому count($options)
будет равен последнему $i+1
который делает дубликат привязки. Попробуйте
foreach($options as $i => $option) { $statement->bindValue($i + 1, $option->getId()); } $statement->bindValue(count($options)+1, $city->getId());