ฉันจะใช้ออบเจ็กต์ PDO อย่างเหมาะสมสำหรับคิวรี SELECT ที่กำหนดพารามิเตอร์ได้อย่างไร


85

ฉันได้ลองทำตามคำแนะนำของ PHP.net ในการทำSELECTแบบสอบถามแล้ว แต่ฉันไม่แน่ใจว่าจะทำอย่างไรดีที่สุด

ฉันต้องการใช้SELECTแบบสอบถามที่กำหนดพารามิเตอร์หากเป็นไปได้เพื่อส่งคืนIDในตารางที่nameฟิลด์ตรงกับพารามิเตอร์ สิ่งนี้ควรคืนค่าหนึ่งIDเนื่องจากจะไม่ซ้ำกัน

จากนั้นฉันต้องการใช้IDเป็นINSERTตารางอื่นดังนั้นฉันจะต้องพิจารณาว่าสำเร็จหรือไม่

ฉันอ่านด้วยว่าคุณสามารถเตรียมแบบสอบถามเพื่อนำกลับมาใช้ใหม่ได้ แต่ฉันไม่แน่ใจว่าจะช่วยได้อย่างไร

คำตอบ:


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 ใหม่ (... ) ใช่ไหม?
Joe Phillips

1
ไม่. PDO เป็นคลาสการเชื่อมต่อ (ควรใช้ชื่อว่า PdoConnection แทน) การเชื่อมต่อสามารถสร้าง PdoStatements คุณเรียกใช้ setAttribute () บนออบเจ็กต์การเชื่อมต่อไม่ใช่แต่ละคำสั่ง (หรือคุณสามารถส่งต่อไปยังผู้สร้าง)
troelskn

1
สิ่งนี้อาจมีประโยชน์:$db = new PDO('mysql:dbname=your_database;host=localhost', 'junior', '444');
Junior Mayhé

2
สำหรับสาย$statement->execute(array(':name' => "Jimbo"));คุณสามารถอธิบายส่วนของ Jimbo ได้หรือไม่?
muttley91

1
@rar On line :nameก่อนหน้าแบบสอบถามจะเริ่มต้นด้วยตัวยึด การเรียกexecuteที่นี่ทำได้ด้วยอาร์เรย์เชื่อมโยงของตัวยึดตำแหน่ง -> คู่ค่า ดังนั้นในกรณีนี้: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
ไม่ได้เนื่องจากคุณไม่ได้เลือกฐานข้อมูลที่จะใช้
RápliAndrás

3
ที่จริงควรอยู่ในสตริง "เซิร์ฟเวอร์" ซึ่งจริงๆแล้วควรเป็น DSN ในรูปแบบของ "{driver}: dbname = {db_name}; host = {server}" แทนที่ค่าปีกกาด้วยสิ่งที่การเชื่อมต่อของคุณต้องการ
thorne51

12

คุณสามารถใช้bindParamหรือbindValueวิธีการเพื่อช่วยเตรียมคำชี้แจงของคุณ ทำให้สิ่งต่างๆชัดเจนขึ้นตั้งแต่แรกเห็นแทนที่จะทำ$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และเปลี่ยนวิธีการดึงข้อมูลเป็น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' และยังใช้ params หลายตัวแทนที่จะใช้เพียงอันเดียว
Joe Phillips

@GillianLoWong $check = $q->fetch(PDO::FETCH_ASSOC); if (!empty($check)){ $row_id = $check['id']; // do something }ทำอะไร?
อับดุล

1
สวัสดี @abdul ฉันได้แทนที่การตรวจสอบจำนวน / ว่างในอาร์เรย์ มันควรจะดูว่ามีผลลัพธ์กลับมาหรือไม่ แต่ pdo ยังมีฟังก์ชันที่เรียกว่า rowCount () ที่ให้คุณตรวจสอบว่าแถวใดได้รับผลกระทบ / ดึงข้อมูลหรือไม่ ไม่มีจุดใดในการดึงข้อมูลหากคุณไม่รู้ด้วยซ้ำว่ามีการเลือกแถวใดบ้างดังนั้นฉันจึงย้ายคำสั่ง fetch ไปยังคำสั่ง if rowCount () :)
Gilly

@Gillian La Wong ขอบคุณสำหรับการค้นหา bindValue ที่สะอาดสำหรับการค้นหาหลายรายการ ที่บันทึกโครงการของฉัน
php-coder

6

คำตอบที่สมบูรณ์ของ litle bit อยู่ที่นี่พร้อมสำหรับการใช้งาน:

    $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

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

หากคุณใช้การเข้ารหัสแบบอินไลน์ในหน้าเดียวและไม่ได้ใช้โอ๊ะโอกว่าไปกับตัวอย่างเต็มนี้จะช่วยได้แน่นอน

//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

แล้วฉันจะลบตัวเองได้อย่างไร
ชีฟซิงห์

ไม่ตรงกันข้าม ฉันเจอโพสต์นี้ในคิวโพสต์คุณภาพต่ำดังนั้นส่วนหลังของความคิดเห็นของฉันคือบอกให้คนอื่นไม่โหวตให้ลบ (ข้อเสนอแนะในการลดคะแนนแทนมีไว้เพื่อแจ้งให้มีการลดคะแนนชั่วคราวซึ่งจะถูกลบออกหลังจากที่โพสต์ของคุณได้รับการแก้ไข) ดังที่ได้กล่าวไว้ในความคิดเห็นก่อนหน้าของฉันมันจะดีกว่าถ้าคุณเพิ่มคำอธิบายว่าทำไมคุณถึงแนะนำโค้ดที่คุณทำ . นอกจากนี้คำถามนี้ยังถามเกี่ยวกับเคียวรีที่กำหนดพารามิเตอร์ แต่field > 6969ดูเหมือนฮาร์ดโค้ดมากกว่ากำหนดพารามิเตอร์
Scott Weldon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.