ข้ามไปยังเนื้อหาหลัก
คู่มือระบบ เนื้อหาผ่านการตรวจสอบแล้ว

การใช้ PDO กับ JOIN Statement

บทความนี้อธิบายวิธีการใช้งาน `JOIN` statement ใน SQL ร่วมกับ PDO เพื่อดึงข้อมูลจากหลายตารางที่สัมพันธ์กัน โดยเน้นที่ `INNER JOIN`, `LEFT JOIN`, และ `RIGHT JOIN`...

การใช้ PDO กับ JOIN Statement

ในบทเรียนก่อนหน้า เราได้เรียนรู้วิธีการใช้ PDO กับ Pagination เพื่อจัดการกับข้อมูลจำนวนมากในตารางเดียว แต่ในโลกของการพัฒนาเว็บจริง ๆ ข้อมูลมักจะกระจายอยู่ในหลายตารางที่สัมพันธ์กัน (Relationships) การดึงข้อมูลจากหลายตารางพร้อมกันจึงเป็นสิ่งจำเป็น และ `JOIN` Statement คือคำตอบสำหรับปัญหานี้ บทนี้จะพาคุณไปทำความเข้าใจและใช้งาน `JOIN` Statement ร่วมกับ PDO เพื่อดึงข้อมูลจากหลายตารางอย่างมีประสิทธิภาพ

ทำความเข้าใจกับ JOIN Statement

`JOIN` Statement เป็นคำสั่ง SQL ที่ใช้รวมแถวจากสองตารางขึ้นไป โดยอิงตามเงื่อนไขที่กำหนดไว้ เงื่อนไขนี้มักจะเกี่ยวข้องกับคอลัมน์ที่มีความสัมพันธ์กันในแต่ละตาราง มี `JOIN` หลายประเภท แต่ในบทนี้เราจะเน้นที่ 3 ประเภทหลัก ๆ ที่ใช้บ่อยที่สุด:

  • INNER JOIN: เลือกเฉพาะแถวที่มีค่าตรงกันในทั้งสองตาราง
  • LEFT JOIN (หรือ LEFT OUTER JOIN): เลือกแถวทั้งหมดจากตารางทางซ้าย (ตารางแรกที่ระบุ) และแถวที่ตรงกันจากตารางทางขวา หากไม่มีค่าที่ตรงกันในตารางทางขวา คอลัมน์จากตารางทางขวาจะเป็น `NULL`
  • RIGHT JOIN (หรือ RIGHT OUTER JOIN): คล้ายกับ `LEFT JOIN` แต่สลับข้างกัน คือเลือกแถวทั้งหมดจากตารางทางขวา และแถวที่ตรงกันจากตารางทางซ้าย

ตัวอย่างฐานข้อมูล

เพื่อความเข้าใจที่ตรงกัน เราจะใช้ฐานข้อมูลตัวอย่างที่มีสองตาราง: `users` และ `orders`

-- ตาราง users
CREATE TABLE users (
  id INT PRIMARY KEY AUTO_INCREMENT,
  username VARCHAR(50) NOT NULL,
  email VARCHAR(100) NOT NULL
);

-- ตาราง orders
CREATE TABLE orders (
  id INT PRIMARY KEY AUTO_INCREMENT,
  user_id INT NOT NULL,
  order_date DATE NOT NULL,
  total_amount DECIMAL(10, 2) NOT NULL,
  FOREIGN KEY (user_id) REFERENCES users(id)
);

-- เพิ่มข้อมูลตัวอย่าง
INSERT INTO users (username, email) VALUES
('john_doe', 'john.doe@example.com'),
('jane_smith', 'jane.smith@example.com');

INSERT INTO orders (user_id, order_date, total_amount) VALUES
(1, '2023-10-26', 100.00),
(1, '2023-10-27', 50.00),
(2, '2023-10-28', 75.00);

INNER JOIN: ดึงข้อมูลผู้ใช้และคำสั่งซื้อ

สมมติว่าเราต้องการดึงข้อมูลผู้ใช้และคำสั่งซื้อทั้งหมดของผู้ใช้เหล่านั้น เราสามารถใช้ `INNER JOIN` เพื่อรวมข้อมูลจากตาราง `users` และ `orders` โดยใช้คอลัมน์ `user_id` เป็นเงื่อนไข

<?php
try {
  // เชื่อมต่อฐานข้อมูล (แทนที่ด้วยข้อมูลการเชื่อมต่อของคุณ)
  $pdo = new PDO("mysql:host=localhost;dbname=your_database", "your_username", "your_password");
  $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  // สร้าง query INNER JOIN
  $stmt = $pdo->prepare("
    SELECT
      users.id AS user_id,
      users.username,
      users.email,
      orders.id AS order_id,
      orders.order_date,
      orders.total_amount
    FROM users
    INNER JOIN orders ON users.id = orders.user_id
  ");

  // execute query
  $stmt->execute();

  // ดึงข้อมูลทั้งหมด
  $results = $stmt->fetchAll(PDO::FETCH_ASSOC);

  // แสดงผลลัพธ์
  foreach ($results as $row) {
    echo "User ID: " . $row['user_id'] . "<br>";
    echo "Username: " . $row['username'] . "<br>";
    echo "Email: " . $row['email'] . "<br>";
    echo "Order ID: " . $row['order_id'] . "<br>";
    echo "Order Date: " . $row['order_date'] . "<br>";
    echo "Total Amount: " . $row['total_amount'] . "<br>";
    echo "<hr>";
  }

} catch (PDOException $e) {
  echo "Connection failed: " . $e->getMessage();
}
?>

คำอธิบายโค้ด:

  1. เราสร้าง query SQL ที่ใช้ `INNER JOIN` เพื่อรวมตาราง `users` และ `orders` โดยใช้ `users.id = orders.user_id` เป็นเงื่อนไข
  2. เราใช้ `AS` เพื่อตั้งชื่อ alias ให้กับคอลัมน์ `users.id` เป็น `user_id` และ `orders.id` เป็น `order_id` เพื่อให้ง่ายต่อการอ้างอิงใน PHP
  3. เราใช้ `fetchAll(PDO::FETCH_ASSOC)` เพื่อดึงข้อมูลทั้งหมดในรูปแบบ array ที่มี key เป็นชื่อคอลัมน์
  4. เราวนลูปผ่าน array ที่ได้ และแสดงผลข้อมูลแต่ละแถว

LEFT JOIN: ดึงข้อมูลผู้ใช้และคำสั่งซื้อ (รวมถึงผู้ใช้ที่ไม่มีคำสั่งซื้อ)

หากเราต้องการดึงข้อมูลผู้ใช้ทั้งหมด รวมถึงผู้ใช้ที่ยังไม่มีคำสั่งซื้อ เราสามารถใช้ `LEFT JOIN` ได้

<?php
try {
  // เชื่อมต่อฐานข้อมูล (แทนที่ด้วยข้อมูลการเชื่อมต่อของคุณ)
  $pdo = new PDO("mysql:host=localhost;dbname=your_database", "your_username", "your_password");
  $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  // สร้าง query LEFT JOIN
  $stmt = $pdo->prepare("
    SELECT
      users.id AS user_id,
      users.username,
      users.email,
      orders.id AS order_id,
      orders.order_date,
      orders.total_amount
    FROM users
    LEFT JOIN orders ON users.id = orders.user_id
  ");

  // execute query
  $stmt->execute();

  // ดึงข้อมูลทั้งหมด
  $results = $stmt->fetchAll(PDO::FETCH_ASSOC);

  // แสดงผลลัพธ์
  foreach ($results as $row) {
    echo "User ID: " . $row['user_id'] . "<br>";
    echo "Username: " . $row['username'] . "<br>";
    echo "Email: " . $row['email'] . "<br>";
    echo "Order ID: " . ($row['order_id'] ? $row['order_id'] : 'N/A') . "<br>"; // ตรวจสอบว่ามี Order ID หรือไม่
    echo "Order Date: " . ($row['order_date'] ? $row['order_date'] : 'N/A') . "<br>"; // ตรวจสอบว่ามี Order Date หรือไม่
    echo "Total Amount: " . ($row['total_amount'] ? $row['total_amount'] : 'N/A') . "<br>"; // ตรวจสอบว่ามี Total Amount หรือไม่
    echo "<hr>";
  }

} catch (PDOException $e) {
  echo "Connection failed: " . $e->getMessage();
}
?>

สิ่งที่แตกต่างจาก `INNER JOIN`:

  • เราใช้ `LEFT JOIN` แทน `INNER JOIN`
  • เราตรวจสอบว่า `order_id`, `order_date`, และ `total_amount` มีค่าหรือไม่ก่อนที่จะแสดงผล หากไม่มีค่า (เป็น `NULL`) เราจะแสดง "N/A" แทน

RIGHT JOIN: ดึงข้อมูลคำสั่งซื้อและผู้ใช้ (ไม่ค่อยได้ใช้)

`RIGHT JOIN` จะคล้ายกับ `LEFT JOIN` แต่สลับข้างกัน ในกรณีนี้ เราจะดึงข้อมูลคำสั่งซื้อทั้งหมด และข้อมูลผู้ใช้ที่เกี่ยวข้อง (ถ้ามี) โดยทั่วไป `LEFT JOIN` จะถูกใช้บ่อยกว่า `RIGHT JOIN` เพราะอ่านง่ายกว่า

<?php
try {
  // เชื่อมต่อฐานข้อมูล (แทนที่ด้วยข้อมูลการเชื่อมต่อของคุณ)
  $pdo = new PDO("mysql:host=localhost;dbname=your_database", "your_username", "your_password");
  $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  // สร้าง query RIGHT JOIN
  $stmt = $pdo->prepare("
    SELECT
      users.id AS user_id,
      users.username,
      users.email,
      orders.id AS order_id,
      orders.order_date,
      orders.total_amount
    FROM orders
    RIGHT JOIN users ON users.id = orders.user_id
  ");

  // execute query
  $stmt->execute();

  // ดึงข้อมูลทั้งหมด
  $results = $stmt->fetchAll(PDO::FETCH_ASSOC);

  // แสดงผลลัพธ์
  foreach ($results as $row) {
    echo "User ID: " . ($row['user_id'] ? $row['user_id'] : 'N/A') . "<br>";
    echo "Username: " . ($row['username'] ? $row['username'] : 'N/A') . "<br>";
    echo "Email: " . ($row['email'] ? $row['email'] : 'N/A') . "<br>";
    echo "Order ID: " . $row['order_id'] . "<br>";
    echo "Order Date: " . $row['order_date'] . "<br>";
    echo "Total Amount: " . $row['total_amount'] . "<br>";
    echo "<hr>";
  }

} catch (PDOException $e) {
  echo "Connection failed: " . $e->getMessage();
}
?>

ข้อผิดพลาดที่พบบ่อยและการแก้ไข

  • Ambiguous Column Names: หากคอลัมน์ที่มีชื่อเดียวกันอยู่ในหลายตาราง คุณต้องระบุชื่อตารางก่อนชื่อคอลัมน์ (เช่น `users.id` แทนที่จะเป็น `id`)
  • Incorrect JOIN Condition: ตรวจสอบให้แน่ใจว่าเงื่อนไข `ON` ถูกต้องและสัมพันธ์กับคอลัมน์ที่เชื่อมโยงกันในแต่ละตาราง
  • Performance Issues: สำหรับตารางขนาดใหญ่ การใช้ `JOIN` อาจทำให้ query ช้าลง การสร้าง index บนคอลัมน์ที่ใช้ในเงื่อนไข `ON` สามารถช่วยปรับปรุงประสิทธิภาพได้

สรุป

ในบทนี้ เราได้เรียนรู้วิธีการใช้ `JOIN` Statement ร่วมกับ PDO เพื่อดึงข้อมูลจากหลายตาราง การทำความเข้าใจ `INNER JOIN`, `LEFT JOIN`, และ `RIGHT JOIN` จะช่วยให้คุณสามารถสร้าง query ที่ซับซ้อนและดึงข้อมูลที่ต้องการได้อย่างแม่นยำ ในบทต่อไป เราจะเรียนรู้เกี่ยวกับการใช้ PDO กับ Subquery เพื่อเพิ่มความสามารถในการดึงข้อมูลที่ซับซ้อนยิ่งขึ้น

Office.in.th Custom Service

ต้องการพัฒนาระบบหรือปรับแต่งจากโครงสร้างนี้?

Office.in.th รับพัฒนาและออกแบบ Enterprise Web Application, API Integration และระบบบริหารงานภาครัฐ/เอกชน พร้อมการสนับสนุนระยะยาว

ดูบริการรับพัฒนาซอฟต์แวร์