#php #sql #mysqli
#php #sql #mysqli
Вопрос:
У меня есть эта функция в PHP. Я пытаюсь вставить (если это необходимо), а затем получить app_id из таблицы.
private function addApp($bundle_identifier,$os_id) {
$driver = new mysqli_driver();
$driver->report_mode = MYSQLI_REPORT_ALL;
//Insert or update app details
if ($stmt = $this->db->prepare("INSERT IGNORE INTO app (app_identifier,os_id) VALUES (?,?); SELECT app_id FROM app WHERE app_identifier = ? AND os_id = ?")){
$stmt->bind_param("ssss", $bundle_identifier,$os_id,$bundle_identifier,$os_id);
$stmt->execute();
$stmt->bind_result($app_id);
if (!isset($app_id)) {
echo "is set";
$app_id=$stmt->insert_id;
}
}
if($this->db->commit()){
return $app_id;
}
return 0;
}
Проблема здесь в том, что stmt всегда имеет значение false с ошибкой:
Неперехваченное исключение ‘mysqli_sql_exception’ с сообщением ‘У вас ошибка в вашем синтаксисе SQL; проверьте руководство, соответствующее вашей версии сервера MySQL, чтобы найти правильный синтаксис для использования рядом ‘ВЫБЕРИТЕ app_id ИЗ приложения, ГДЕ app_identifier = ? И os_id = ?’ в строке 1′
Странно то, что этот запрос отлично работает в моем SQL. Это ограничение mysqli?
Комментарии:
1. Я думаю,
execute
выполняется один оператор, а не несколько операторов.2. Примечание:
if (!isset($app_id)) { echo "is set";
противоречиво.3. @Fred-ii- это для целей тестирования
4. Какой результат вы привязываете? Вы
INSERTING
и неSELECTING
.5. Я выбираю в конце запроса. В этом проблема
Ответ №1:
Согласно http://php.net/manual/en/mysqli.prepare.php :
Запрос должен состоять из одного оператора SQL.
Что в основном отвечает на ваш вопрос. Вы должны использовать два вызова db для двух запросов. Или используйте что-то вродеhttp://php.net/manual/en/mysqli.multi-query.php
Приведенное ниже приведено только для информации, поскольку оно относится к PDO, в то время как вопрос касается mysqli. Хотя в целом это полезно.
Я думаю, что причина, по которой это работает в mysql, но не в mysqli, заключается в том, что последний поддерживает подготовленные операторы изначально, в то время как первый использует эмуляцию. Поскольку ваше выражение содержит два запроса, все связанные параметры задаются драйвером для первого запроса (из которых использует два и отбрасывает два других). Затем второй запрос не получает параметров, и поэтому вопросительные знаки являются синтаксическими ошибками. С помощью эмуляции подготовленных операторов PHP фактически заменяет вопросительные знаки правильно экранированными значениями и, таким образом, формирует два допустимых запроса.
Вы можете включить эмуляцию с помощью $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true)
, однако это может немного повлиять на производительность.
Смотрите также http://www.php.net/manual/en/pdo.setattribute.php
Комментарии:
1. Спасибо за ваш ответ. Я попробовал это и теперь получаю эту ошибку:
Call to undefined method mysqli::setAttribute()
2. правильно… По какой-то причине я думал, что вы используете PDO — отсюда ссылка на функцию PDO и константу. Я не думаю, что низкоуровневый драйвер mysqli поддерживает подобную эмуляцию. Таким образом, вы можете либо поместить значения в запрос напрямую (как я вижу, это числа, поэтому вы можете сделать запрос безопасным, применив
intval
к переменным перед отправкой их в запрос), либо разделить это на два вызова db.3. Я даже пытался жестко запрограммировать результаты, но ничего не происходит. Как только я удалил «ВЫБРАТЬ», все работает нормально.
4. @BlackM Я обновил ответ. В документации четко указано, что «подготовить» работает только с одним запросом.