SQLSTATE[HY093]: Invalid parameter number,проблема с sql запросом

363
03 мая 2017, 12:11
public static function getSearchProductsListByCategory($value1,$value2,$categoryId, $page = 1)
{
    $limit = Product::SHOW_BY_DEFAULT;
    $offset = ($page - 1) * self::SHOW_BY_DEFAULT;
    $db = Db::getConnection();
    $sql = 'SELECT id, name, price, is_new FROM product '
            . 'WHERE price BETWEEN :value1 AND :value2 AND status = "1" AND category_id = :category_id'
            . 'ORDER BY id ASC LIMIT :limit OFFSET :offset';
    $result = $db->prepare($sql);
    $result->execute(array(":value1"=>$value1,":value2"=>$value2,":category_id"=>$categoryId,":limit"=>$limit,":offset"=>$offset));
    $i = 0;
    $products = array();
    while ($row = $result->fetch()) {
        $products[$i]['id'] = $row['id'];
        $products[$i]['name'] = $row['name'];
        $products[$i]['price'] = $row['price'];
        $products[$i]['is_new'] = $row['is_new'];
        $i++;
    }
    return $products;
}
Answer 1

Непосредственно ошибка: выведите на экран переменную $sql и увидите параметр под названием category_idORDER. Внимание на пробелы. Вообще редко доводится видеть построчно разбитый SQL через конкатенацию. Чаще его оформляют одним блоком текста в кавычках вот так:

 $sql = 'SELECT id, name, price, is_new FROM product 
        WHERE price BETWEEN :value1 AND :value2 AND status = "1" AND category_id = :category_id
        ORDER BY id ASC LIMIT :limit OFFSET :offset';

С указанием limit и offset через параметры есть некоторая проблема в комбинация фактов:

  • SQL-парсер mysql считает, и довольно обоснованно, что limit и offset должны быть строго числами
  • PHP PDO по-умолчанию использует эмуляцию подготовленных выражений
  • execute с передачей массива всех параметров - дико удобно, но ориентирован только на строковые параметры

В итоге PHP подставляет строки в запрос вместо чисел, получается limit '10' (даже если тип переменной был числовой, да), на что очень обижается парсер. Парсер mysql изменять как-то несподручно, поэтому остаётся два варианта:

  • выключить эмуляцию подготовленных выражений:

    $pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
    

    Для mysql однозначных минусов такого решения назвать не могу.

  • привязывать параметры с явным указанием числового типа:

    $stmt->bindValue(':lim', (int) $limit, \PDO::PARAM_INT);
    

И у вас какой-то очень странный и слишком многословный return $result->fetchAll(); написан в конце метода.

READ ALSO
Как switch вынести в отдельный файл?

Как switch вынести в отдельный файл?

Можно ли switch вынести в отдельный файл, учитывая то, что он находится в другом switch? Просто в основном файле получается слишком много кода, хотелось...

361
sha256 C# PHP почему разные хэши?

sha256 C# PHP почему разные хэши?

Сразу предупреждаю, в С# я не понимаю но как я понял должно было бы быть так $hash = hash_hmac('sha256',$password,$salt,true);

324
функция ofstream c++

функция ofstream c++

Как реализовать чтобы при каждой новой итерации цикла с функцией ofstream менялось название файлаtxt

331
Почему ругается компоновщик?

Почему ругается компоновщик?

В чём проблема? Проясните пожалуйста нубуВ первый раз создаю многофайловый проект

319