Como posso usar adequadamente um objeto PDO para uma consulta SELECT parametrizada

85

Eu tentei seguir as instruções do PHP.net para fazer SELECTconsultas, mas não tenho certeza da melhor maneira de fazer isso.

Gostaria de usar uma SELECTconsulta parametrizada , se possível, para retornar o IDem uma tabela onde o namecampo corresponde ao parâmetro. Isso deve retornar um IDporque será exclusivo.

Eu gostaria então de usar isso IDem uma INSERToutra tabela, então terei de determinar se foi bem-sucedido ou não.

Também li que você pode preparar as consultas para reutilização, mas não tinha certeza de como isso ajuda.

Joe Phillips
fonte

Respostas:

158

Você seleciona dados 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

Você insere da mesma maneira:

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

Recomendo que você configure o PDO para lançar exceções em caso de erro. Você obterá então um PDOExceptionse alguma das consultas falhar - Não há necessidade de verificar explicitamente. Para ativar as exceções, chame isso logo depois de criar o $dbobjeto:

$db = new PDO("...");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Troelskn
fonte
Suponho que você quer dizer PDOStatement onde você tem um PDO novo (...), certo?
Joe Phillips,
1
não. PDO é a classe de conexão (provavelmente deveria ter sido nomeada PdoConnection). A conexão pode criar PdoStatements. Você chama setAttribute () no objeto de conexão - não nas instruções individuais. (Como alternativa, você pode passá-lo para o construtor)
troelskn
1
isso pode ser útil:$db = new PDO('mysql:dbname=your_database;host=localhost', 'junior', '444');
Junior Mayhé
2
Para a linha $statement->execute(array(':name' => "Jimbo"));, você pode explicar a parte do Jimbo?
muttley91
1
@rar Na linha anterior, a consulta é iniciada com um espaço reservado :name. Chamar executeaqui é feito com uma matriz associativa de pares de espaço reservado -> valor. Portanto, neste caso, o :nameplaceholder será substituído pela string Jimbo. Observe que não se trata simplesmente de uma substituição de string, pois o valor é escapado ou enviado por um canal diferente da consulta real, evitando, assim, qualquer tipo de ataques de injeção.
troelskn
16

Tenho trabalhado com o PDO recentemente e a resposta acima está completamente certa, mas eu só queria documentar que o seguinte também 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
fonte
16
Não, não precisa, porque você não selecionou qual banco de dados usar.
Rápli András
3
Isso deve estar na string "server", que deve ser um DSN na forma de "{driver}: dbname = {db_name}; host = {server}" substituindo os valores das chaves por quaisquer que sejam suas necessidades de conexão
thorne51
12

Você pode usar os métodos bindParamou bindValuepara ajudar a preparar sua declaração. Isso torna as coisas mais claras à primeira vista, em vez de fazer, $check->execute(array(':name' => $name));especialmente se você estiver vinculando vários valores / variáveis.

Verifique o exemplo claro e fácil de ler abaixo:

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

Se você estiver esperando várias linhas, remova o LIMIT 1e altere o método de busca para 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
fonte
Não tenho certeza. Parece uma resposta válida para mim. Acho que seria benéfico usar 'meunome' em vez de 'nome' e também usar vários parâmetros em vez de apenas um.
Joe Phillips
@GillianLoWong O que ele $check = $q->fetch(PDO::FETCH_ASSOC); if (!empty($check)){ $row_id = $check['id']; // do something }faz?
Abdul de
1
Olá @abdul, substituí a verificação de contagem / vazio na matriz. Era para ver se algum resultado era retornado. Mas pdo também tem uma função chamada rowCount () que permite que você verifique se alguma linha foi afetada / buscada. Não faz sentido buscar dados se você nem mesmo sabe se alguma linha foi selecionada, então movi a instrução fetch para a instrução if rowCount (). :)
Gilly
@Gillian La Wong, obrigado por sua consulta limpa de bindValue para consulta onde múltiplo. que salvam meu projeto.
php-coder
6

Uma resposta um pouco mais completa está aqui com tudo pronto para uso:

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

 echo $done[0];

Aqui $dbhestá o conector PDO db, e com base na idtabela users, usernameusamosfetch();

Espero que isso ajude alguém, Divirta-se!

Domuta Marcel
fonte
Ou use fetchColumn()para evitar [0]ser necessário. Além disso, lembre-se de usar LIMIT 1no SQL.
rybo111
3

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

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

Obtendo Contagem de Linha

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

Método 2: declarações com parâmetros

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

Método 3: Parâmetros de ligação

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

Quer saber mais veja este link

Sudhir
fonte
4
Remova o Método 1. Ele permite a injeção de mysql.
Tomahock
-2

se você estiver usando codificação embutida em uma única página e não usar ops, então vá com este exemplo completo, com certeza ajudará

//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
fonte
Embora este trecho de código possa resolver o problema, ele não explica por que ou como responde à pergunta. Por favor incluir uma explicação para o seu código , como o que realmente ajuda a melhorar a qualidade do seu post. Lembre-se de que você está respondendo à pergunta para leitores no futuro, e essas pessoas podem não saber os motivos de sua sugestão de código. Sinalizadores / revisores: para respostas apenas com código, como esta, faça downvote, não exclua!
Scott Weldon
Então, o que devo excluí-lo
sozinho
Não, exatamente o oposto. Encontrei esta postagem na Fila de Postagens de Baixa Qualidade e, portanto, a última parte do meu comentário foi para dizer às pessoas para não votarem para excluir. (Em vez disso, a sugestão de downvote foi feita para solicitar downvotes provisórios, que seriam removidos depois que sua postagem fosse editada.) Conforme mencionado em meu comentário anterior, seria melhor se você adicionasse uma explicação de por que sugeriu o código que você fez . Além disso, esta pergunta pergunta sobre consultas parametrizadas, mas field > 6969parece codificada em vez de parametrizada.
Scott Weldon