การรวมข้อมูลจากหลายตารางด้วย OUTER JOIN

คำสั่ง OUTER JOIN ของ MySQL มีอยู่ 2 รูปแบบคือ LEFT OUTER JOIN (หรือ LEFT JOIN) และ RIGHT OUTER JOIN (หรือ RIGHT JOIN) โดยที่คำสั่งในกลุ่มนี้จะเป็นการ Query โดยการจับคู่ข้อมูลจาก 2 ตาราง โดยรักษาข้อมูลในตารางหลักไว้ และคืนค่า NULL ในฟิลด์ที่ไม่สามารถจับคู่ได้หรือหากไม่พบข้อมูลในตารางรอง หรือจะอธิบายอีกแบบว่า เราจะได้ทุก record ออกมาจากตารางหลักนั่นเอง ดังแผนภาพด้านล่าง
OUTER JOIN
SELECT U.id,U.email,E.sent FROM db_user AS U LEFT JOIN db_email AS E ON E.member_id=U.id
จากตัวอย่างการ JOIN ข้างบนเราจะได้ข้อมูลทุก record ของตาราง user (รายชื่ออีเมล์สมาชิกทุกคน) โดยจับคู่กับตาราง email โดยที่ถ้าพบว่า E.member_id=U.id แสดงว่าอีเมล์นี้มีการส่งแล้ว โดยคืนค่าเวลาที่ส่งที่ฟิลด์ sent ของตาราง db_email(หากยังไม่ได้ส่งฟิลด์นี้จะเป็น NULL)
สิ่งที่ควรจำสำหรับการ JOIN แบบนี้คือ เงือนไขการ JOIN จะต้องถูกใส่ไว้ใน ON เท่านั้น ส่วนเงื่อนไขการค้นหาให้ใส่ไว้ในคำสั่ง WHERE เท่านั้นเช่นกัน

ปัญหาการใช้งาน OUTER JOIN

จริงๆแล้วคำสั่งด้านบนก็ทำงานตามที่ควรจะเป็นแหละครับ แต่ที่นี้มันมีปัญหาด้านประสิทธิภาพหากตารางที่นำมา JOIN มีจำนวนข้อมูลมาก คำสั่งด้านบนจะทำงานได้ช้าลงตามจำนวน reccord ที่เพิ่มขึ้น แบบก้าวกระโดด เนื่องจากในกระบวนการ JOIN ตารางหลัก จะทำการจับคู่กับตารางรองในทุกเร็คคอร์ดก่อนที่จะเลือก record ที่ตรงกัน

การแก้ปัญหานี้อาจต้องใช้วิธีการ query ในรูปแบบอื่น
SELECT * (
(SELECT U.id,U.email,E.sent FROM db_user AS U INNER JOIN db_email AS E ON E.member_id=U.id)
UNION ALL
(SELECT U.id,U.email,0 FROM db_user)
} AS Q GROUP BY Q.id

อธิบายได้ดังนี้นะครับ คำสั่ง SELECT U.id,U.email,E.sent FROM db_user AS U INNER JOIN db_email AS E ON E.member_id=U.id จะเลือกเฉพาะรายชื่อที่สามารถจับคู่ได้ หรือรายชื่อที่ส่งแล้วเท่านั้น ในขณะที่ SELECT U.id,U.email,0 FROM db_user จะทำการเลือกรายชื่อสมาชิกทุกคน แล้วนำผลลัพท์ของทั้ง 2 query ที่ซ้ำกัน โดยใช้ UNION ALL (ผมใช้ UNION ALL เพราะมีประสิทธิภาพมากกว่า UNION เนื่องจากไม่จำเป็นต้องตัด record ที่ซ้ำกัน) และมาทำการตัด record ที่ซ้ำกันอีกครั้งด้วย GROUP BY ที่ query ชั้นนอกสุด
ผู้เขียน Goragod โพสต์เมื่อ 05 พ.ค. 2555 เปิดดู 21,208 ป้ายกำกับ SQL

เรื่องที่เกี่ยวข้อง

^