ปัญหา: เปรียบเทียบ String ที่มีตัวเลข
String Comparison ทำงานแบบ Lexicographical (ตัวอักษร):
'10' > '2' -- FALSE เพราะ '1' < '2'
'5-9' > '4-8' -- TRUE แต่ไม่ได้หมายความว่า 5 > 4 ในทุกกรณี
การเตรียมข้อมูล
mysql> CREATE TABLE DemoTable1881 (
UserId INT,
UserEducationGap VARCHAR(20)
);
mysql> INSERT INTO DemoTable1881 VALUES
(101, '5-9'), (102, '2-4'), (103, '4-8'), (104, '7-12');
เปรียบเทียบส่วนตัวเลขแรก (ก่อน Hyphen)
mysql> SELECT * FROM DemoTable1881
WHERE CAST(SUBSTRING(UserEducationGap, 1, INSTR(UserEducationGap, '-') - 1) AS SIGNED) >= 4;
ผลลัพธ์ (5-9, 4-8, 7-12 มีตัวเลขแรก >= 4):
+--------+------------------+
| UserId | UserEducationGap |
+--------+------------------+
| 101 | 5-9 |
| 103 | 4-8 |
| 104 | 7-12 |
+--------+------------------+
การแยกส่วนตัวเลข
-- SUBSTRING(str, start, length)
-- INSTR(str, substr) หาตำแหน่ง substr ใน str
-- '5-9': INSTR('-') = 2, SUBSTRING(1, 1) = '5'
-- '7-12': INSTR('-') = 2, SUBSTRING(1, 1) = '7'
-- '10-20': INSTR('-') = 3, SUBSTRING(1, 2) = '10'
ปรับปรุงรองรับหลายหลัก
SELECT * FROM DemoTable1881
WHERE CAST(SUBSTRING_INDEX(UserEducationGap, '-', 1) AS SIGNED) >= 4;
-- SUBSTRING_INDEX ใช้งานง่ายกว่า: ส่วนก่อน - ตัวแรก
CAST vs CONVERT
CAST(expr AS type)
CONVERT(expr, type)
-- SIGNED = Signed Integer
-- UNSIGNED = Unsigned Integer
-- DECIMAL(m,d) = ทศนิยม
-- CHAR(N) = String
แนวทางแก้ไขข้อมูล (Best Practice)
-- แยกเก็บ Min/Max แทน String Range
CREATE TABLE education_gaps (
user_id INT,
gap_min INT,
gap_max INT
);
-- Query ง่ายและใช้ Index ได้
SELECT * FROM education_gaps WHERE gap_min >= 4;
ข้อสรุป
- หลีกเลี่ยงเก็บ Numeric Range ใน String
- ถ้าบังคับต้อง Query ให้ Parse ออกมาก่อน (SUBSTRING_INDEX + CAST)
- Performance: Full Scan, ไม่ใช้ Index