Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> MySQL

MySQL ใช้ FIND_IN_SET สำหรับ Comma-Separated Values ใน IN Operator

ปัญหา: 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_SETIN
InputString คั่น CommaList ของ Values
ReturnPosition (INT) หรือ 0Boolean (TRUE/FALSE)
NULL HandlingNULL ถ้า Arg ใดเป็น NULLNULL ถ้า Col เป็น NULL
Index Usageไม่ใช้ Index (Full Scan)ใช้ Index ได้
Performanceช้า (Function per Row)เร็ว

⚠️ ข้อจำกัดสำคัญ

  1. ไม่ใช้ Index ได้ - Full Table Scan เสมอ
  2. ไม่รองรับ Space: FIND_IN_SET('a', 'a, b') = 0 (เพราะมี Space)
  3. ไม่รองรับ Comma ใน Value: Value ที่มี Comma เองจะแยกผิด
  4. 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)$'