¿Cómo puedo usar correctamente un objeto PDO para una consulta SELECT parametrizada?

85

Intenté seguir las instrucciones de PHP.net para realizar SELECTconsultas, pero no estoy seguro de cuál es la mejor manera de hacerlo.

Me gustaría usar una SELECTconsulta parametrizada , si es posible, para devolver el IDen una tabla donde el namecampo coincide con el parámetro. Esto debería devolver uno IDporque será único.

Luego me gustaría usar eso IDpara una INSERTtabla en otra, así que tendré que determinar si fue exitoso o no.

También leí que puede preparar las consultas para su reutilización, pero no estaba seguro de cómo esto ayuda.

Joe Phillips
fuente

Respuestas:

158

Selecciona datos como este:

$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

Se inserta de la misma manera:

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

Le recomiendo que configure PDO para generar excepciones en caso de error. Luego, obtendría un PDOExceptionsi alguna de las consultas falla: no es necesario verificar explícitamente. Para activar las excepciones, llame a esto justo después de haber creado el $dbobjeto:

$db = new PDO("...");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
troelskn
fuente
Supongo que te refieres a PDOStatement donde tienes un nuevo PDO (...), ¿verdad?
Joe Phillips
1
No. PDO es la clase de conexión (probablemente debería haberse llamado PdoConnection en su lugar). La conexión puede crear PdoStatements. Llamas a setAttribute () en el objeto de conexión, no en las declaraciones individuales. (Alternativamente, puede pasarlo al constructor)
troelskn
1
esto podría ser útil:$db = new PDO('mysql:dbname=your_database;host=localhost', 'junior', '444');
Junior Mayhé
2
Para la línea $statement->execute(array(':name' => "Jimbo"));, ¿puedes explicar la parte de Jimbo?
muttley91
1
@rar En la línea anterior, la consulta se inicia con un marcador de posición :name. La llamada executeaquí se realiza con una matriz asociativa de marcadores de posición -> pares de valores. Entonces, en este caso, el :namemarcador de posición se reemplazará con la cadena Jimbo. Tenga en cuenta que no se trata simplemente de un reemplazo de cadena, ya que el valor se escapa o se envía a través de un canal diferente al de la consulta real, evitando así cualquier tipo de ataques de inyección.
troelskn
16

He estado trabajando con PDO últimamente y la respuesta anterior es completamente correcta, pero solo quería documentar que lo siguiente también funciona.

$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
fuente
16
No, no es así, ya que no ha seleccionado qué base de datos usar.
Rápli András
3
En realidad, debería estar en la cadena "servidor", que en realidad debería ser un DSN en la forma de "{controlador}: dbname = {db_name}; host = {servidor}" reemplazando los valores de las
llaves
12

Puede utilizar los métodos bindParamo bindValuepara ayudar a preparar su declaración. Hace las cosas más claras a primera vista en lugar de hacerlo, $check->execute(array(':name' => $name));especialmente si está vinculando múltiples valores / variables.

Consulte el ejemplo claro y fácil de leer a continuación:

$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 espera varias filas, elimine LIMIT 1y cambie el método de recuperación a 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
fuente
No estoy seguro. Me parece una respuesta válida. Creo que se beneficiaría de usar 'myname' en lugar de 'name' y también usar múltiples parámetros en lugar de solo uno.
Joe Phillips
@GillianLoWong ¿Qué hace el $check = $q->fetch(PDO::FETCH_ASSOC); if (!empty($check)){ $row_id = $check['id']; // do something }?
Abdul
1
Hola @abdul, he reemplazado el recuento / verificación vacía en la matriz. Se suponía que debía ver si se obtenían resultados. Pero pdo también tiene una función llamada rowCount () que le permite verificar si alguna fila se vio afectada / recuperada. No tiene sentido buscar datos si ni siquiera sabe si se seleccionó alguna fila, así que moví la declaración de recuperación a la declaración if rowCount (). :)
Gilly
@Gillian La Wong gracias por su consulta limpia de bindValue para múltiples consultas where. que salvan mi proyecto.
php-coder
6

Una pequeña respuesta completa está aquí con todo listo para usar:

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

 echo $done[0];

Aquí $dbhestá el conector PDO db, y según la idtabla users, obtenemos el usernameusofetch();

Espero que esto ayude a alguien, ¡Disfruta!

Domuta Marcel
fuente
O utilícelo fetchColumn()para evitar [0]ser necesitado. Además, recuerde utilizar LIMIT 1en SQL.
rybo111
3

Método 1: USE el método de consulta PDO

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

Obtener el recuento de filas

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

Método 2: declaraciones con parámetros

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

Método 3: enlazar parámetros

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

Quieres saber más mira este enlace

Sudhir
fuente
4
Elimine el método 1. Permite la inyección de mysql.
Tomahock
-2

Si está usando codificación en línea en una sola página y no usa oops, vaya con este ejemplo completo, seguramente ayudará

//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
fuente
Si bien este fragmento de código puede resolver el problema, no explica por qué ni cómo responde a la pregunta. Por favor, incluya una explicación de su código , como que realmente ayuda a mejorar la calidad de su puesto. Recuerde que está respondiendo a la pregunta para los lectores en el futuro, y es posible que esas personas no conozcan los motivos de su sugerencia de código. Marcadores / revisores: para respuestas de solo código como esta, ¡no elimine!
Scott Weldon
Entonces, ¿qué debería eliminarlo yo mismo?
Shiv Singh
No, exactamente lo contrario. Encontré esta publicación en la cola de publicaciones de baja calidad , por lo que la última parte de mi comentario fue para decirle a la gente que no votara para eliminar. (En cambio, la sugerencia de votar negativamente tenía como objetivo generar votos negativos provisionales, que se eliminarían después de que se haya editado su publicación). Como mencioné en mi comentario anterior, sería mejor si agregara una explicación de por qué sugirió el código que hizo . Además, esta pregunta se refiere a consultas parametrizadas, pero field > 6969parece estar codificada en lugar de parametrizada.
Scott Weldon