ปัญหาการใช้งานข้อมูลชนิด float บน MySQL เมื่อ select ค่ากลับออกมาแล้วได้ผลลัพท์ไม่เหมือนตอนที่ใส่เข้าไป
วันนี้ได้รับรายงานว่าเจอข้อผิดพลาดจากฐานข้อมูล MariaDB บนข้อมูลชนิด float โดยที่เมื่อใส่จำนวนเต็ม 1223484 หรือ 3660208 ในตอนที่ select ข้อมูลกลับออกมา กลับได้ค่าไม่เหมือนเดิม
ปัญหานี้เกิดกับข้อมูลชนิด FLOAT เท่านั้นนะครับ ผมเลยออกแบบการทดสอบตามนี้
สร้างตารางสำหรับทดสอบ
และใส่ข้อมูล 1223484 และ 3660208 ลงในตาราง
มาดูผลลัพท์กัน
จากรูปจะเห็นว่า ข้อมูลชนิด FLOAT เมื่อ select ออกมาแล้วได้ค่าไม่เหมือนตอนที่ใส่เข้าไป ในขณะที่ DECIMAL และ DOUBLE ไม่มีปัญหานี้
เอาจริงๆ ปัญหานี้ควรเกิดกับจุดทศนิยมมากกว่า เพราะมันเป็นข้อจำกัดที่รู้กันอยู่แล้ว และไม่ควรเกิดกับตัวเลขจำนวนเต็ม และยังอาจจะมีตัวเลขอื่นๆอีกที่สร้างปัญหานี้ได้ ดังนั้นผมแนะนำให้หลีกเลี่ยงปัญหานี้ด้วยการใช้ข้อมูลชนิดอื่นแทน ซึ่งผมเลือกเป็น DOUBLE หรือ REAL
วิธีการเปลี่ยนชนิดของข้อมูล มี 2 แนวทาง
แนวทางแรกมีขั้นตอนดังนี้
แนวทางแรกเหมาะกับคอลัมน์ที่เก็บเป็นเลขจำนวนเต็มเท่านั้นนะครับ แต่ไม่เหมาะกับคอลัมน์ที่เก็บเลขทศนิยม เนื่องจากข้อมูล FLOAT เมื่อแปลงเป็น DOUBLE แล้วจะได้ค่าที่เป็นทศนิยมที่ยาวกว่า และได้ค่าไม่เท่าเดิม ดังนั้นวิธีการแปลงด้วยวิธีแรกอาจทำให้ค่าที่จัดเก็บผิดพลาด (ในระดับจุดทศนิยม) ได้
วิธีการแปลงของผมสำหรับเคสแบบนี้ คือ
ปัญหานี้เกิดกับข้อมูลชนิด FLOAT เท่านั้นนะครับ ผมเลยออกแบบการทดสอบตามนี้
สร้างตารางสำหรับทดสอบ
CREATE TABLE `test` (
`decimal` decimal(10,0) NOT NULL,
`float` float NOT NULL,
`double` double NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
และใส่ข้อมูล 1223484 และ 3660208 ลงในตาราง
INSERT INTO `test` (`decimal`, `float`, `double`) VALUES
('1223484', 1223484, 1223484),
('3660208', 3660208, 3660208);
มาดูผลลัพท์กัน
จากรูปจะเห็นว่า ข้อมูลชนิด FLOAT เมื่อ select ออกมาแล้วได้ค่าไม่เหมือนตอนที่ใส่เข้าไป ในขณะที่ DECIMAL และ DOUBLE ไม่มีปัญหานี้
เอาจริงๆ ปัญหานี้ควรเกิดกับจุดทศนิยมมากกว่า เพราะมันเป็นข้อจำกัดที่รู้กันอยู่แล้ว และไม่ควรเกิดกับตัวเลขจำนวนเต็ม และยังอาจจะมีตัวเลขอื่นๆอีกที่สร้างปัญหานี้ได้ ดังนั้นผมแนะนำให้หลีกเลี่ยงปัญหานี้ด้วยการใช้ข้อมูลชนิดอื่นแทน ซึ่งผมเลือกเป็น DOUBLE หรือ REAL
วิธีการเปลี่ยนชนิดของข้อมูล มี 2 แนวทาง
แนวทางแรกมีขั้นตอนดังนี้
- เพิ่มคอลัมน์ใหม่เป็นชนิดข้อมูลที่ต้องการลงในตาราง
เราจะได้คอลัมน์ float2 ชนิด REAL เพิ่มมา - อัปเดทข้อมูลจากคอลัมน์ float ไปยัง float2
UPDATE `test` SET `float2`=`float`
จะเห็นว่าข้อมูลในคอลัมน์ float2 ที่ copy มาจาก float เป็นข้อมูลที่ถูกต้อง แต่เมื่อ select ออกมามันผิด - สุดท้าย ลบคอลัมน์เก่า และเปลี่ยนชื่อ float2 ให้เป็น float แทน ALTER TABLE `test` DROP `float`;
ALTER TABLE `test` CHANGE `float2` `float` REAL NOT NULL;
แนวทางแรกเหมาะกับคอลัมน์ที่เก็บเป็นเลขจำนวนเต็มเท่านั้นนะครับ แต่ไม่เหมาะกับคอลัมน์ที่เก็บเลขทศนิยม เนื่องจากข้อมูล FLOAT เมื่อแปลงเป็น DOUBLE แล้วจะได้ค่าที่เป็นทศนิยมที่ยาวกว่า และได้ค่าไม่เท่าเดิม ดังนั้นวิธีการแปลงด้วยวิธีแรกอาจทำให้ค่าที่จัดเก็บผิดพลาด (ในระดับจุดทศนิยม) ได้
วิธีการแปลงของผมสำหรับเคสแบบนี้ คือ
- เปลี่ยนคอลัมน์เป็นชนิด VARCHAR(50) ซึ่งความยาว 50 ขึ้นกับข้อมูลที่จัดเก็บนะครับ วิธีนี้จะทำให้ได้ค่าที่จัดเก็บเป็นตัวเลขเดิม
- เปลี่ยนข้อลัมน์เป็นชนิดที่ต้องการ (REAL หรือ DOUBLE) อีกที