ใช้ EXISTS + Subquery สำหรับ Semi-Join (Filter ตามตารางอื่น)
EXISTS คืนค่า TRUE หาก Subquery คืนแถวอย่างน้อย 1 แถว ใช้กรองตารางหลัก (DemoTable1) ให้เหลือเฉพาะแถวที่มีค่าตรงกับตารางอ้างอิง (DemoTable2)
สร้างตาราง 1: วิชา (Subject)
mysql> CREATE TABLE DemoTable1 (
-> Id INT,
-> SubjectName VARCHAR(20)
-> );
Query OK, 0 rows affected (0.58 sec)
mysql> INSERT INTO DemoTable1 VALUES
-> (111, 'MySQL'), (112, 'MongoDB'), (113, 'Java'), (114, 'C'), (115, 'MySQL');
Query OK, 5 rows affected
สร้างตาราง 2: นักเรียน + วิชาที่เรียน (StudentSubject)
mysql> CREATE TABLE DemoTable2 (
-> FirstName VARCHAR(20),
-> StudentSubject VARCHAR(20)
-> );
Query OK, 0 rows affected (0.73 sec)
mysql> INSERT INTO DemoTable2 VALUES
-> ('Chris', 'MySQL'), ('Bob', 'MySQL'), ('Sam', 'MySQL'), ('Carol', 'C');
Query OK, 4 rows affected
คำสั่ง: หา Id จาก DemoTable1 ที่ SubjectName มีอยู่ใน DemoTable2.StudentSubject
mysql> SELECT Id FROM DemoTable1
-> WHERE EXISTS (
-> SELECT 1 FROM DemoTable2
-> WHERE SubjectName = StudentSubject
-> );
ผลลัพธ์
+------+ | Id | +------+ | 111 | | 114 | | 115 | +------+
คำอธิบาย
SELECT 1- ไม่สำคัญจะ Select อะไร แค่ต้องการ TRUE/FALSEEXISTSหยุดค้นหาทันทีเมื่อเจอ Match แถวแรก (Short-circuit) → เร็วกว่า IN สำหรับ Subquery ขนาดใหญ่- Match: MySQL (111, 115) และ C (114)
เปรียบเทียบ EXISTS vs IN vs JOIN
| วิธี | คำสั่ง | ความแตกต่าง |
|---|---|---|
| EXISTS | WHERE EXISTS (SELECT 1 FROM t2 WHERE t1.col = t2.col) | Semi-Join, หยุดไว้ตอนเจอ Match, จัดการ NULL ดี |
| IN | WHERE col IN (SELECT col FROM t2) | อาจช้ากว่า EXISTS, NULL ใน Subquery ทำให้เป็น UNKNOWN |
| INNER JOIN | SELECT DISTINCT t1.Id FROM t1 JOIN t2 ON t1.col = t2.col | คืนค่าซ้ำได้ (ต้อง DISTINCT), อาจช้ากว่า |
| LEFT JOIN + IS NOT NULL | SELECT t1.Id FROM t1 LEFT JOIN t2 ON ... WHERE t2.col IS NOT NULL | เทียบเท่า INNER JOIN |