Предупреждение: PDOStatement :: execute (): SQLSTATE [HY093]: недопустимый номер параметра: число связанных переменных не соответствует количеству токенов в

Я работаю с 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;
}
}

7

Решение

Похоже, вы пытаетесь построить длинную (?) Серию сравнений ‘или’: 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);
2

Позиционные параметры в SQL начинаются с 1. Вы обрабатываете это, привязываясь к позиции $i+1 в вашем цикле $ options.

Но тогда вы связываете последний параметр для 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 выдавать исключения при ошибке.

0

Я столкнулся с этой проблемой из-за того, что дополнительные записи в массиве именованных параметров были переданы в 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
0

Так как вы сделали $i+1 в цикле так count($options) будет равна последнему $i+1 который делает дубликат связывания. Попробуйте

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

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