Як я можу правильно використовувати об’єкт 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заповнювач буде замінено на рядок Джимбо. Зверніть увагу, що це не просто заміна рядка, оскільки значення або екрановане, або відправлене за іншим каналом від фактичного запиту, таким чином запобігаючи будь-яким атакам введення.
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}", замінюючи значення фігурних
дужок на

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, я замінив перевірку count / empty на масиві. Передбачалось перевірити, чи повернуто якісь результати. Але pdo також має функцію з назвою rowCount (), яка дозволяє перевірити, чи не було вплинуто / вилучено якісь рядки взагалі. Немає сенсу отримувати дані, якщо ви навіть не знаєте, чи були вибрані будь-які рядки, тому я перемістив оператор отримання в оператор if rowCount (). :)
Гіллі

@Gillian La Wong дякує за ваш чистий запит bindValue для кількох запитів, де. що рятують мій проект.
php-кодер

6

Тут є невелика повна відповідь із усіма готовими до використання:

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

 echo $done[0];

Ось $dbhPDO db connecter, і, виходячи idз таблиці, usersми отримали usernameвикористанняfetch();

Сподіваюся, це комусь допоможе, насолоджуйтесь!


Або використовуйте, fetchColumn()щоб уникнути [0]необхідності. Також пам’ятайте про використання LIMIT 1в SQL.
rybo111

3

Метод 1: USE PDO query method

$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.