ปัญหา: IN Operator ไม่รองรับ Comma-Separated String
WHERE col IN ('A,B,C') จะค้นหาค่า 'A,B,C' ทั้งสตริง ไม่ใช่ 3 ค่าแยกกัน
Solution: FIND_IN_SET()
FIND_IN_SET(str, comma_separated_list) คืนค่า Position (1-based) ของ str ในรายการ คืน 0 ถ้าไม่เจอ
ตัวอย่าง
CREATE TABLE DemoTable604 (
Id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Title VARCHAR(100)
);
INSERT INTO DemoTable604(Title) VALUES
('MySQL'), ('C++'), ('MongoDB'), ('Java');
Query: หา Title ที่อยู่ใน 'C++,MongoDB'
SELECT * FROM DemoTable604
WHERE FIND_IN_SET(Title, 'C++,MongoDB');
ผลลัพธ์:
+----+---------+
| Id | Title |
+----+---------+
| 2 | C++ |
| 3 | MongoDB |
+----+---------+
FIND_IN_SET vs IN
| คุณสมบัติ | FIND_IN_SET | IN |
|---|---|---|
| Input | String คั่น Comma | List ของ Values |
| Return | Position (INT) หรือ 0 | Boolean (TRUE/FALSE) |
| NULL Handling | NULL ถ้า Arg ใดเป็น NULL | NULL ถ้า Col เป็น NULL |
| Index Usage | ไม่ใช้ Index (Full Scan) | ใช้ Index ได้ |
| Performance | ช้า (Function per Row) | เร็ว |
⚠️ ข้อจำกัดสำคัญ
- ไม่ใช้ Index ได้ - Full Table Scan เสมอ
- ไม่รองรับ Space:
FIND_IN_SET('a', 'a, b')= 0 (เพราะมี Space) - ไม่รองรับ Comma ใน Value: Value ที่มี Comma เองจะแยกผิด
- Max Length: String Argument จำกัดความยาว
Best Practice: Normalize Data
แทนที่จะเก็บ Comma-Separated ให้สร้าง Junction Table (Many-to-Many)
-- แทนที่จะเก็บ tags = 'mysql,php,java'
CREATE TABLE posts (id INT PRIMARY KEY, title VARCHAR(100));
CREATE TABLE tags (id INT PRIMARY KEY, name VARCHAR(50));
CREATE TABLE post_tags (post_id INT, tag_id INT, PRIMARY KEY(post_id, tag_id));
-- Query ด้วย JOIN (ใช้ Index ได้)
SELECT p.* FROM posts p
JOIN post_tags pt ON p.id = pt.post_id
JOIN tags t ON pt.tag_id = t.id
WHERE t.name IN ('mysql', 'php');
กรณีบังคับต้องใช้ FIND_IN_SET (Legacy Data)
-- Trim Space ก่อน
WHERE FIND_IN_SET(TRIM(Title), REPLACE('C++, MongoDB', ' ', ''))
-- หรือใช้ REGEXP (MySQL 8.0+)
WHERE Title REGEXP '^(C\\+\\+|MongoDB)$'