Как правильно использовать объект PDO для параметризованного запроса SELECT


85

Я пробовал следовать инструкциям PHP.net для выполнения SELECTзапросов, но я не уверен, как лучше это сделать.

Я хотел бы использовать параметризованный SELECTзапрос, если это возможно, чтобы вернуть IDв таблице, где nameполе соответствует параметру. Он должен вернуть один, IDпотому что он будет уникальным.

Затем я хотел бы использовать это IDдля INSERTдругой таблицы, поэтому мне нужно будет определить, было ли это успешным или нет.

Я также читал, что вы можете подготовить запросы для повторного использования, но я не знал, как это помогает.

Ответы:


158

Вы выбираете данные так:

$db = new PDO("...");
$statement = $db->prepare("select id from some_table where name = :name");
$statement->execute(array(':name' => "Jimbo"));
$row = $statement->fetch(); // Use fetchAll() if you want all results, or just iterate over the statement, since it implements Iterator

Таким же образом вставляешь:

$statement = $db->prepare("insert into some_other_table (some_id) values (:some_id)");
$statement->execute(array(':some_id' => $row['id']));

Я рекомендую вам настроить PDO на создание исключений при ошибке. Затем вы получите сообщение, PDOExceptionесли какой-либо из запросов завершится ошибкой - нет необходимости явно проверять. Чтобы включить исключения, вызовите это сразу после создания $dbобъекта:

$db = new PDO("...");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Я полагаю, вы имеете в виду PDOStatement, где у вас есть новый PDO (...), верно?
Джо Филлипс,

1
нет. PDO - это класс подключения (вместо этого, вероятно, должен был называться PdoConnection). Соединение может создавать PdoStatements. Вы вызываете setAttribute () для объекта подключения, а не для отдельных операторов. (Как вариант, вы можете передать его конструктору)
troelskn

1
это может быть полезно:$db = new PDO('mysql:dbname=your_database;host=localhost', 'junior', '444');
Junior Mayhé

2
Что касается линии $statement->execute(array(':name' => "Jimbo"));, не могли бы вы объяснить часть Джимбо?
muttley91

1
@rar В предыдущей строке запрос инициируется с заполнителем :name. Вызов executeздесь выполняется с помощью ассоциативного массива пар заполнитель -> значение. Так что в этом случае :nameзаполнитель будет заменен строкой Jimbo. Обратите внимание, что это не просто замена строки, так как значение либо экранируется, либо отправляется по другому каналу, отличному от фактического запроса, что предотвращает любые атаки инъекций.
troelskn

16

В последнее время я работал с PDO, и приведенный выше ответ полностью верен, но я просто хотел задокументировать, что следующее также работает.

$nametosearch = "Tobias";
$conn = new PDO("server", "username", "password");
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sth = $conn->prepare("SELECT `id` from `tablename` WHERE `name` = :name");
$sth->bindParam(':name', $nametosearch);
// Or sth->bindParam(':name', $_POST['namefromform']); depending on application
$sth->execute();

16
Нет, так как вы не выбрали, какую базу данных использовать.
Рапли Андраш

3
На самом деле это должно быть в строке «server», которая на самом деле должна быть DSN в форме «{driver}: dbname = {db_name}; host = {server}», заменяя значения фигурных скобок на то, что нужно вашему соединению
thorne51

12

Вы можете использовать методы bindParamили, bindValueчтобы подготовить заявление. Это делает вещи более ясными на первый взгляд, а не делает. $check->execute(array(':name' => $name));Особенно, если вы привязываете несколько значений / переменных.

Посмотрите на понятный и легко читаемый пример ниже:

$q = $db->prepare("SELECT id FROM table WHERE forename = :forename and surname = :surname LIMIT 1");
$q->bindValue(':forename', 'Joe');
$q->bindValue(':surname',  'Bloggs');
$q->execute();

if ($q->rowCount() > 0){
    $check = $q->fetch(PDO::FETCH_ASSOC);
    $row_id = $check['id'];
    // do something
}

Если вы ожидаете, что несколько строк, удалите LIMIT 1и измените метод выборки на fetchAll:

$q = $db->prepare("SELECT id FROM table WHERE forename = :forename and surname = :surname");// removed limit 1
$q->bindValue(':forename', 'Joe');
$q->bindValue(':surname',  'Bloggs');
$q->execute();

if ($q->rowCount() > 0){
    $check = $q->fetchAll(PDO::FETCH_ASSOC);
    //$check will now hold an array of returned rows. 
    //let's say we need the second result, i.e. index of 1
    $row_id = $check[1]['id']; 
    // do something
}

Не уверена. Мне кажется, это верный ответ. Я думаю, было бы полезно использовать myname вместо name, а также использовать несколько параметров вместо одного.
Джо Филлипс,

@GillianLoWong Что делает $check = $q->fetch(PDO::FETCH_ASSOC); if (!empty($check)){ $row_id = $check['id']; // do something }?
Абдул

1
Привет @abdul, я заменил счетчик / пустую проверку в массиве. Предполагалось, что будут получены какие-либо результаты. Но в pdo также есть функция rowCount (), которая позволяет вам проверить, были ли затронуты / извлечены какие-либо строки вообще. Нет смысла извлекать данные, если вы даже не знаете, были ли выбраны какие-либо строки, поэтому я переместил оператор выборки в оператор if rowCount (). :)
Gilly

@Gillian La Wong благодарит за ваш чистый запрос bindValue для множественного запроса where. которые спасают мой проект.
php-coder

6

Небольшой полный ответ здесь, все готово к использованию:

    $sql = "SELECT `username` FROM `users` WHERE `id` = :id";
    $q = $dbh->prepare($sql);
    $q->execute(array(':id' => "4"));
    $done= $q->fetch();

 echo $done[0];

Вот $dbhсоединитель PDO db, и на основе idтаблицы usersмы получили usernameиспользованиеfetch();

Надеюсь, это кому-то поможет, наслаждайтесь!


Или используйте, fetchColumn()чтобы избежать [0]необходимости. Также не забудьте использовать LIMIT 1в SQL.
rybo111

3

Метод 1: метод запроса USE PDO

$stmt = $db->query('SELECT id FROM Employee where name ="'.$name.'"');
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);

Получение количества строк

$stmt = $db->query('SELECT id FROM Employee where name ="'.$name.'"');
$row_count = $stmt->rowCount();
echo $row_count.' rows selected';

Метод 2: утверждения с параметрами

$stmt = $db->prepare("SELECT id FROM Employee WHERE name=?");
$stmt->execute(array($name));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

Метод 3: привязать параметры

$stmt = $db->prepare("SELECT id FROM Employee WHERE name=?");
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

**bind with named parameters**
$stmt = $db->prepare("SELECT id FROM Employee WHERE name=:name");
$stmt->bindValue(':name', $name, PDO::PARAM_STR);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

or
$stmt = $db->prepare("SELECT id FROM Employee WHERE name=:name");
$stmt->execute(array(':name' => $name));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

Хотите узнать больше, посмотрите эту ссылку


4
Удалите метод 1. Он позволяет внедрять mysql.
Tomahock

-2

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

//connect to the db
$dbh = new PDO('mysql:host=localhost;dbname=mydb', dbuser, dbpw); 

//build the query
$query="SELECT field1, field2
FROM ubertable
WHERE field1 > 6969";

//execute the query
$data = $dbh->query($query);
//convert result resource to array
$result = $data->fetchAll(PDO::FETCH_ASSOC);

//view the entire array (for testing)
print_r($result);

//display array elements
foreach($result as $output) {
echo output[field1] . " " . output[field1] . "<br />";
}

Хотя этот фрагмент кода может решить проблему, он не объясняет, почему и как он отвечает на вопрос. Пожалуйста, включите объяснение вашего кода , так как это действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причины вашего предложения кода. Отметившие / обозреватели: для ответов только с кодом, таких как этот, голосуйте против, не удаляйте!
Скотт Велдон,

Так что же мне самому удалить?
Шив Сингх

Нет, как раз наоборот. Я наткнулся на этот пост в очереди постов низкого качества , и поэтому последняя часть моего комментария заключалась в том, чтобы сказать людям не голосовать за удаление. (Предложение о понижающем голосе вместо этого предназначалось для того, чтобы вызвать предварительные отрицательные голоса, которые будут удалены после редактирования вашего сообщения.) Как упоминалось в моем предыдущем комментарии, было бы лучше, если бы вы добавили объяснение, почему вы предложили код, который вы сделали . Кроме того, этот вопрос касается параметризованных запросов, но field > 6969выглядит жестко запрограммированным, а не параметризованным.
Скотт Велдон
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.