如何正确使用PDO对象进行参数化SELECT查询


85

我已经尝试按照PHP.net说明进行SELECT查询,但是我不确定执行此操作的最佳方法。

SELECT如果可能,我想使用参数化查询来返回ID表中name字段与参数匹配的表。这应该返回一个,ID因为它将是唯一的。

然后,我想将其ID用于INSERT另一个表,因此我需要确定它是否成功。

我还读到您可以准备查询以供重用,但是我不确定这有什么帮助。

Answers:


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');
JuniorMayhé2012年

2
对于这一行$statement->execute(array(':name' => "Jimbo"));,您能解释一下Jimbo部分吗?
muttley91

1
@rar在上一行,使用占位符启动查询:nameexecute此处的调用是通过占位符->值对的关联数组来完成的。因此,在这种情况下,:name占位符将替换为字符串Jimbo。请注意,它不是简单地执行字符串替换,因为该值会转义或通过与实际查询不同的通道发送,从而防止了任何类型的注入攻击。
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
该名称实际上应在“服务器”字符串中,该字符串实际上应为“ {driver}:dbname = {db_name}; host = {server}”形式的DSN,用连接所需的花括号值替换
thorne51

12

您可以使用bindParambindValue方法来帮助准备您的陈述。它使事情一目了然,而不是一目了然$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并将fetch方法更改为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 }办?
阿卜杜勒2015年

1
@abdul,您好,我已替换了阵列上的计数/空检查。应该查看是否返回任何结果。但是pdo还具有一个称为rowCount()的函数,该函数可让您检查是否有任何行受到影响/提取。如果您甚至都不知道是否选择了任何行,则获取数据毫无意义,因此我将fetch语句移至if rowCount()语句中。:)
Gilly 2015年

@Gillian La Wong感谢您对bindValue的多次干净查询。保存我的项目。
php-coder

6

一点点的完整答案就在这里,所有准备就绪:

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

 echo $done[0];

$dbh是PDO db连接器,根据id表,users我们可以username使用fetch();

我希望这可以帮助某人,尽情享受!


或使用fetchColumn()以避免[0]被需要。另外,请记住要LIMIT 1在SQL中使用。
rybo111 '16

3

方法1:使用PDO查询方法

$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

如果您在单个页面中使用内联编码而不是使用oops,而不是使用此完整示例,那一定会有所帮助

//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 />";
}

尽管此代码段可以解决问题,但并未说明原因或答案。请附上代码说明,因为这确实有助于提高您的帖子质量。请记住,您将来会为读者回答这个问题,而这些人可能不知道您提出代码建议的原因。举报人/审阅者: 对于仅限代码的答案,例如这一答案,请表决,不要删除!
Scott Weldon

所以我应该删除自己的内容
Shiv Singh

不,正好相反。我在“低质量帖子队列”中遇到了该帖子,因此我的评论的后半部分是告诉人们不要投票删除。(建议降级是为了提示临时降级,在您的帖子被编辑后将被删除。)正如我之前的评论中所提到的,最好添加解释为什么建议您编写代码的解释。同样,此问题询问有关参数化查询的信息,但field > 6969看起来是硬编码而不是参数化的。
Scott Weldon
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.