JOIN ต่อตาราง
หัวใจของ relational database ต่อ users กับ orders ผ่าน foreign key เห็นความต่างของ INNER, LEFT, RIGHT, FULL JOIN ผ่าน animation
~12 นาที
ในบทที่ 02 เราเห็นแล้วว่า orders.user_id ชี้กลับไปที่ users.id แต่เวลา query ข้อมูลจริง ผู้บริหาร Vibe Mart อยากเห็น "ชื่อลูกค้า" คู่กับ "ยอดสั่งซื้อ" ไม่ใช่แค่ตัวเลข user_id ที่ดูแล้วไม่รู้เรื่อง คำสั่ง JOIN นี่แหละที่จับ row จากสองตารางมาวางคู่กันโดยใช้ key เป็นตัวเชื่อม
โครงสร้างพื้นฐาน
SELECT u.name, o.total, o.status
FROM users u
JOIN orders o ON o.user_id = u.id;uและoคือ alias ที่ตั้งให้สั้น จะได้ไม่ต้องพิมพ์ชื่อตารางเต็มทุกครั้งON o.user_id = u.idคือเงื่อนไขที่บอกว่า "row ไหน match กัน"- ผลลัพธ์ที่ได้คือ row ที่ match กันแล้ว เอาทุก column ของทั้งสองตารางมารวมเป็น row เดียว
JOIN มี 4 แบบหลัก
ความต่างของแต่ละแบบอยู่ที่ "ทำยังไงกับ row ที่ไม่ match" ลองกดสลับดูในด้านล่าง
Hover row ฝั่งใดก็ได้ เห็นเส้นโยงไปยัง row ที่ match กัน
INNER JOIN เอาเฉพาะที่มีคู่กันทั้งสองฝั่งuser ที่ไม่มี order หาย, order ที่ไม่มี user หาย
users
#12024-01
ปอนด์
กรุงเทพ
#22024-02
น้ำเพชร
เชียงใหม่
#32024-02
เอิร์น
กรุงเทพ
#92024-07
แตงโม
กรุงเทพ
#102024-08
ก้อย
NULL
orders
#1shipped
user_id: 1฿121
#2shipped
user_id: 1฿890
#5shipped
user_id: 2฿450
#6paid
user_id: 2฿1,290
#8shipped
user_id: 3฿2,729
#9shipped
user_id: 3฿890
#11paid
user_id: 3฿539
ผลลัพธ์ของ INNER JOIN7 rows
| u.id | u.name | u.city | o.id | o.total | o.status |
|---|---|---|---|---|---|
| 1 | ปอนด์ | กรุงเทพ | 1 | 121 | shipped |
| 1 | ปอนด์ | กรุงเทพ | 2 | 890 | shipped |
| 2 | น้ำเพชร | เชียงใหม่ | 5 | 450 | shipped |
| 2 | น้ำเพชร | เชียงใหม่ | 6 | 1,290 | paid |
| 3 | เอิร์น | กรุงเทพ | 8 | 2,729 | shipped |
| 3 | เอิร์น | กรุงเทพ | 9 | 890 | shipped |
| 3 | เอิร์น | กรุงเทพ | 11 | 539 | paid |
- INNER JOIN เอาเฉพาะ row ที่ match กันทั้งสองฝั่ง user ที่ไม่เคยซื้อจะหายไป (เป็นแบบที่ใช้บ่อยที่สุด และเป็น default ของหลายฐานข้อมูล)
- LEFT JOIN เก็บทุก row ฝั่งซ้ายไว้ user ที่ไม่มี order ก็ยังเห็นอยู่ ส่วน column ฝั่ง orders จะเป็น NULL
- RIGHT JOIN เก็บทุก row ฝั่งขวา ใช้น้อยมาก เพราะแค่สลับฝั่งให้เป็น LEFT JOIN ก็ได้ผลเหมือนกัน
- FULL JOIN เก็บทุก row จากทั้งสองฝั่ง ใช้น้อยที่สุด บางฐานอย่าง MySQL ก็ไม่มีให้ใช้ด้วยซ้ำ
JOIN หลายตารางต่อเนื่อง
ถ้าอยากดู "ชื่อลูกค้า + ชื่อสินค้า + จำนวน" ต้อง join 4 ตารางต่อกัน คือ users → orders → order_items → products
SELECT u.name, p.name, oi.qty
FROM users u
JOIN orders o ON o.user_id = u.id
JOIN order_items oi ON oi.order_id = o.id
JOIN products p ON oi.product_id = p.id
LIMIT 10;JOIN แต่ละชั้นมีเงื่อนไข ON เพิ่มเข้ามา เพื่อบอกว่า "ตารางที่เพิ่มเข้ามาใหม่ match กับตารางก่อนหน้ายังไง" ในธุรกิจจริงการ JOIN 4 หรือ 5 ตารางถือเป็นเรื่องปกติ
Playground ลอง JOIN จริง
ตัวอย่าง:
กด Cmd / Ctrl + Enter เพื่อรัน
สรุปบทนี้
JOIN ... ON ...ใช้จับ row จากสองตาราง มา match กันด้วย key- INNER เอาเฉพาะที่ match กัน ส่วน LEFT เก็บฝั่งซ้ายหมด แล้วฝั่งขวาเป็น NULL ถ้าไม่มีคู่
- JOIN ต่อกันได้หลายตาราง แต่ละชั้นต้องมี ON ใหม่ของตัวเอง
- ลืม ON เมื่อไหร่ ก็ได้ Cartesian product ระเบิดทันที ระวัง
- บทถัดไปจะเข้าเรื่อง
GROUP BYสำหรับสรุปข้อมูลเป็น bucket