SQL-4.2 LEFT / RIGHT / FULL JOIN
INNER JOIN ทิ้งแถวที่ไม่มี match — แต่บางทีคุณ ต้องการ เห็นแถวนั้น เช่น “นักเรียนที่ยังไม่ลงทะเบียน” นั่นคือที่มาของ LEFT JOIN
ภาพรวม JOIN Types
Section titled “ภาพรวม JOIN Types”INNER JOIN: เฉพาะ match [ A ∩ B ]LEFT JOIN: ทุกแถวจาก A [ A ∪ (A∩B) ]RIGHT JOIN: ทุกแถวจาก B [ (A∩B) ∪ B ]FULL OUTER JOIN: ทุกแถวจากทั้งคู่ [ A ∪ B ]LEFT JOIN — เก็บทุกแถวจากตารางซ้าย
Section titled “LEFT JOIN — เก็บทุกแถวจากตารางซ้าย”-- LEFT JOIN: เก็บนักเรียนทุกคน แม้ไม่มี enrollmentSELECT s.student_id, s.name, e.course_id, e.enrolled_onFROM students sLEFT JOIN enrollments e ON s.student_id = e.student_id;ผลลัพธ์:
| student_id | name | course_id | enrolled_on |
|---|---|---|---|
| STD001 | สมชาย | CS101 | 2025-08-15 |
| STD001 | สมชาย | CS102 | 2025-08-16 |
| STD002 | สมหญิง | CS101 | 2025-08-15 |
| STD003 | วิชัย | NULL | NULL |
ใช้ LEFT JOIN หา “ใครยังไม่ลงทะเบียน”:
SELECT s.nameFROM students sLEFT JOIN enrollments e ON s.student_id = e.student_idWHERE e.enrollment_id IS NULL;-- ได้: วิชัยVLOOKUP ที่หาไม่เจอจะได้ #N/A — ซึ่งเทียบเท่า NULL ใน LEFT JOIN:
=IFERROR(VLOOKUP(A2, enrollments!A:C, 3, FALSE), "ไม่มี")IFERROR ทำหน้าที่เหมือน COALESCE ใน SQL
import pandas as pd
students = pd.DataFrame({ 'student_id': ['STD001', 'STD002', 'STD003'], 'name': ['สมชาย', 'สมหญิง', 'วิชัย']})enrollments = pd.DataFrame({ 'student_id': ['STD001', 'STD001', 'STD002'], 'course_id': ['CS101', 'CS102', 'CS101']})
# LEFT JOINresult = students.merge(enrollments, on='student_id', how='left')print(result)# STD003 ยังอยู่ แต่ course_id = NaN
# หาคนที่ยังไม่ลงทะเบียนno_enroll = result[result['course_id'].isna()]print(no_enroll[['name']])#include <stdio.h>#include <string.h>
int main() { char *students[] = {"STD001", "STD002", "STD003"}; char *names[] = {"สมชาย", "สมหญิง", "วิชัย"}; char *enroll_sid[] = {"STD001", "STD001", "STD002"}; char *enroll_cid[] = {"CS101", "CS102", "CS101"};
for (int s = 0; s < 3; s++) { int found = 0; for (int e = 0; e < 3; e++) { if (strcmp(students[s], enroll_sid[e]) == 0) { printf("%s %s %s\n", students[s], names[s], enroll_cid[e]); found = 1; } } // LEFT JOIN: ถ้าไม่เจอ ก็ยังแสดง if (!found) { printf("%s %s NULL\n", students[s], names[s]); } } return 0;}RIGHT JOIN & FULL OUTER JOIN
Section titled “RIGHT JOIN & FULL OUTER JOIN”-- RIGHT JOIN: เก็บทุกแถวจากตารางขวา (enrollments)SELECT s.name, e.course_idFROM students sRIGHT JOIN enrollments e ON s.student_id = e.student_id;
-- FULL OUTER JOIN: เก็บทุกแถวจากทั้งสองตารางSELECT s.name, e.course_idFROM students sFULL OUTER JOIN enrollments e ON s.student_id = e.student_id;Sheets ไม่มี RIGHT JOIN / FULL JOIN โดยตรง — ต้องใช้เทคนิคซ้อน VLOOKUP หรือใช้ QUERY function
# RIGHT JOINresult_right = students.merge(enrollments, on='student_id', how='right')
# FULL OUTER JOINresult_full = students.merge(enrollments, on='student_id', how='outer')print(result_full)// FULL OUTER JOIN ใน C = LEFT JOIN + แถวจากขวาที่ไม่มี match// ซับซ้อนขึ้น แต่หลักการเดียวกัน:// loop ซ้าย → หา match ในขวา// loop ขวา → หาแถวที่ยังไม่เคยถูก matchเมื่อไหร่ใช้อะไร
Section titled “เมื่อไหร่ใช้อะไร”| สถานการณ์ | ใช้ JOIN แบบ |
|---|---|
| ดูเฉพาะนักเรียนที่ลงทะเบียนแล้ว | INNER JOIN |
| ดูนักเรียนทุกคน + วิชาที่ลง (ถ้ามี) | LEFT JOIN |
| หานักเรียนที่ยังไม่ลงทะเบียน | LEFT JOIN + WHERE ... IS NULL |
| ดูข้อมูลจากทั้งสองฝั่งไม่ให้ตกหล่น | FULL OUTER JOIN |