การใช้ PDO กับ Subquery
ในบทความนี้ เราจะมาเรียนรู้วิธีการใช้ Subquery ใน SQL ร่วมกับ PDO เพื่อดึงข้อมูลที่ซับซ้อนยิ่งขึ้น Subquery คือ Query ที่ซ้อนอยู่ภายใน Query อีกทีหนึ่ง ทำให้เราสามารถดึงข้อมูลโดยอ้างอิงจากผลลัพธ์ของ Query อื่นได้
Subquery คืออะไร?
Subquery หรือ Inner Query คือ SELECT statement ที่ฝังอยู่ภายใน SQL statement หลัก Subquery จะถูก execute ก่อน SQL statement หลัก และผลลัพธ์ของ Subquery จะถูกนำไปใช้ในการ execute SQL statement หลัก
Subquery สามารถปรากฏในหลายส่วนของ SQL statement หลัก เช่น
- WHERE clause
- SELECT clause
- FROM clause (น้อยครั้งที่จะใช้)
ในบทความนี้ เราจะเน้นการใช้งาน Subquery ใน WHERE clause และ SELECT clause เป็นหลัก
การเขียน Subquery
รูปแบบการเขียน Subquery พื้นฐานคือ:
SELECT column1, column2
FROM table_name
WHERE column3 IN (SELECT column3 FROM another_table WHERE condition);
ในตัวอย่างนี้ Subquery คือ (SELECT column3 FROM another_table WHERE condition) ซึ่งจะถูก execute ก่อน และผลลัพธ์ที่ได้จะถูกนำไปใช้ใน WHERE clause ของ Query หลัก
การใช้ Subquery ใน WHERE Clause
Subquery ใน WHERE clause มักถูกใช้เพื่อกรองข้อมูลโดยอ้างอิงจากผลลัพธ์ของ Query อื่น ตัวอย่างเช่น เราต้องการดึงข้อมูลผู้ใช้ทั้งหมดที่ทำการสั่งซื้อ (order) อย่างน้อยหนึ่งครั้ง เราสามารถทำได้ดังนี้:
SELECT *
FROM users
WHERE id IN (SELECT user_id FROM orders);
ในตัวอย่างนี้ Subquery (SELECT user_id FROM orders) จะดึง `user_id` ทั้งหมดจากตาราง `orders` จากนั้น Query หลักจะดึงข้อมูลผู้ใช้ทั้งหมดที่มี `id` ตรงกับ `user_id` ที่ได้จาก Subquery
ตัวอย่างการใช้งานจริง:
สมมติว่าเรามีตาราง `products` และ `orders` โดย `orders` มี column `product_id` ที่อ้างอิงไปยัง `id` ของ `products` เราต้องการดึงข้อมูลสินค้าทั้งหมดที่ถูกสั่งซื้ออย่างน้อย 5 ครั้ง:
SELECT *
FROM products
WHERE id IN (
SELECT product_id
FROM orders
GROUP BY product_id
HAVING COUNT(product_id) >= 5
);
PHP Code (PDO):
<?php
try {
$pdo = new PDO("mysql:host=localhost;dbname=your_database", "username", "password");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "SELECT *
FROM products
WHERE id IN (
SELECT product_id
FROM orders
GROUP BY product_id
HAVING COUNT(product_id) >= 5
)";
$stmt = $pdo->query($sql);
if ($stmt->rowCount() > 0) {
echo "<h3>สินค้าที่ถูกสั่งซื้ออย่างน้อย 5 ครั้ง:</h3>";
echo "<ul>";
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "<li>" . $row["name"] . " (ID: " . $row["id"] . ")</li>";
}
echo "</ul>";
} else {
echo "<p>ไม่มีสินค้าที่ถูกสั่งซื้ออย่างน้อย 5 ครั้ง</p>";
}
} catch (PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}
?>
คำอธิบาย Code:
- เราสร้าง PDO connection ไปยังฐานข้อมูล
- เราสร้าง SQL query ที่ใช้ Subquery ใน WHERE clause
- เรา execute query ด้วย
$pdo->query($sql) - เรา loop ผ่านผลลัพธ์ที่ได้และแสดงข้อมูลสินค้า
- เราจัดการ exception ในกรณีที่เกิดข้อผิดพลาดในการเชื่อมต่อหรือ query
การใช้ Subquery ใน SELECT Clause
Subquery ใน SELECT clause มักถูกใช้เพื่อดึงข้อมูลเพิ่มเติมที่เกี่ยวข้องกับแต่ละ record ใน Query หลัก ตัวอย่างเช่น เราต้องการดึงข้อมูลผู้ใช้แต่ละคนพร้อมกับจำนวน order ที่พวกเขาเคยทำ เราสามารถทำได้ดังนี้:
SELECT
users.*,
(SELECT COUNT(*) FROM orders WHERE user_id = users.id) AS order_count
FROM users;
ในตัวอย่างนี้ Subquery (SELECT COUNT(*) FROM orders WHERE user_id = users.id) จะถูก execute สำหรับแต่ละ row ในตาราง `users` และจะ return จำนวน order ที่ `user_id` ตรงกับ `users.id` ผลลัพธ์ที่ได้จะถูกแสดงเป็น column ชื่อ `order_count`
ตัวอย่างการใช้งานจริง:
สมมติว่าเรามีตาราง `users` และ `orders` เหมือนเดิม เราต้องการดึงข้อมูลผู้ใช้แต่ละคนพร้อมกับวันที่ order ล่าสุดของพวกเขา:
SELECT
users.*,
(SELECT MAX(order_date) FROM orders WHERE user_id = users.id) AS last_order_date
FROM users;
PHP Code (PDO):
<?php
try {
$pdo = new PDO("mysql:host=localhost;dbname=your_database", "username", "password");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "SELECT
users.*,
(SELECT MAX(order_date) FROM orders WHERE user_id = users.id) AS last_order_date
FROM users";
$stmt = $pdo->query($sql);
if ($stmt->rowCount() > 0) {
echo "<h3>ข้อมูลผู้ใช้พร้อมวันที่ Order ล่าสุด:</h3>";
echo "<table border='1'>";
echo "<tr><th>ID</th><th>Name</th><th>Email</th><th>Last Order Date</th></tr>";
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "<tr>";
echo "<td>" . $row["id"] . "</td>";
echo "<td>" . $row["name"] . "</td>";
echo "<td>" . $row["email"] . "</td>";
echo "<td>" . $row["last_order_date"] . "</td>";
echo "</tr>";
}
echo "</table>";
} else {
echo "<p>ไม่มีข้อมูลผู้ใช้</p>";
}
} catch (PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}
?>
คำอธิบาย Code:
- เราสร้าง PDO connection ไปยังฐานข้อมูล
- เราสร้าง SQL query ที่ใช้ Subquery ใน SELECT clause
- เรา execute query ด้วย
$pdo->query($sql) - เรา loop ผ่านผลลัพธ์ที่ได้และแสดงข้อมูลผู้ใช้พร้อมวันที่ Order ล่าสุด
- เราจัดการ exception ในกรณีที่เกิดข้อผิดพลาดในการเชื่อมต่อหรือ query
ข้อผิดพลาดที่พบบ่อยในการใช้ Subquery
- Performance: Subquery อาจทำให้ Query ช้าลง โดยเฉพาะอย่างยิ่งถ้า Subquery มีความซับซ้อนหรือ return ข้อมูลจำนวนมาก ควรพิจารณาใช้ JOIN statement แทนถ้าเป็นไปได้
- Correlated Subquery: Correlated Subquery คือ Subquery ที่อ้างอิงถึง column จาก Query หลัก Correlated Subquery อาจทำให้ Query ช้าลงมาก เนื่องจาก Subquery จะถูก execute สำหรับแต่ละ row ใน Query หลัก
- Subquery Returns More Than One Row: Subquery ที่ใช้ใน WHERE clause ซึ่งใช้ operator เช่น `=`, `!=`, `>`, `<` ต้อง return เพียง row เดียวเท่านั้น ถ้า Subquery return หลาย row จะเกิด error ควรใช้ operator `IN`, `ANY`, หรือ `ALL` แทน
สรุป
Subquery เป็นเครื่องมือที่มีประโยชน์สำหรับการดึงข้อมูลที่ซับซ้อน แต่ควรใช้อย่างระมัดระวังเพื่อหลีกเลี่ยงปัญหาด้าน Performance ในบทความนี้ เราได้เรียนรู้วิธีการใช้ Subquery ใน WHERE clause และ SELECT clause พร้อมทั้งยกตัวอย่างการใช้งานจริงและข้อผิดพลาดที่พบบ่อย ในบทความถัดไป เราจะเรียนรู้เกี่ยวกับการใช้ PDO กับ Stored Procedure