Jak prawidłowo użyć obiektu PDO dla sparametryzowanego zapytania SELECT

85

Próbowałem postępować zgodnie z instrukcjami PHP.net dotyczącymi wykonywania SELECTzapytań, ale nie jestem pewien, jak najlepiej to zrobić.

Chciałbym SELECT, jeśli to możliwe, użyć sparametryzowanego zapytania, aby zwrócić IDw tabeli, w której namepole pasuje do parametru. To powinno zwrócić jeden, IDponieważ będzie unikalny.

Chciałbym następnie jak korzystać z tego IDza INSERTw innej tabeli, więc będzie trzeba ustalić, czy to był udany, czy nie.

Czytałem również, że możesz przygotować zapytania do ponownego wykorzystania, ale nie byłem pewien, jak to pomaga.

Joe Phillips
źródło

Odpowiedzi:

158

Wybierasz takie dane:

$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

Wstawiasz w ten sam sposób:

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

Zalecam skonfigurowanie PDO do zgłaszania wyjątków w przypadku błędu. Otrzymasz wtedy, PDOExceptionjeśli którekolwiek z zapytań zakończy się niepowodzeniem - nie ma potrzeby jawnego sprawdzania. Aby włączyć wyjątki, wywołaj to zaraz po utworzeniu $dbobiektu:

$db = new PDO("...");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
troelskn
źródło
Zakładam, że masz na myśli PDOStatement, w którym masz nowe PDO (...), prawda?
Joe Phillips
1
Nie. PDO to klasa połączenia (prawdopodobnie powinna była nazywać się PdoConnection). Połączenie może tworzyć PdoStatements. Wywołujesz metodę setAttribute () w obiekcie połączenia, a nie w poszczególnych instrukcjach. (Alternatywnie możesz przekazać to konstruktorowi)
troelskn
1
może się to przydać:$db = new PDO('mysql:dbname=your_database;host=localhost', 'junior', '444');
Junior Mayhé,
2
Dla linii $statement->execute(array(':name' => "Jimbo"));, można wyjaśnić udział Jimbo?
muttley91,
1
@rar W poprzednim wierszu zapytanie jest inicjowane za pomocą symbolu zastępczego :name. Wywołanie executetutaj odbywa się za pomocą asocjacyjnej tablicy symboli zastępczych -> par wartości. Zatem w tym przypadku :namesymbol zastępczy zostanie zastąpiony ciągiem znaków Jimbo. Zwróć uwagę, że nie polega to po prostu na zamianie ciągu znaków, ponieważ wartość jest albo uciekana, albo wysyłana innym kanałem niż rzeczywiste zapytanie, zapobiegając w ten sposób wszelkiego rodzaju atakom iniekcyjnym.
troelskn
16

Ostatnio pracowałem z PDO i powyższa odpowiedź jest całkowicie prawidłowa, ale chciałem tylko udokumentować, że poniższe działa również.

$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();
SmashCode
źródło
16
Nie, nie jest, ponieważ nie wybrałeś bazy danych, której chcesz użyć.
Rápli András
3
Powinien on znajdować się w ciągu „server”, który powinien być nazwą DSN w postaci „{driver}: dbname = {db_name}; host = {server}”, zastępując wartości nawiasów klamrowych wszelkimi potrzebami połączenia
thorne51
12

Aby przygotować oświadczenie, możesz skorzystać z metod bindParamlub bindValue. Sprawia to, że rzeczy są bardziej jasne na pierwszy rzut oka, zamiast robić. $check->execute(array(':name' => $name));Szczególnie, jeśli wiążesz wiele wartości / zmiennych.

Sprawdź jasny, łatwy do odczytania przykład poniżej:

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

Jeśli spodziewasz się wielu wierszy, usuń LIMIT 1i zmień metodę pobierania na 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
}
Gilly
źródło
Niepewny. Wydaje mi się, że to ważna odpowiedź. Myślę, że przydałoby się użycie „myname” zamiast „name”, a także użycie wielu parametrów zamiast tylko jednego.
Joe Phillips
@GillianLoWong Co robi $check = $q->fetch(PDO::FETCH_ASSOC); if (!empty($check)){ $row_id = $check['id']; // do something }?
Abdul
1
Cześć @abdul, zamieniłem licznik / pusty czek na tablicy. Miał sprawdzić, czy zwrócono jakiekolwiek wyniki. Ale pdo ma również funkcję o nazwie rowCount (), która pozwala sprawdzić, czy jakiekolwiek wiersze zostały w ogóle dotknięte / pobrane. Pobieranie danych nie ma sensu, jeśli nawet nie wiesz, czy wybrano jakiekolwiek wiersze, więc przeniosłem instrukcję fetch do instrukcji if rowCount (). :)
Gilly
@Gillian La Wong dziękuję za czyste zapytanie bindValue dla wielu zapytań gdzie. które uratują mój projekt.
php-coder
6

Trochę kompletna odpowiedź jest tutaj, a wszystko jest gotowe do użycia:

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

 echo $done[0];

Oto $dbhłącznik db PDO i na podstawie idtabeli usersotrzymaliśmy usernameużyciefetch();

Mam nadzieję, że komuś to pomoże, ciesz się!

Domuta Marcel
źródło
Lub użyj, fetchColumn()aby uniknąć [0]potrzeby. Pamiętaj też, aby używać LIMIT 1w SQL.
rybo111
3

Metoda 1: Metoda zapytania USE PDO

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

Pobieranie liczby wierszy

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

Metoda 2: Instrukcje z parametrami

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

Metoda 3: Powiązanie parametrów

$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);

Chcesz wiedzieć więcej, spójrz na ten link

Sudhir
źródło
4
Usuń metodę 1. Umożliwia iniekcję mysql.
Tomahock
-2

jeśli używasz kodowania wbudowanego na jednej stronie i nie używasz oops, to przejdź do tego pełnego przykładu, z pewnością pomoże

//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 />";
}
Shiv Singh
źródło
Chociaż ten fragment kodu może rozwiązać problem, nie wyjaśnia, dlaczego ani jak odpowiada na pytanie. Dołącz wyjaśnienie swojego kodu , ponieważ naprawdę pomaga to poprawić jakość Twojego postu. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a osoby te mogą nie znać powodów, dla których zaproponowałeś kod. Osoby zgłaszające / recenzenci: w przypadku odpowiedzi zawierających tylko kod, takich jak ta, głosuj przeciw, nie usuwaj!
Scott Weldon,
Więc co powinienem usunąć samemu
Shiv Singh
Nie, dokładnie odwrotnie. Natknąłem się na ten post w kolejce postów niskiej jakości , więc ostatnia część mojego komentarza miała na celu poinformowanie ludzi, aby nie głosowali za usunięciem. (Sugestia, aby zamiast tego głosować przeciw, miała na celu zachęcenie do tymczasowych głosów przeciw, które zostałyby usunięte po edycji twojego postu). Jak wspomniałem w moim poprzednim komentarzu, byłoby lepiej, gdybyś dodał wyjaśnienie, dlaczego zasugerowałeś kod, który zrobiłeś . To pytanie dotyczy również zapytań sparametryzowanych, ale field > 6969wygląda na zakodowane, a nie sparametryzowane.
Scott Weldon