2.2 Leading Zeros 🔥
นี่คือ bug ที่พบบ่อยที่สุดในงาน data — ทุกคนเจอ ไม่มียกเว้น คุณเปิดไฟล์ CSV ใน Sheets แล้วรหัสนักเรียน
00123กลายเป็น123ทันที JOIN กับฐานข้อมูลเดิมไม่ได้ ข้อมูลกลายเป็นขยะ
สมมติฐานข้อมูลมีนักเรียน:
| student_id (VARCHAR) | name |
|---|---|
| 00123 | Ploy |
| 00456 | Som |
| 00789 | Tong |
ขั้นตอนที่ทำ bug:
- Export เป็น CSV →
student_idยังเป็น00123 - เปิด CSV ใน Google Sheets → Sheets เห็น
00123คิดว่าเป็น “ตัวเลข” → ตัด leading zeros →123 - พยายาม JOIN กลับ →
123 ≠ 00123→ ไม่ match!
ทำไมมันเกิดขึ้น
Section titled “ทำไมมันเกิดขึ้น”กฎง่ายๆ: ตัวเลข 123 กับ 00123 เป็นค่าเดียวกัน (หนึ่งร้อยยี่สิบสาม) แต่ text "123" กับ "00123" เป็น คนละค่า
เครื่องมือที่ “ช่วยเยอะ” (เช่น Sheets, Excel) จะพยายาม auto-detect type — ถ้ามันเห็นค่าที่หน้าตาเป็นตัวเลข มันจะแปลงให้ → leading zeros หาย
กฎทอง:
ทดลอง 1: เห็นปัญหา
Section titled “ทดลอง 1: เห็นปัญหา”- เปิด Sheet ใหม่
- พิมพ์
00123ในเซลล์ A1 → Sheets เปลี่ยนเป็น123ทันที! - ลอง
=A1→ ได้123(leading zeros หายแล้ว กู้คืนไม่ได้)
ทดลอง 2: วิธีป้องกัน
Section titled “ทดลอง 2: วิธีป้องกัน”วิธี 1: ใส่ apostrophe นำหน้า
- พิมพ์
'00123ในเซลล์ B1 → แสดงเป็น00123(text) =ISTEXT(B1)→ TRUE=ISNUMBER(B1)→ FALSE
วิธี 2: Format cell ก่อนพิมพ์
- เลือก column C → Format → Number → Plain text
- พิมพ์
00123ใน C1 → leading zeros อยู่ครบ!
วิธี 3: Import CSV อย่างปลอดภัย
- ไปที่ File → Import
- เลือก “Convert text to numbers, dates, and formulas” → No
- ทุก column จะถูก import เป็น text → leading zeros อยู่ครบ
ทดลอง 3: เปรียบเทียบ
Section titled “ทดลอง 3: เปรียบเทียบ”=A1=B1 → FALSE (123 ≠ "00123")=A1=123 → TRUE (123 = 123)=B1="00123" → TRUE ("00123" = "00123")#include <stdio.h>#include <string.h>#include <stdlib.h>
int main() { // ถูก: เก็บ ID เป็น text char id_text[] = "00123"; printf("Text ID: \"%s\" (len=%zu)\n", id_text, strlen(id_text)); // Text ID: "00123" (len=5)
// ผิด: เก็บ ID เป็น integer int id_num = 00123; // C ตีความเลขนำด้วย 0 เป็น octal! printf("Numeric ID: %d\n", id_num); // Numeric ID: 83 (!!) — 00123 ในฐาน 8 = 83 ในฐาน 10
// ถูก: ถ้าจะแปลง text → int ต้องทำชัดเจน int parsed = atoi("00123"); printf("Parsed: %d\n", parsed); // Parsed: 123 — leading zeros หาย
// ถ้าต้องการ leading zeros กลับ ต้อง format printf("Formatted: %05d\n", parsed); // Formatted: 00123 — ใช้ %05d เพื่อเติม 0 นำ
// แต่ถ้าความยาวไม่แน่นอน (บาง ID 3 หลัก บาง 5 หลัก) // → ไม่มีทางรู้ว่าต้องเติม 0 กี่ตัว → เก็บเป็น text เสมอ!
return 0;}Key insight: ใน C ตัวเลขที่ขึ้นต้นด้วย 0 ถูกตีความเป็น octal (ฐาน 8) → 00123 = 83 ในฐาน 10 — ยิ่งอันตรายกว่า Sheets!
import pandas as pd
# ปัญหา: อ่าน CSV โดยไม่ระบุ dtype# สมมติไฟล์ students.csv มีเนื้อหา:# student_id,name# 00123,Ploy# 00456,Som# 00789,Tong
# วิธีผิดdf_bad = pd.read_csv('students.csv')print(df_bad)# student_id name# 0 123 Ploy ← leading zeros หาย!# 1 456 Som# 2 789 Tongprint(df_bad.dtypes)# student_id int64 ← pandas แปลงเป็นตัวเลข!
# วิธีถูก: ระบุ dtypedf_good = pd.read_csv('students.csv', dtype={'student_id': str})print(df_good)# student_id name# 0 00123 Ploy ← leading zeros อยู่ครบ!# 1 00456 Som# 2 00789 Tongprint(df_good.dtypes)# student_id object ← เก็บเป็น string
# วิธีปลอดภัยสุด: ทุก column เป็น string ก่อน แล้วค่อยแปลงทีหลังdf_safe = pd.read_csv('students.csv', dtype=str)สำหรับไม่มีไฟล์ — ลองสร้างเอง:
import io
csv_data = """student_id,name00123,Ploy00456,Som00789,Tong"""
# ผิดdf_bad = pd.read_csv(io.StringIO(csv_data))print(df_bad['student_id'].tolist()) # [123, 456, 789]
# ถูกdf_good = pd.read_csv(io.StringIO(csv_data), dtype={'student_id': str})print(df_good['student_id'].tolist()) # ['00123', '00456', '00789']-- ถูก: เก็บ ID เป็น VARCHARCREATE TABLE students_good ( student_id VARCHAR(10), name VARCHAR(50));
INSERT INTO students_good VALUES ('00123', 'Ploy');INSERT INTO students_good VALUES ('00456', 'Som');INSERT INTO students_good VALUES ('00789', 'Tong');
SELECT * FROM students_good;-- student_id | name-- 00123 | Ploy ← leading zeros อยู่ครบ
-- ผิด: เก็บ ID เป็น INTEGERCREATE TABLE students_bad ( student_id INTEGER, name VARCHAR(50));
INSERT INTO students_bad VALUES (00123, 'Ploy');INSERT INTO students_bad VALUES (00456, 'Som');
SELECT * FROM students_bad;-- student_id | name-- 123 | Ploy ← leading zeros หาย!
-- ปัญหา: JOIN ระหว่างตารางที่เก็บต่างกันSELECT g.name, b.nameFROM students_good gJOIN students_bad b ON g.student_id = CAST(b.student_id AS VARCHAR);-- ไม่ match! '00123' ≠ '123'
-- ต้อง pad ให้ตรงกันSELECT g.name, b.nameFROM students_good gJOIN students_bad b ON g.student_id = LPAD(CAST(b.student_id AS VARCHAR), 5, '0');-- ตอนนี้ match: LPAD('123', 5, '0') = '00123'กฎ: ID, รหัส, เบอร์โทร → ใช้ VARCHAR เสมอ ห้ามใช้ INTEGER
สรุปวิธีป้องกัน
Section titled “สรุปวิธีป้องกัน”| เครื่องมือ | วิธีป้องกัน |
|---|---|
| Google Sheets | ใส่ ' นำหน้า หรือ format column เป็น “Plain text” ก่อน import |
| C | เก็บ ID เป็น char[] ไม่ใช่ int |
| Python (pandas) | pd.read_csv(file, dtype={'id_col': str}) |
| SQL | ใช้ VARCHAR ไม่ใช่ INTEGER สำหรับ ID columns |