Comment utiliser correctement un objet PDO pour une requête SELECT paramétrée

85

J'ai essayé de suivre les instructions de PHP.net pour faire des SELECTrequêtes mais je ne suis pas sûr de la meilleure façon de procéder.

Je voudrais utiliser une SELECTrequête paramétrée , si possible, pour renvoyer le IDdans une table où le namechamp correspond au paramètre. Cela devrait en renvoyer un IDcar il sera unique.

Je voudrais ensuite utiliser cela IDpour une INSERTautre table, donc je devrai déterminer si cela a réussi ou non.

J'ai également lu que vous pouvez préparer les requêtes pour la réutilisation, mais je ne savais pas comment cela pouvait aider.

Joe Phillips
la source

Réponses:

158

Vous sélectionnez des données comme celles-ci:

$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

Vous insérez de la même manière:

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

Je vous recommande de configurer PDO pour lancer des exceptions en cas d'erreur. Vous obtiendrez alors un PDOExceptionsi l'une des requêtes échoue - Pas besoin de vérifier explicitement. Pour activer les exceptions, appelez ceci juste après avoir créé l' $dbobjet:

$db = new PDO("...");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
troelskn
la source
Je suppose que vous voulez dire PDOStatement où vous avez un nouvel AOP (...), non?
Joe Phillips
1
non. PDO est la classe de connexion (devrait probablement avoir été nommée PdoConnection à la place). La connexion peut créer des PdoStatements. Vous appelez setAttribute () sur l'objet de connexion - pas les instructions individuelles. (Vous pouvez également le transmettre au constructeur)
troelskn
1
cela pourrait être utile:$db = new PDO('mysql:dbname=your_database;host=localhost', 'junior', '444');
Junior Mayhé
2
Pour la ligne $statement->execute(array(':name' => "Jimbo"));, pouvez-vous expliquer la partie Jimbo?
muttley91
1
@rar Sur la ligne précédente, la requête est lancée avec un espace réservé :name. L'appel executeici se fait avec un tableau associatif de paires d'espace réservé -> valeurs. Donc, dans ce cas, l' :nameespace réservé sera remplacé par la chaîne Jimbo. Notez qu'il ne s'agit pas simplement d'un remplacement de chaîne, car la valeur est soit échappée, soit envoyée sur un canal différent de la requête réelle, empêchant ainsi tout type d'attaque par injection.
troelskn
16

J'ai travaillé avec PDO ces derniers temps et la réponse ci-dessus est tout à fait correcte, mais je voulais juste documenter que ce qui suit fonctionne également.

$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
la source
16
Non, ce n'est pas le cas, car vous n'avez pas sélectionné la base de données à utiliser.
Rápli András
3
Cela devrait en fait être dans la chaîne "server", qui devrait en fait être un DSN sous la forme "{driver}: dbname = {db_name}; host = {server}" en remplaçant les valeurs d'accolade par ce dont votre connexion a besoin
thorne51
12

Vous pouvez utiliser les méthodes bindParamou bindValuepour vous aider à préparer votre relevé. Cela rend les choses plus claires à première vue au lieu de le faire $check->execute(array(':name' => $name));Surtout si vous liez plusieurs valeurs / variables.

Consultez l'exemple clair et facile à lire ci-dessous:

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

Si vous attendez plusieurs lignes, supprimez le LIMIT 1et modifiez la méthode de récupération en 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
la source
Pas certain. Cela me semble une réponse valable. Je pense qu'il serait avantageux d'utiliser «myname» au lieu de «name» et d'utiliser également plusieurs paramètres au lieu d'un seul.
Joe Phillips
@GillianLoWong Que fait le $check = $q->fetch(PDO::FETCH_ASSOC); if (!empty($check)){ $row_id = $check['id']; // do something }?
Abdul
1
Salut @abdul, j'ai remplacé le compte / chèque vide sur le tableau. Il était censé voir si des résultats étaient renvoyés. Mais pdo a également une fonction appelée rowCount () qui vous permet de vérifier si des lignes ont été affectées / récupérées. Il est inutile de récupérer des données si vous ne savez même pas si des lignes ont été sélectionnées, j'ai donc déplacé l'instruction fetch dans l'instruction if rowCount (). :)
Gilly
@Gillian La Wong merci pour votre requête propre de bindValue pour la requête multiple where. qui sauvent mon projet.
php-coder
6

Une petite réponse complète est ici avec tout prêt à l'emploi:

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

 echo $done[0];

Voici le $dbhconnecteur PDO db, et basé sur le idtableau, usersnous obtenons l' usernameutilisationfetch();

J'espère que cela aidera quelqu'un, profitez-en!

Domuta Marcel
la source
Ou utilisez fetchColumn()pour éviter d' [0]être nécessaire. N'oubliez pas non plus d'utiliser LIMIT 1dans le SQL.
rybo111 du
3

Méthode 1: Utiliser la méthode de requête PDO

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

Obtenir le nombre de lignes

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

Méthode 2: déclarations avec paramètres

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

Méthode 3: Lier les paramètres

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

Vous voulez en savoir plus regardez ce lien

Sudhir
la source
4
Veuillez supprimer la méthode 1. Elle permet l'injection mysql.
Tomahock
-2

si vous utilisez le codage en ligne sur une seule page et que vous n'utilisez pas Oups, allez avec cet exemple complet, cela vous aidera certainement

//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
la source
Bien que cet extrait de code puisse résoudre le problème, il n'explique pas pourquoi ni comment il répond à la question. S'il vous plaît inclure une explication de votre code , car cela contribue vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondez à la question aux lecteurs à l'avenir et que ces personnes pourraient ne pas connaître les raisons de votre suggestion de code. Signaleurs / réviseurs: pour les réponses de code uniquement telles que celle-ci, voter contre, ne pas supprimer!
Scott Weldon
Alors, que dois-je supprimer moi-même
Shiv Singh
Non, exactement le contraire. Je suis tombé sur ce message dans la file d'attente des messages de faible qualité , et la dernière partie de mon commentaire était donc de dire aux gens de ne pas voter pour la suppression. (La suggestion de rejeter à la place visait à provoquer des votes défavorables provisoires, qui seraient supprimés une fois votre message modifié.) Comme mentionné dans mon commentaire précédent, il serait préférable que vous ajoutiez une explication pour expliquer pourquoi vous avez suggéré le code que vous avez fait . En outre, cette question concerne les requêtes paramétrées, mais field > 6969semble codée en dur plutôt que paramétrée.
Scott Weldon