การย้ายข้อมูลจาก Legacy System (ระบบเก่าที่งานสำคัญยังพึ่งพาแต่ดูแลหรือแก้ไขยาก) คือการดึงข้อมูลจากระบบเดิม แปลงให้เข้ากับโครงสร้างของระบบใหม่ ทำความสะอาดตามกติกาที่เจ้าของข้อมูลตกลง แล้วพิสูจน์ด้วยการกระทบยอดว่าข้อมูลครบและความหมายไม่เปลี่ยนก่อนสลับไปใช้ระบบใหม่ ในระบบของไทย จุดที่ทำให้ข้อมูลเสียโดยไม่มี error คือภาษาไทยที่เก็บเป็น TIS-620 หรือ Windows-874 ปี พ.ศ. ที่อยู่ในช่องวันที่แบบ ค.ศ. และข้อความที่พิมพ์อิสระ ทั้งหมดตรวจได้ถ้าวางขั้นตรวจไว้ตั้งแต่รอบซ้อมแรก

สรุปสั้น: เริ่มจาก profile ข้อมูลต้นทางทุกตารางที่จะย้าย รวมถึง encoding ของข้อความไทยและช่วงปีในช่องวันที่ ทำตาราง mapping ที่เจ้าของข้อมูลรับรองกติกาการแก้ข้อมูล ซ้อมย้ายด้วยข้อมูลขนาดจริงและจับเวลาจนผลซ้ำได้ กระทบยอดหลายชั้นตั้งแต่จำนวนแถว ยอดรวมรายงวด hash รายระเบียน จนถึงรายงานที่ผู้ใช้เทียบเอง แล้วจึงตัดสิน go/no-go ใน cutover ที่มีช่วงหยุดรับข้อมูลและทางถอยกลับ ปิดระบบเก่าเมื่อมี backup สุดท้ายและกำหนดระยะเก็บรักษาแล้ว ส่วนเรื่อง PDPA ในบทความเป็นการตีความเพื่อประกอบการวางแผน ไม่ใช่คำแนะนำทางกฎหมาย

บทความนี้เขียนสำหรับทีม IT เจ้าของระบบ และผู้รับจ้างที่ต้องรับผิดชอบให้ข้อมูลย้ายไปครบ เนื้อหาเน้นฝั่งข้อมูล คำสั่งตัวอย่างให้ลองกับสำเนาข้อมูลเท่านั้น เอกสารที่อ้างถึงตรวจ ณ วันที่ 8 พฤศจิกายน 2026

ทำไมการย้ายข้อมูลมักเป็นส่วนที่เสี่ยงที่สุดของการเปลี่ยนระบบเก่า?

เพราะข้อมูลที่ผิดมักไม่ทำให้ระบบล่ม ระบบใหม่เปิดได้ หน้าจอแสดงผลได้ แต่ยอดในรายงานไม่ตรง ชื่อลูกค้าบางรายอ่านไม่ออก หรือวันที่เลื่อนไป 543 ปี และมักพบหลังผู้ใช้ทำงานบนระบบใหม่ไปแล้ว ซึ่งถึงตอนนั้นการถอยกลับยากกว่าก่อน cutover มาก

โค้ดของระบบใหม่ทดสอบได้กับ requirement แต่ข้อมูลในระบบเก่าสะสมกติกาที่ไม่มีใครเขียนไว้ เช่น รหัสสถานะที่เลิกใช้แล้วแต่ยังอยู่ในข้อมูลปีเก่า ช่องที่ผู้ใช้เอาไปเก็บข้อมูลอย่างอื่น หรือข้อมูลที่ถูกแก้ตรงในฐานข้อมูลโดยไม่ผ่านโปรแกรม แนวทางการย้ายฐานข้อมูลของ Google Cloud จึงให้ทดสอบการย้ายข้อมูลอย่างละเอียดและซ้ำหลายรอบ เพื่อให้ข้อมูลทุกรายการที่รู้จักย้ายไปโดยไม่มีข้อผิดพลาดจากการแปลง และเตือนว่าถ้ามีค่าใหม่ที่ไม่เคยเห็นปรากฏในต้นทาง กระบวนการย้ายอาจล้มเหลวได้

คู่มือการ implement Dynamics 365 ของ Microsoft ระบุว่าระบบเดิม (legacy system) อาจเป็นแอปพลิเคชันทางธุรกิจอีกตัว หรือเป็นชุดไฟล์ Excel ก็ได้ และกำหนดบทบาท data steward ซึ่งเป็นผู้ให้นิยามและกติกาของข้อมูล หลักนี้ใช้ได้กับทุกระบบ คือคนที่ตัดสินว่าข้อมูลใดถูกต้องควรเป็นเจ้าของข้อมูลฝั่งธุรกิจ ไม่ใช่ผู้เขียนสคริปต์ย้ายข้อมูล

การย้ายข้อมูลจากระบบเก่ามีขั้นตอนอะไรบ้าง?

แบ่งได้เจ็ดขั้น ขั้นที่ 1–5 ทำซ้ำหลายรอบก่อนวันจริง ส่วนขั้นที่ 6–7 ทำครั้งเดียว

  1. สำรวจและ profile ข้อมูลต้นทาง รู้ว่ามีตารางและไฟล์อะไร ขนาดเท่าไร และข้อมูลจริงหน้าตาเป็นอย่างไร
  2. ทำ mapping ไปยังโครงสร้างใหม่ ทุกคอลัมน์ปลายทางมีที่มาและกติกาแปลง
  3. ตกลงกติกาทำความสะอาดข้อมูลกับเจ้าของข้อมูล ข้อมูลที่ผิดหรือขาดจะแก้ ทิ้ง หรือย้ายไปตามเดิมพร้อมเครื่องหมาย
  4. ซ้อมย้าย (trial migration) ด้วยข้อมูลขนาดจริง จับเวลา และแก้จนผลซ้ำได้
  5. กระทบยอด (reconciliation) พิสูจน์ว่าครบและถูกต้อง โดยมีผู้ลงนามรับผล
  6. Cutover หยุดรับข้อมูลในระบบเก่า ย้ายส่วนต่างสุดท้าย กระทบยอด ตัดสิน go/no-go และมีทางถอยกลับ
  7. ปิดระบบเก่าและเก็บรักษาข้อมูลเดิม ตามระยะเวลาที่กฎหมายและธุรกิจต้องการ แล้วลบอย่างมีหลักฐาน

คู่มือ Dynamics 365 ฉบับเดียวกันแนะนำให้ทดสอบและตรวจการย้ายข้อมูลอย่างน้อยหนึ่งครั้งในสภาพแวดล้อม SIT และ UAT และระบุว่างานย้ายข้อมูลรบกวนงานอื่นได้ จึงไม่ควรทำพร้อมกับการทดสอบอื่น ข้อนี้มีผลต่อแผนงาน เพราะรอบซ้อมย้ายต้องมีช่วงเวลาและสภาพแวดล้อมของตัวเอง

Profile ข้อมูลต้นทางต้องดูอะไรบ้าง?

ดูข้อมูลจริง ไม่ใช่เฉพาะ schema เพราะ schema บอกว่าคอลัมน์เป็น VARCHAR แต่ไม่บอกว่าข้างในเป็นภาษาไทย encoding ใด อย่างน้อยควรมีตัวเลขเหล่านี้ของทุกคอลัมน์สำคัญ

  • จำนวนแถว จำนวนค่าว่าง และจำนวนค่าที่ไม่ซ้ำ
  • ค่าต่ำสุดและสูงสุดของวันที่และตัวเลข ซึ่งทำให้เห็นปี พ.ศ. ที่ปนอยู่ทันที
  • ความยาวสูงสุดของข้อความ ทั้งนับเป็นตัวอักษรและนับเป็นไบต์
  • encoding ของข้อความไทย (วิธีตรวจอยู่ในหัวข้อถัดไป)
  • รหัสที่ใช้จริงในคอลัมน์สถานะหรือประเภท เทียบกับรายการที่เอกสารบอก
  • ระเบียนซ้ำตามคีย์ทางธุรกิจ เช่น ลูกค้าคนเดียวกันที่มีหลายรหัส

ถ้ายังไม่มีรายการระบบและฐานข้อมูลที่เชื่อถือได้ ให้สร้างจากระบบที่รันอยู่ก่อนตามวิธีสำรวจระบบเก่าที่ไม่มีเอกสาร และถ้าระบบอยู่กับผู้รับจ้างรายเดิม ให้ได้สิทธิ์เข้าถึงฐานข้อมูลและ backup ที่กู้คืนได้ตามรายการรับมอบจากผู้รับจ้างเดิมก่อนเริ่ม profile

ตาราง mapping และกติกาทำความสะอาดข้อมูลควรมีอะไร?

ตาราง mapping ใช้หนึ่งแถวต่อหนึ่งคอลัมน์ปลายทาง ระบุคอลัมน์ต้นทาง กติกาแปลง ค่าที่ใช้เมื่อต้นทางว่าง ผู้ตัดสินกติกา และวันที่ตกลง กติกาทำความสะอาดควรตัดสินโดยเจ้าของข้อมูล เช่น ลูกค้าซ้ำจะรวมหรือไม่ ใบแจ้งหนี้ที่ปิดแล้วต้องย้ายทั้งหมดหรือย้ายเฉพาะยอดคงค้าง และข้อมูลที่ตรวจไม่ผ่านจะแก้ก่อนย้าย แก้หลังย้าย หรือย้ายไปพร้อมเครื่องหมายว่ารอตรวจ

อย่าแก้ข้อมูลเงียบ ๆ ในสคริปต์ ทุกกติกาที่เปลี่ยนค่าควรมีรายงานจำนวนแถวที่ถูกแก้ และเก็บค่าเดิมไว้ในตารางพักหรือคอลัมน์แยก เพื่อให้ตรวจย้อนได้เมื่อผู้ใช้ถามว่าข้อมูลของตนเปลี่ยนไปเพราะอะไร

ภาษาไทยในระบบเก่าเก็บด้วย encoding อะไรได้บ้าง?

ระบบไทยที่สร้างก่อนใช้ Unicode มักเก็บภาษาไทยแบบหนึ่งไบต์ต่อตัวอักษรด้วย TIS-620 หรือ Windows-874 ส่วนระบบใหม่ใช้ UTF-8 ซึ่งใช้สามไบต์ต่อตัวอักษรไทย ความต่างที่ต้องรู้ก่อนแปลงมีดังนี้

Encoding ภาษาไทยที่พบในระบบเก่า (สรุปจากทะเบียนของ IANA ตาราง mapping ของ Unicode และเอกสารของ Microsoft)
Encodingข้อเท็จจริงที่เกี่ยวกับการย้ายข้อมูล
TIS-620IANA ขึ้นทะเบียนโดยระบุที่มาเป็นสำนักงานมาตรฐานผลิตภัณฑ์อุตสาหกรรม (TISI) และมี ISO-8859-11 เป็นชื่อแฝง (alias) อักษรไทยอยู่ที่ไบต์ 0xA1 (ก) ถึง 0xFB
ISO-8859-11ตาราง mapping ของ Unicode ระบุว่าเทียบเท่า TIS 620-2533 บวก NO-BREAK SPACE ที่ 0xA0 ส่วนไบต์ 0x80–0x9F เป็นอักขระควบคุม
Windows-874 (cp874)Microsoft ใช้ code page 874 ชื่อ windows-874 สำหรับภาษาไทย ตามตาราง cp874 อักษรไทยอยู่ตำแหน่งเดียวกับ TIS-620 แต่ใช้ไบต์บางตัวในช่วง 0x80–0x97 เป็นเครื่องหมาย เช่น 0x80 €, 0x85 …, 0x91–0x94 อัญประกาศโค้ง, 0x95 •, 0x96 – และ 0x97 —
UTF-8อักษรไทยอยู่ในช่วง U+0E00–U+0E7F ซึ่งใช้สามไบต์ต่อตัว ขึ้นต้นด้วย E0 B8 หรือ E0 B9

ผลในทางปฏิบัติคือ ข้อความที่พิมพ์จากโปรแกรมบน Windows อาจมีอัญประกาศโค้ง ขีดยาว หรือเครื่องหมายสามจุดที่เป็นไบต์ของ cp874 ถ้าถอดรหัสด้วย TIS-620 แบบเคร่งครัด ไบต์เหล่านี้จะกลายเป็นอักขระควบคุมหรือแปลงไม่ได้ ส่วนอักษรไทยไม่กระทบ จึงควรถอดรหัสข้อมูลที่มาจาก Windows ด้วย cp874 และนับไบต์ในช่วง 0x80–0x9F ก่อนแปลงทุกครั้ง Microsoft เองเตือนว่า ANSI code page อาจต่างกันระหว่างเครื่อง ซึ่งทำให้ข้อมูลเสียได้ และแนะนำให้แอปพลิเคชันใช้ Unicode เช่น UTF-8 หรือ UTF-16

ตามมาตรฐาน Unicode บทที่ 16 ผังอักษรไทยใน Unicode อิงมาตรฐาน TIS 620-2529 และฉบับปรับปรุง 620-2533 และสระหน้า เช่น เ แ โ ใ ไ ถูกพิมพ์และเก็บไว้ก่อนพยัญชนะ ตาราง mapping แปลงไบต์ของ TIS-620 เป็น code point ทีละตัวแบบหนึ่งต่อหนึ่ง ปัญหาจึงมักไม่ได้อยู่ที่ตารางแปลง แต่อยู่ที่การรู้ให้แน่ว่าไบต์ที่มีอยู่เป็น encoding ใด

ภาษาไทยเพี้ยนหลังย้ายฐานข้อมูล หน้าตาแบบไหน?

ภาษาไทยเพี้ยน หรือที่มักเรียกกันว่า "ภาษาต่างดาว" (mojibake) เกิดเมื่อไบต์ถูกอ่านด้วย encoding ที่ไม่ใช่ตัวที่ใช้เขียน และรูปแบบที่เห็นบอกได้ว่าผิดตรงไหน ตัวอย่างด้านล่างเราสร้างด้วย codec ของ Python

  • "ภาษา" กลายเป็น เธ เธฒเธฉเธฒ ไบต์ UTF-8 ถูกแสดงเป็น cp874 หรือ TIS-620 สังเกตได้จาก "เธ" หรือ "เน" ที่ขึ้นต้นซ้ำทุกตัว
  • "จังหวัด" กลายเป็น จังหวัด ไบต์ UTF-8 ถูกแสดงเป็น cp1252 (ซึ่งเป็น latin1 ของ MySQL) ถ้าเป็น Latin-1 แบบเคร่งครัด บางตัวจะเป็นอักขระควบคุมที่มองไม่เห็น
  • "ภาษา" กลายเป็น ÀÒÉÒ ไบต์ TIS-620 ถูกแสดงเป็น Latin-1 พบเมื่อภาษาไทยถูกเก็บในคอลัมน์ที่ประกาศเป็น latin1
  • ภาษาไทยกลายเป็น � ปนกับอักขระแปลก ๆ ที่ไม่ใช่ภาษาไทย ไบต์ TIS-620 ถูกอ่านเป็น UTF-8 ไบต์ส่วนใหญ่ไม่ใช่ลำดับไบต์ UTF-8 ที่ถูกต้อง จึงถูกแทนด้วยอักขระทดแทน (U+FFFD) บางคู่ไบต์บังเอิญเป็น UTF-8 ที่ถูกต้องจึงกลายเป็นอักขระภาษาอื่น ถ้าข้อความถูกบันทึกกลับในสภาพนี้ ข้อมูลเดิมในแถวนั้นหายไปแล้ว ต้องดึงจากต้นทางใหม่
  • Double encoding ข้อความ UTF-8 ถูกตีความเป็น Latin-1 แล้วเข้ารหัสเป็น UTF-8 ซ้ำ ไบต์ของอักษรไทยแต่ละตัวจะขึ้นต้นด้วย C3 A0 C2 B8 หรือ C3 A0 C2 B9 กรณีนี้ย้อนกลับได้ถ้าไม่มีการแก้ข้อความหลังจากนั้น (ถอดรหัส UTF-8 เข้ารหัสกลับด้วย charset เดียวกับที่ทำให้เพี้ยน ถ้าผ่านการเชื่อมต่อ latin1 ของ MySQL ให้ใช้ cp1252 เพราะMySQL ระบุว่า latin1 ของ MySQL คือ cp1252 แล้วถอดรหัสเป็น UTF-8 อีกครั้ง) เอกสารเดียวกันระบุว่าไบต์ 0x81, 0x8D, 0x8F, 0x90 และ 0x9D ซึ่ง cp1252 ไม่ได้กำหนดอักขระไว้ MySQL แปลงเป็น U+0081, U+008D, U+008F, U+0090 และ U+009D ถ้าย้อนกลับนอก MySQL ด้วย codec cp1252 แบบเคร่งครัด อักษรอย่าง ก (E0 B8 81) จะ error ต้องจัดการไบต์ทั้งห้าตัวนี้เอง ให้ลองกับสำเนาและเทียบกับต้นฉบับก่อน

ตรวจ encoding ของข้อมูลไทยในฐานข้อมูลอย่างไร?

ดูที่ไบต์ ไม่ใช่ที่หน้าจอ เพราะสิ่งที่เห็นบนหน้าจอผ่านการแปลงของ client มาแล้ว ใน MySQL ฟังก์ชัน HEX() แสดงทุกไบต์ของข้อความเป็นเลขฐานสิบหก LENGTH() นับเป็นไบต์ และ CHAR_LENGTH() นับเป็น code point เช่น

SELECT HEX(name), LENGTH(name), CHAR_LENGTH(name) FROM customer LIMIT 20;

  • UTF-8 ที่ถูกต้อง อักษรไทยแต่ละตัวขึ้นต้นด้วย E0B8 หรือ E0B9 และถ้าข้อความเป็นภาษาไทยล้วน LENGTH เท่ากับสามเท่าของ CHAR_LENGTH
  • Double encoding เห็น C3A0C2B8 หรือ C3A0C2B9 ซ้ำ ๆ
  • TIS-620 หรือ cp874 ในคอลัมน์ที่ประกาศเป็น latin1 เห็นไบต์เดี่ยวในช่วง A1–FB

ตรวจ charset ของการเชื่อมต่อด้วย ตามเอกสาร MySQL เซิร์ฟเวอร์ถือว่าคำสั่งที่ client ส่งมาอยู่ใน character_set_client และส่งผลลัพธ์กลับด้วย character_set_results ถ้า client ส่งไบต์ TIS-620 แต่ประกาศว่าเป็น charset อื่น ข้อมูลที่บันทึกจะผิดตั้งแต่ต้น ตรวจค่าที่ใช้อยู่ได้ด้วย SHOW SESSION VARIABLES LIKE 'character_set_%';

ใน PostgreSQL ให้ดู encoding ของฐานข้อมูลก่อน ถ้าเป็น SQL_ASCII เอกสาร PostgreSQL ระบุว่าจะไม่มีการแปลงหรือตรวจไบต์ 128–255 เลย และอธิบายว่าค่านี้เป็นการประกาศว่าไม่รู้ encoding มากกว่าจะบอกว่าใช้ encoding ใด ฐานข้อมูลแบบนี้อาจมีภาษาไทยหลาย encoding ปนกัน ต้อง profile เป็นรายแถว

แปลง TIS-620 เป็น UTF-8 อย่างไรไม่ให้ตัวอักษรหาย?

หลักคือแปลงครั้งเดียวจาก encoding ที่ตรวจแล้วว่าถูก และนับให้ได้ว่ามีอะไรแปลงไม่ได้ ตัวอย่างเครื่องมือตามชนิดของต้นทาง

  • ไฟล์ export ใช้ iconv GNU libiconv รองรับ ISO-8859-11, TIS-620 และ CP874 ไฟล์ที่มาจาก Windows ให้ใช้ CP874 เช่น iconv -f CP874 -t UTF-8 old.csv > new.csv อย่าใช้ตัวเลือก -c กับข้อมูลจริง เพราะตามคู่มือตัวเลือกนี้ทิ้งอักขระที่แปลงไม่ได้โดยไม่แจ้ง ถ้าต้องการหาไบต์ที่เสีย iconv ของ GNU libiconv มี --byte-subst ที่แทนไบต์ผิดด้วยข้อความที่มองเห็นได้ (iconv ที่มากับ glibc บน Linux ส่วนใหญ่ไม่มีตัวเลือกนี้ ดูคู่มือ iconv ของ Linux) ส่วน iconv บน macOS เป็นคนละรุ่นและตัวเลือกต่างกัน ตรวจชื่อ encoding ที่รองรับด้วย iconv -l
  • คอลัมน์ MySQL ที่ประกาศ charset ผิด เอกสาร MySQL ให้แปลงคอลัมน์เป็นชนิด binary ก่อน เพื่อลบข้อมูล charset โดยไม่แปลงไบต์ แล้วจึงแปลงเป็นชนิดข้อความที่ระบุ charset ที่ถูก เช่น ALTER TABLE t MODIFY col BLOB; ตามด้วย ALTER TABLE t MODIFY col VARCHAR(100) CHARACTER SET tis620; แล้วจึงแปลงเป็น utf8mb4 เอกสารเดียวกันเตือนว่าวิธีนี้ใช้ไม่ได้ถ้าคอลัมน์มีหลาย encoding ปนกัน การแปลงอาจทำให้ข้อมูลหายถ้ามีอักขระที่ไม่อยู่ในทั้งสอง charset ต้องระบุ NOT NULL และ DEFAULT ใหม่ และการเปลี่ยน charset ต้องใช้ ALGORITHM=COPY ถ้าต้นทางมาจาก Windows ให้นับแถวที่มีไบต์ 0x80–0x9F ก่อน เช่น SELECT COUNT(*) FROM t WHERE HEX(col) REGEXP '^(..)*[89]'; (ใช้กับคอลัมน์ที่ยังเก็บเป็นไบต์เดี่ยวเท่านั้น ไม่ใช่คอลัมน์ utf8mb4 ที่แปลงแล้ว) เพราะไบต์กลุ่มนี้คือส่วนที่ cp874 กับ TIS-620 ต่างกัน ถ้าพบ ให้ทดลองกับสำเนาและตรวจผลก่อน
  • MySQL ปลายทาง ใช้ utf8mb4 ไม่ใช่ utf8 เพราะเอกสาร MySQL ระบุว่า utf8 เป็นชื่อแฝงของ utf8mb3 ซึ่งถูกประกาศ deprecated แล้ว และแนะนำ utf8mb4 สำหรับแอปพลิเคชันใหม่
  • PostgreSQL รองรับ WIN874 (Windows CP874) เป็น encoding ของเซิร์ฟเวอร์และแปลงไป UTF8 ได้ แต่ไม่มี TIS620 ในตาราง encoding ถ้าโหลดไบต์ดิบเข้าคอลัมน์ bytea ในตารางพัก ใช้ convert_from แปลงเป็นข้อความในฐานข้อมูล UTF8 ได้ เช่น SELECT convert_from(raw_name, 'WIN874') FROM staging;
  • SQL Server เอกสารของ Microsoft ระบุว่าคอลัมน์ที่ไม่ใช่ Unicode (char/varchar) ใช้ code page ตาม collation ข้อมูลที่ย้ายระหว่างคอลัมน์แบบนี้ต้องแปลง code page collation เริ่มต้นของ locale ภาษาไทยคือ Thai_CI_AS ตั้งแต่ SQL Server 2019 collation ที่ลงท้าย _UTF8 ทำให้ char/varchar เก็บ UTF-8 ได้ และ Microsoft แนะนำ nchar/nvarchar สำหรับข้อมูลหลายภาษา

ขนาดคอลัมน์ต้องคิดใหม่ ใน MySQL ตัวเลขใน CHAR(M) และ VARCHAR(M) นับเป็นตัวอักษร และตาราง charset ระบุว่า tis620 ใช้สูงสุดหนึ่งไบต์ต่อตัว ส่วน utf8mb4 ใช้สูงสุดสี่ไบต์ ใน SQL Server ตัวเลข n ของ char/varchar คือจำนวนไบต์ ไม่ใช่จำนวนตัวอักษร และใน collation UTF-8 อักษรไทยใช้สามไบต์ต่อตัว ตัวอย่างในเอกสารของ Microsoft คือ char(10) เก็บอักขระช่วง 2048–65535 ได้เพียงสามตัว คอลัมน์ที่เคยพอสำหรับชื่อภาษาไทยใน code page แบบหนึ่งไบต์จึงอาจตัดข้อความเมื่อเปลี่ยนเป็น UTF-8

ลำดับการเรียงภาษาไทย (collation) เปลี่ยนหลังย้ายไหม?

อาจเปลี่ยน จึงต้องทดสอบ ไม่ใช่สมมติว่าเหมือนเดิม ใน MySQL 8.4 charset tis620 มี collation tis620_thai_ci เป็นค่าเริ่มต้น ส่วน utf8mb4 ใช้ utf8mb4_0900_ai_ci ซึ่งอิง UCA 9.0.0 และ CLDR v30 ไม่แยกตัวพิมพ์เล็กใหญ่และเครื่องหมายเสริม และตารางภาษาที่มี collation เฉพาะของ MySQL 8.4 ไม่มีภาษาไทย ส่วน utf8mb4_general_ci เป็น collation รุ่นเก่าที่ไม่รองรับ contraction

ตาม Unicode Collation Algorithm (UTS #10) สระหน้า เ ถึง ไ ถูกจัดการด้วย contraction ตั้งแต่ UCA 4.1 เพื่อให้เรียงเหมือนสลับกับพยัญชนะที่ตามมา collation ที่เทียบทีละอักขระโดยไม่มี contraction จึงไม่ได้ผลนี้ ส่วนกติกาเรียงภาษาไทยของ CLDR ปรับลำดับของไปยาลน้อย ไม้ยมก นิคหิต ลากข้าง และพินทุ ให้เรียงตามพจนานุกรมฉบับราชบัณฑิตยสถาน พ.ศ. 2542 ใน PostgreSQL คำสั่ง ORDER BY ใช้ collation ของคอลัมน์ที่เรียง collation จาก libc ขึ้นกับระบบปฏิบัติการ และ collation ของ ICU ตั้งชื่อตาม BCP 47 ต่อท้ายด้วย -x-icu (เอกสาร PostgreSQL)

วิธีตรวจที่ใช้ได้จริงคือเลือกรายงานที่ผู้ใช้พึ่งลำดับ เช่น รายชื่อเรียงตามชื่อ แล้วเทียบผลของระบบเก่ากับระบบใหม่ด้วยข้อมูลชุดเดียวกัน ถ้าต่าง ให้เจ้าของรายงานตัดสินว่าลำดับใดถูก แล้วจึงเลือก collation ของปลายทาง

ปี พ.ศ. ในช่องวันที่ ตรวจและแปลงเป็น ค.ศ. อย่างไร?

ตรวจด้วยการหาปีที่มากกว่าปีปัจจุบัน แล้วแปลงด้วยการลบ 543 จากปี หลังยืนยันกับเจ้าของข้อมูลว่าคอลัมน์นั้นบันทึกเป็น พ.ศ. จริง ปัญหาคือฐานข้อมูลไม่เตือน เพราะปี 2567 อยู่ในช่วงที่ชนิดข้อมูลวันที่ยอมรับ

  • MySQL DATE และ DATETIME รับปี 1000–9999 แต่ TIMESTAMP รับได้ถึง 2038-01-19 03:14:07 UTC ปี พ.ศ. จึงผ่าน DATE แต่ไม่ผ่าน TIMESTAMP และเมื่อปิด strict mode MySQL แปลงวันที่ที่ไม่ถูกต้องเป็น '0000-00-00'
  • PostgreSQL date รับถึงปี 5874897 และ SQL Server date รับ 0001-01-01 ถึง 9999-12-31 ตามปฏิทินเกรกอเรียน

ปฏิทินพุทธศักราชแบบไทยใช้เดือน วัน และปีอธิกสุรทินเหมือนปฏิทินเกรกอเรียน ต่างกันที่ปี ThaiBuddhistChronology ของ Java ระบุว่าปีในศักราชปัจจุบันเท่ากับปี ISO บวก 543 และกำหนดจุดเทียบให้ 1 มกราคม 2484 (พุทธ) ตรงกับ 1 มกราคม 1941 (ISO) ส่วน ThaiBuddhistCalendar ของ .NET ยกตัวอย่างว่า 1 มกราคม ค.ศ. 2001 ตรงกับ 1 มกราคม พ.ศ. 2544 ถ้ามีข้อมูลวันที่ก่อนปี 2484 ให้ตรวจกับเจ้าของข้อมูลก่อนใช้สูตรเดียวกัน

ข้อควรระวังเมื่อแปลง

  • แปลงปีก่อนสร้างวันที่ 29 กุมภาพันธ์ 2567 (พ.ศ.) คือ 29 กุมภาพันธ์ 2024 ซึ่งมีอยู่จริง แต่ถ้าตีความปี 2567 เป็น ค.ศ. วันนี้ไม่มีอยู่ เพราะ 2567 หารด้วย 4 ไม่ลงตัว ระบบเก่าที่เก็บวันที่เป็นข้อความ เช่น "29/02/2567" จึงควรแยกปีออกมาลบ 543 ก่อนแปลงเป็นชนิด DATE ไม่เช่นนั้นแถวนั้นจะ error หรือกลายเป็น '0000-00-00'
  • คอลัมน์เดียวมีทั้ง พ.ศ. และ ค.ศ. เช่น ข้อมูลที่บันทึกผ่านหน้าจอเป็น พ.ศ. แต่ข้อมูลที่นำเข้าจากไฟล์เป็น ค.ศ. ให้แยกตามแหล่งที่มาหรือช่วงเวลาที่ยืนยันได้ ไม่ใช้กติกาเดียวทั้งคอลัมน์ แถวที่ตัดสินไม่ได้ให้เจ้าของข้อมูลตรวจ
  • ปีสองหลัก SQL Server ตีความปีสองหลักด้วยค่า two-digit year cutoff ซึ่งค่าเริ่มต้นคือ 2049 (49 เป็น 2049 และ 50 เป็น 1950) ส่วน MySQL ตีความ 00–69 เป็น 2000–2069 และ 70–99 เป็น 1970–1999 ไฟล์เก่าที่เก็บปี พ.ศ. สองหลัก เช่น "67" จึงกลายเป็น ค.ศ. 1967 ใน SQL Server หรือ 2067 ใน MySQL ต้องแปลงเองก่อนนำเข้า
  • ปีที่ไม่ได้อยู่ในชนิดวันที่ เช่น คอลัมน์ตัวเลขที่เก็บแค่ปี หรือปีงบประมาณ ให้ตรวจแยก เพราะการค้นตามชนิดวันที่จะไม่เจอ

ตัวอย่างการนับแถวที่น่าจะเป็น พ.ศ. ใน MySQL: SELECT COUNT(*) FROM orders WHERE YEAR(order_date) > YEAR(CURDATE()); ถ้าคอลัมน์มีวันที่ในอนาคตจริง เช่น วันหมดอายุสัญญา ให้ใช้เกณฑ์ที่เหมาะกับคอลัมน์นั้น เช่น ปีที่มากกว่า 2400

ตรวจเลขประจำตัวประชาชน 13 หลักระหว่างย้ายข้อมูลอย่างไร?

ใช้หลักที่ 13 ซึ่งเป็นเลขตรวจสอบ (check digit) จับเลขที่พิมพ์ผิด วิธีคำนวณที่ใช้กันแพร่หลายคือ คูณเลขหลักที่ 1–12 ด้วย 13 ลดลงทีละหนึ่งจนถึง 2 รวมผล หารด้วย 11 เอาเศษ นำ 11 ลบเศษ แล้วเอาหลักหน่วยของผลลัพธ์เป็นเลขตรวจสอบ เราไม่พบเอกสารทางการของกรมการปกครองหรือราชกิจจานุเบกษาที่กำหนดสูตรนี้ จึงอ้างได้เพียงว่าเป็นสูตรที่ใช้กันทั่วไป เช่นในไลบรารีโอเพนซอร์ส python-stdnum

ตัวอย่างสมมติ เลข 1-2345-45678-78-? คำนวณได้ (1×13)+(2×12)+(3×11)+(4×10)+(5×9)+(4×8)+(5×7)+(6×6)+(7×5)+(8×4)+(7×3)+(8×2) = 362 เศษจากการหารด้วย 11 คือ 10 และ 11 − 10 = 1 เลขตรวจสอบจึงเป็น 1

  • เลขที่ผ่านการตรวจแสดงเพียงว่ารูปแบบถูก ไม่ได้ยืนยันว่ามีบุคคลนั้นอยู่จริง
  • อย่าแก้เลขที่ไม่ผ่านโดยอัตโนมัติ ให้ทำรายการส่งเจ้าของข้อมูลตรวจกับเอกสารต้นทาง
  • เก็บเป็นข้อความ 13 ตัวอักษร ไม่ใช่ตัวเลข และตรวจว่าไม่มีขีดหรือช่องว่างปน
  • เลขประจำตัวประชาชนเป็นข้อมูลส่วนบุคคล จึงใช้กติกาเดียวกับหัวข้อ PDPA ด้านล่าง

ส่วนคำถามว่าควรใช้เลข 13 หลักเป็นคีย์หลักของระบบใหม่หรือไม่ อยู่ในบทความระบบสารสนเทศสวัสดิการ

ชื่อ ที่อยู่ และไฟล์ export จากระบบเก่ามีปัญหาอะไรบ้าง?

ข้อมูลที่พิมพ์อิสระมักไม่สม่ำเสมอ และไฟล์ export ของระบบเก่ามีกติกาที่ต้องรู้ก่อนอ่าน

  • ชื่อและที่อยู่ภาษาไทย ที่พบบ่อยคือช่องว่างไม่สม่ำเสมอ (สองช่อง ช่องว่างหน้าและท้าย หรือ NO-BREAK SPACE ที่ดูเหมือนช่องว่าง) คำย่อหลายแบบ เช่น "จ." กับ "จังหวัด" "อ." กับ "อำเภอ" หรือ "กทม." กับ "กรุงเทพมหานคร" และคำนำหน้าชื่อที่อยู่ในช่องเดียวกับชื่อ รูปแบบเหล่านี้เป็นสิ่งที่พบบ่อยในข้อมูลที่พิมพ์อิสระ ไม่ได้มาจากมาตรฐานใด ให้เก็บค่าเดิม และเขียนค่าที่ปรับแล้วลงคอลัมน์แยกเพื่อให้ตรวจย้อนได้
  • ไฟล์ Excel ตามเอกสารของ Microsoft Excel ตัดเลขศูนย์นำหน้า แปลงตัวเลขยาวเป็นรูปแบบวิทยาศาสตร์ และเก็บความแม่นยำได้ 15 หลัก เบอร์โทรศัพท์ที่ขึ้นต้นด้วย 0 รหัสสินค้า หรือเลขยาว ๆ จึงอาจเสียตั้งแต่ตอนเปิดไฟล์ ให้นำเข้าคอลัมน์เหล่านี้เป็นข้อความ (Text) แล้วเทียบกับต้นทาง
  • ไฟล์ DBF เช่น ตารางของ Visual FoxPro ตามโครงสร้างไฟล์ที่ Microsoft อธิบาย ไบต์ตำแหน่ง 29 ของ header (นับตำแหน่งแรกเป็น 0) เป็น code page mark และแต่ละระเบียนขึ้นต้นด้วยไบต์สถานะการลบ ถ้าเป็นเครื่องหมาย * (0x2A) แปลว่าระเบียนถูกลบแล้วแต่ยังอยู่ในไฟล์ โปรแกรมที่อ่าน DBF ตรง ๆ จึงอาจดึงระเบียนที่ผู้ใช้ลบไปแล้วมาด้วย
  • ไฟล์ fixed-width ถ้าความกว้างของแต่ละช่องนับเป็นไบต์ของ TIS-620 หรือ cp874 ให้ตัดช่องตามไบต์ก่อนแปลง encoding เพราะหลังแปลงเป็น UTF-8 อักษรไทยแต่ละตัวยาวสามไบต์

ภาษาไทยหรือวันที่ผิดหลังย้ายข้อมูล ดูอาการแล้วตรวจอะไร?

ตารางนี้รวบรวมอาการที่เกี่ยวกับข้อความไทยและวันที่จากหัวข้อข้างต้น ใช้เป็นจุดเริ่มเมื่อพบปัญหาในรอบซ้อมหรือหลัง cutover

อาการที่พบบ่อย → สาเหตุ → วิธีตรวจ
อาการที่พบบ่อยสาเหตุวิธีตรวจ
ข้อความไทยกลายเป็น เธ… เน… ซ้ำทุกตัวไบต์ UTF-8 ถูกแสดงเป็น cp874 หรือ TIS-620HEX() ของค่าในฐานข้อมูล ถ้าขึ้นต้นด้วย E0B8 หรือ E0B9 ข้อมูลถูกแล้ว ปัญหาอยู่ที่ client หรือโปรแกรมที่เปิด
ข้อความไทยกลายเป็น ฅไบต์ UTF-8 ถูกแสดงเป็น cp1252 (ซึ่งเป็น latin1 ของ MySQL) ถ้าเป็น Latin-1 แบบเคร่งครัด บางตัวจะเป็นอักขระควบคุมที่มองไม่เห็นเหมือนข้อบน และตรวจ character_set_results หรือ encoding ของโปรแกรมที่ export
ข้อความไทยกลายเป็น ÀÒÉÒไบต์ TIS-620 อยู่ในคอลัมน์ที่ประกาศเป็น latin1HEX() เห็นไบต์เดี่ยว A1–FB แก้ด้วยการแปลงเป็น BLOB ก่อนตามเอกสาร MySQL
ข้อความไทยกลายเป็น � ปนกับอักขระแปลก ๆไบต์ TIS-620 ถูกอ่านเป็น UTF-8 แล้วบันทึกทับนับแถวที่ HEX มี EFBFBD (U+FFFD) ถ้าพบ ต้องดึงจากต้นทางใหม่
HEX มี C3A0C2B8 ซ้ำ ๆDouble encodingย้อนกลับได้ถ้ายังไม่ถูกแก้ ลองกับสำเนาก่อน
อัญประกาศโค้ง ขีดยาว หรือ € หายหรือเป็นอักขระแปลกข้อมูล cp874 ถูกถอดรหัสเป็น TIS-620นับไบต์ 0x80–0x9F ในต้นทาง
ข้อความไทยถูกตัดท้ายคอลัมน์ปลายทางนับเป็นไบต์ เช่น varchar ใน SQL Server หรือไฟล์ fixed-widthเทียบ CHAR_LENGTH ต้นทางกับปลายทาง และตรวจว่าขนาดคอลัมน์ปลายทาง (นับเป็นไบต์) ไม่น้อยกว่าความยาวสูงสุดของต้นทางคูณสาม
ลำดับรายชื่อในรายงานไม่เหมือนเดิมCollation ต่างกันเทียบรายงานเดียวกันจากสองระบบ
วันที่เป็นปี 25xxปี พ.ศ. ในคอลัมน์ ค.ศ.นับแถวที่ปีมากกว่าปีปัจจุบัน
วันที่ 29 ก.พ. หาย หรือเป็น 0000-00-00สร้างวันที่จากปี พ.ศ. ก่อนลบ 543 หรือ MySQL ปิด strict modeนับวันที่ว่างและ 0000-00-00 เทียบกับต้นทาง
ปีเป็น 1967 หรือ 2067 ทั้งที่ควรเป็น 2024ปีสองหลักถูกตีความด้วยกติกาของฐานข้อมูล (two-digit year cutoff ของ SQL Server หรือช่วง 00–69 ของ MySQL)ดูค่าต่ำสุดและสูงสุดของปีจากผล profile
เบอร์โทรไม่มี 0 นำหน้าเปิดไฟล์ด้วย Excel ก่อนนำเข้าเทียบความยาวกับต้นทาง
จำนวนระเบียนมากกว่าในโปรแกรมเดิมอ่านระเบียนที่ถูกลบจากไฟล์ DBFนับระเบียนที่ขึ้นต้นด้วย 0x2A

ตรวจสอบข้อมูลหลังย้ายระบบอย่างไรให้มั่นใจว่าครบและถูกต้อง?

ใช้หลายชั้นประกอบกัน เพราะแต่ละวิธีจับปัญหาคนละแบบ จำนวนแถวที่ตรงกันไม่ได้แปลว่าค่าถูก และยอดรวมที่ตรงกันไม่ได้แปลว่าชื่อภาษาไทยอ่านออก วิธีด้านล่างเป็นแนวปฏิบัติที่ใช้กันทั่วไป ไม่ได้มาจากมาตรฐานฉบับใดฉบับหนึ่ง

วิธีกระทบยอดข้อมูลและสิ่งที่แต่ละวิธีจับได้
วิธีจับปัญหาอะไรได้
นับจำนวนแถวต่อตาราง และต่อสถานะหรือประเภทแถวหายหรือซ้ำ กติกากรองที่ตัดข้อมูลเกิน
ยอดรวมควบคุมรายงวด (control totals) เช่น ยอดเงินรวมรายเดือน หรือจำนวนรายการต่อสาขาตัวเลขเพี้ยน การปัดเศษ และแถวที่ไปผิดงวดเพราะวันที่แปลงผิด
Hash ต่อระเบียน คำนวณจากค่าที่ปรับเป็นรูปแบบเดียวกันแล้วทั้งสองฝั่งค่าที่เปลี่ยนในบางคอลัมน์ รวมถึงข้อความไทย
ตรวจข้อความไทยโดยเฉพาะ เช่น นับแถวที่มี U+FFFD รูปแบบ เธ/เน ซ้ำ หรือ HEX ที่ไม่ใช่ E0B8/E0B9ภาษาไทยเพี้ยนที่ hash ไม่เห็น ถ้าทั้งสองฝั่งถูกถอดรหัสผิดแบบเดียวกัน
สุ่มเทียบรายการกับผู้ใช้ฝั่งธุรกิจความหมายผิดทั้งที่ตัวเลขตรง เช่น สถานะที่ map ผิด
เทียบรายงานจากระบบเก่ากับระบบใหม่ผลรวมของทุกกติกา รวมถึงลำดับการเรียง

การคำนวณ hash ต้องตกลงรูปแบบก่อน เช่น ลำดับคอลัมน์ รูปแบบวันที่ ตัวคั่น และให้ข้อความเป็น UTF-8 ทั้งสองฝั่ง ไม่เช่นนั้นจะได้ค่าต่างทั้งที่ข้อมูลตรงกัน ส่วนคอลัมน์ที่ตั้งใจแปลง เช่น ปี พ.ศ. ให้ใช้กติกาเดียวกันกับค่าฝั่งต้นทางก่อนเทียบ

เครื่องมือของผู้ให้บริการคลาวด์ช่วยตรวจได้แค่ไหน?

ถ้าใช้ AWS Database Migration Service ฟีเจอร์ data validation จะเทียบแต่ละแถวของต้นทางกับแถวที่สอดคล้องกันในปลายทาง หลังโหลดข้อมูลทั้งตารางเสร็จ และตรวจการเปลี่ยนแปลงต่อเนื่องในงานแบบ CDC แถวที่ไม่ตรงจะถูกบันทึกในตาราง awsdms_control.awsdms_validation_failures_v1 บนปลายทาง แยกเป็น RECORD_DIFF, MISSING_SOURCE, MISSING_TARGET และ TABLE_WARNING และสร้างงานแบบ validation only เพื่อดูจำนวนแถวที่ไม่ตรงก่อนหรือระหว่างช่วง cutover ได้ ข้อจำกัดที่เกี่ยวกับงานย้ายระบบเก่าโดยตรงมีดังนี้

  • ตารางต้องมี primary key หรือ unique index ซึ่งระบบเก่าบางระบบไม่มี
  • ไม่รองรับเมื่อใช้ task setting แบบแทนที่อักขระ (character substitution)
  • ข้ามคอลัมน์ที่มีการทำ data masking ใน table mapping
  • หยุดตรวจเมื่อพบแถวที่ไม่ผ่านหรือถูกพักไว้เกิน 10,000 แถว
  • ใช้ทรัพยากรของต้นทาง ปลายทาง และเครือข่ายเพิ่ม และใช้เวลานอกเหนือจากเวลาที่ใช้ย้าย
  • เอกสารยกตัวอย่างว่า ถ้า primary key บน PostgreSQL ปลายทางไม่ได้ใช้ collation "C" ลำดับการเรียงจะต่างจาก Oracle และการตรวจจะล้มเหลว เป็นอีกกรณีที่ collation มีผลต่อการย้ายข้อมูล

สำหรับ Azure Database Migration Service รุ่น classic ในงานย้าย SQL Server ไป Azure SQL Database มีตัวเลือก Data Integrity Check ที่เทียบ checksum ของตารางต้นทางกับปลายทางหลังย้าย (เอกสาร API) ถ้าใช้เส้นทางย้ายอื่นของ Azure ให้ตรวจในเอกสารของบริการนั้นว่ามีการตรวจแบบเดียวกันหรือไม่

เครื่องมือเหล่านี้ตรวจว่าแถวตรงกัน แต่ไม่รู้ว่าข้อมูลต้นทางถูกตามความหมายของธุรกิจหรือไม่ ยอดรวมรายงวดและการเทียบรายงานกับผู้ใช้จึงยังจำเป็น ถ้าเป็นงานจ้างของหน่วยงานรัฐ รายงานกระทบยอดควรเป็นหลักฐานตรวจรับที่เขียนไว้ในTOR ย้ายระบบขึ้นคลาวด์ภาครัฐ

Cutover ฝั่งข้อมูลต้องเตรียมอะไร และถอยกลับอย่างไร?

ต้องมีช่วงหยุดรับข้อมูล (freeze) backup สุดท้าย การย้ายส่วนต่างล่าสุด การกระทบยอดที่ใช้เป็นเกณฑ์ go/no-go และวิธีนำข้อมูลที่เกิดบนระบบใหม่กลับไปถ้าต้องถอย ขั้นตอนฝั่งโครงสร้างพื้นฐาน เช่น DNS และช่วงดูแลใกล้ชิดหลังย้าย อยู่ในหัวข้อ cutover และ rollback ของคู่มือ Cloud Migration

  • Freeze แนวทาง cutover ของ AWS Prescriptive Guidance เริ่มจากหยุดรับข้อมูลเข้าระบบเดิม ทำ backup สุดท้ายที่ใช้ถอยกลับได้ แล้ว sync ข้อมูลครั้งสุดท้าย และระบุว่าการล็อกต้นทางทำให้ไม่มีธุรกรรมใหม่ แต่อาจต้องใช้ช่วงหยุดระบบนานขึ้น ให้แจ้งผู้ใช้ว่าช่วงใดห้ามบันทึกงาน และงานที่เกิดระหว่างนั้นจะบันทึกอย่างไร
  • ส่วนต่างสุดท้าย ถ้ารอบซ้อมที่ย้ายทั้งก้อนใช้เวลานานเกินช่วงหยุด ให้ย้ายข้อมูลเก่าที่ไม่เปลี่ยนแล้วไว้ก่อน และย้ายเฉพาะส่วนที่เปลี่ยนในวันจริง ซึ่งต้องรู้ให้ได้ว่าแถวใดเปลี่ยน เช่น จากคอลัมน์เวลาแก้ไขที่เชื่อถือได้
  • Go/no-go จากผลการกระทบยอด กำหนดล่วงหน้าว่าผลแบบใดผ่าน เช่น จำนวนแถวและยอดรวมรายงวดต้องตรงทุกตาราง และรายการที่ไม่ตรงต้องอยู่ในรายการยกเว้นที่เจ้าของข้อมูลยอมรับแล้ว แนวทางของ AWS ให้มี checkpoint ที่มีเกณฑ์ถอยกลับกำหนดไว้ก่อน และมีผู้ตัดสินใจว่าจะแก้ต่อหรือถอยกลับ
  • ถอยกลับเมื่อระบบใหม่มีข้อมูลแล้ว ตามแนวทางเดียวกัน ถ้ายังไม่มีข้อมูลเปลี่ยน การถอยกลับอาจเป็นเพียงการเปลี่ยนเส้นทางผู้ใช้ แต่ถ้าระบบใหม่มีธุรกรรมแล้ว อาจต้องนำข้อมูลกลับไประบบเดิม ทางเลือกที่ AWS ระบุ ได้แก่ fail-forward, dual write และ backup/restore แบบ native ซึ่งควรทดสอบการกู้คืนในสภาพแวดล้อมทดสอบก่อนวัน cutover ให้ตัดสินตั้งแต่ตอนวางแผนว่าจะใช้วิธีใด และเตรียมสคริปต์ย้ายข้อมูลกลับไว้ถ้าเลือกทางนั้น
  • Backup ปลายทางก่อนเปิดใช้ Google Cloud แนะนำให้ทดสอบฟังก์ชันพื้นฐานและ backup ฐานข้อมูลปลายทางก่อนเปิดให้ client เข้าถึง

สิ่งที่ทดสอบก่อน cutover ไม่ได้ ให้บันทึกเป็นความเสี่ยงพร้อมวิธีตรวจพบและวิธีรับมือตามที่แนวทางของ AWS แนะนำ และระหว่างนี้ระบบเก่ายังต้องปลอดภัยและกู้คืนได้ ดูวิธีดูแลระบบเก่าระหว่างรอ modernize

หลังย้ายแล้ว ควรเก็บระบบเก่าและข้อมูลเดิมไว้นานแค่ไหน?

เก็บตามระยะที่กฎหมายและธุรกิจกำหนด แล้วลบอย่างมีหลักฐาน ไม่ใช่ปิดเครื่องทิ้งไว้โดยไม่มีกำหนด Google Cloud แนะนำให้ทำ backup สุดท้ายของฐานข้อมูลต้นทางแต่ละตัวก่อนลบ เพื่อให้มีสถานะสุดท้ายที่กำหนดได้และเข้าถึงได้

  • ระยะเก็บรักษาตามกฎหมาย ต่างกันตามชนิดข้อมูล ตัวอย่างเช่น ข้อหารือของกรมสรรพากร เลขที่ กค 0811/8629 (4 กันยายน 2544) ระบุว่าบริษัทต้องเก็บรักษาบัญชีและเอกสารหลักฐานการบันทึกบัญชีไว้ 5 ปีนับแต่วันปิดบัญชี ตามมาตรา 14 แห่ง พ.ร.บ. การบัญชี พ.ศ. 2543 ระยะของข้อมูลแต่ละชนิดให้ฝ่ายบัญชีและฝ่ายกฎหมายขององค์กรยืนยัน
  • เก็บในรูปแบบที่ยังเปิดได้ ข้อมูลเก่าที่ไม่ได้ย้ายไปทั้งหมด เช่น รายการรายวันของปีเก่า ควร export เป็นรูปแบบที่อ่านได้โดยไม่ต้องใช้โปรแกรมเดิม เช่น CSV แบบ UTF-8 พร้อมเอกสารอธิบายคอลัมน์ หรือเก็บฐานข้อมูลแบบอ่านอย่างเดียว พร้อมกำหนดผู้มีสิทธิ์เข้าถึง
  • ลบเมื่อพ้นกำหนด PDPA มาตรา 37 (3) ให้ผู้ควบคุมข้อมูลส่วนบุคคลจัดให้มีระบบการตรวจสอบเพื่อลบหรือทำลายข้อมูลส่วนบุคคลเมื่อพ้นกำหนดระยะเวลาการเก็บรักษา หรือที่ไม่เกี่ยวข้องหรือเกินความจำเป็นตามวัตถุประสงค์ เราแนะนำให้นับสำเนาที่ใช้ซ้อมย้ายรวมอยู่ในระบบนี้ด้วย
  • ล้างสื่อบันทึกของเครื่องเก่า ใช้ NIST SP 800-88 Rev. 2 (กันยายน 2025) เป็นแนวทางล้างข้อมูลบนดิสก์และสื่อบันทึก (media sanitization) ให้กู้คืนไม่ได้ตามระดับที่กำหนด ก่อนปลดระวางหรือส่งคืนเครื่อง

ใช้ข้อมูลส่วนบุคคลจริงซ้อมย้ายข้อมูลได้ไหม และ PDPA เกี่ยวข้องอย่างไร?

PDPA ไม่มีมาตราที่พูดถึงสภาพแวดล้อมทดสอบหรือการย้ายระบบโดยตรง หัวข้อนี้จึงเป็นการตีความของเราจากมาตราที่เกี่ยวข้องเพื่อประกอบการวางแผน ไม่ใช่คำแนะนำทางกฎหมาย

  • พ.ร.บ. คุ้มครองข้อมูลส่วนบุคคล พ.ศ. 2562 มาตรา 6 นิยามข้อมูลส่วนบุคคลว่าเป็นข้อมูลเกี่ยวกับบุคคลซึ่งทำให้ระบุตัวบุคคลนั้นได้ไม่ว่าทางตรงหรือทางอ้อม สำเนาฐานข้อมูลที่ใช้ซ้อมย้ายจึงยังเป็นข้อมูลส่วนบุคคลเหมือนต้นฉบับ
  • มาตรา 22 ให้เก็บรวบรวมข้อมูลส่วนบุคคลได้เท่าที่จำเป็นภายใต้วัตถุประสงค์อันชอบด้วยกฎหมายของผู้ควบคุมข้อมูลส่วนบุคคล ถ้อยคำพูดถึงการเก็บรวบรวม แต่หลักเดียวกันใช้วางแผนได้ว่าสำเนาสำหรับซ้อมควรมีเฉพาะตารางและคอลัมน์ที่การซ้อมต้องใช้
  • มาตรา 27 ห้ามผู้ควบคุมข้อมูลใช้หรือเปิดเผยข้อมูลส่วนบุคคลโดยไม่ได้รับความยินยอม เว้นแต่เป็นข้อมูลที่เก็บรวบรวมได้โดยไม่ต้องขอความยินยอมตามมาตรา 24 หรือมาตรา 26 การนำข้อมูลไปใช้ในงานย้ายระบบจึงควรอยู่ในขอบวัตถุประสงค์ที่องค์กรมีอยู่ ให้ DPO ยืนยัน
  • มาตรา 37 (1) ให้จัดให้มีมาตรการรักษาความมั่นคงปลอดภัยที่เหมาะสมตามมาตรฐานขั้นต่ำที่คณะกรรมการประกาศกำหนด ซึ่งออกเป็นประกาศคณะกรรมการคุ้มครองข้อมูลส่วนบุคคล เรื่อง มาตรการรักษาความมั่นคงปลอดภัยของผู้ควบคุมข้อมูลส่วนบุคคล พ.ศ. 2565 (ราชกิจจานุเบกษา เล่ม 139 ตอนพิเศษ 140 ง วันที่ 20 มิถุนายน 2565) ข้อ 4 (6) กำหนดอย่างน้อยให้มี (ก) การควบคุมการเข้าถึงโดยคำนึงถึงหลักให้สิทธิเท่าที่จำเป็น (need-to-know basis) และสิทธิน้อยที่สุด (least privilege) (ข) การบริหารจัดการการเข้าถึงของผู้ใช้งาน รวมถึงการทบทวนและถอดถอนสิทธิ (ค) หน้าที่ของผู้ใช้งานเพื่อป้องกันการเข้าถึงหรือใช้โดยมิชอบ รวมถึงการลักลอบทำสำเนาข้อมูลส่วนบุคคล และ (ง) วิธีตรวจสอบย้อนหลังการเข้าถึง เปลี่ยนแปลง แก้ไข หรือลบข้อมูลส่วนบุคคล (audit trails) สภาพแวดล้อมซ้อมย้ายที่มีข้อมูลจริงจึงควรมีมาตรการเหล่านี้เท่ากับ production และถอดสิทธิเมื่องานจบ
  • มาตรา 40 ให้ผู้ประมวลผลข้อมูลส่วนบุคคล เช่น ผู้รับจ้างย้ายข้อมูล ดำเนินการตามคำสั่งของผู้ควบคุมข้อมูลเท่านั้น จัดให้มีมาตรการรักษาความมั่นคงปลอดภัยและแจ้งเหตุละเมิดให้ผู้ควบคุมทราบ และจัดทำบันทึกรายการกิจกรรมการประมวลผล ส่วนประกาศข้างต้นข้อ 6 ให้ผู้ควบคุมพิจารณากำหนดในข้อตกลงให้ผู้ประมวลผลมีมาตรการที่เป็นไปตามมาตรฐานขั้นต่ำตามข้อ 4

ในทางปฏิบัติ รอบซ้อมที่ทดสอบโครงสร้างและเวลาใช้ข้อมูลที่ปกปิดหรือสร้างขึ้นได้ แต่การตรวจภาษาไทยและการกระทบยอดต้องใช้ค่าจริง เพราะปัญหา encoding อยู่ในไบต์ของข้อมูลจริง ทางที่สมดุลกว่าคือจำกัดรอบที่ใช้ข้อมูลจริงให้อยู่ในสภาพแวดล้อมที่ควบคุมสิทธิเท่า production มีบันทึกการเข้าถึง และลบเมื่อจบ ส่วนเทคนิคการทำข้อมูลนิรนามและเอกสารอ้างอิงภาษาไทยอยู่ในหัวข้อ PDPA ของบทความรับดูแลระบบเก่าที่ไม่มีเอกสาร วิธีที่ใช้กับระบบจริงให้ปรึกษาเจ้าหน้าที่คุ้มครองข้อมูลส่วนบุคคล (DPO) หรือที่ปรึกษากฎหมายขององค์กร

Checklist: ก่อนย้ายข้อมูลจาก Legacy System

ใช้ไล่ตรวจก่อนเริ่มรอบซ้อมแรก และทบทวนอีกครั้งก่อนกำหนดวัน cutover

  1. มีรายการตาราง ไฟล์ และระบบที่เชื่อมกับข้อมูลที่จะย้าย และมี backup ต้นทางที่ทดสอบกู้คืนแล้ว
  2. มีสิทธิ์อ่านฐานข้อมูลต้นทางโดยตรง ไม่ต้องพึ่งไฟล์ export ของผู้รับจ้างเดิมเพียงทางเดียว
  3. Profile ทุกคอลัมน์สำคัญ: จำนวนแถว ค่าว่าง ค่าไม่ซ้ำ ช่วงวันที่ และความยาวสูงสุดทั้งเป็นตัวอักษรและไบต์
  4. ระบุ encoding ของข้อความไทยรายคอลัมน์จาก HEX และนับจำนวนแถวที่มีไบต์ 0x80–0x9F แถวที่มี U+FFFD และแถวที่เป็น double encoding
  5. ตรวจ charset ของการเชื่อมต่อทุกจุดที่อ่านหรือเขียนข้อมูล รวมถึงเครื่องมือ export
  6. เลือก charset และ collation ปลายทาง (ใน MySQL ใช้ utf8mb4 ไม่ใช่ utf8) และคิดขนาดคอลัมน์ใหม่สำหรับสามไบต์ต่อตัวอักษรไทย
  7. หาคอลัมน์วันที่ที่มีปี พ.ศ. ปีสองหลัก หรือทั้งสองแบบปนกัน และให้เจ้าของข้อมูลยืนยันกติกาแปลงรายคอลัมน์
  8. ตรวจเลขประจำตัวประชาชนด้วยเลขตรวจสอบ และส่งรายการเลขที่ไม่ผ่านให้เจ้าของข้อมูลตรวจ
  9. มีตาราง mapping ทุกคอลัมน์ปลายทาง พร้อมกติกาทำความสะอาดที่เจ้าของข้อมูลรับรอง และเก็บค่าเดิมของข้อมูลที่ถูกแก้
  10. นำเข้าคอลัมน์รหัส เบอร์โทร และเลขยาวจาก Excel เป็นข้อความ และกรองระเบียนที่ถูกลบออกจากไฟล์ DBF
  11. ซ้อมย้ายด้วยข้อมูลขนาดจริงจนผลซ้ำได้ และจับเวลาเทียบกับช่วงหยุดที่ยอมรับได้
  12. กำหนดชุดกระทบยอด: จำนวนแถว ยอดรวมรายงวด hash ต่อระเบียน การตรวจข้อความไทย รายการสุ่มตรวจ และรายงานที่ผู้ใช้เทียบ พร้อมผู้ลงนาม
  13. เทียบลำดับการเรียงในรายงานภาษาไทยระหว่างระบบเก่ากับระบบใหม่
  14. กำหนดช่วงหยุดรับข้อมูล backup สุดท้าย วิธีย้ายส่วนต่าง เกณฑ์ go/no-go และวิธีนำข้อมูลใหม่กลับระบบเดิมถ้าต้องถอย
  15. สภาพแวดล้อมซ้อมย้ายที่มีข้อมูลส่วนบุคคลจริงมีการควบคุมสิทธิ บันทึกการเข้าถึง ข้อตกลงกับผู้ประมวลผล และกำหนดลบสำเนา
  16. กำหนดระยะเก็บรักษาข้อมูลเดิม รูปแบบที่เก็บ ผู้มีสิทธิ์เข้าถึง และวิธีลบข้อมูลและล้างสื่อของเครื่องเก่าเมื่อพ้นกำหนด

ประเมินข้อมูลในระบบเดิมก่อนย้าย

ถ้ายังไม่รู้ว่าระบบเดิมเก็บภาษาไทยแบบใด มีปี พ.ศ. ปนอยู่ที่ใด หรือข้อมูลส่วนใดต้องให้เจ้าของข้อมูลตัดสิน การประเมินก่อนเริ่มโครงการจะได้ข้อเท็จจริงสำหรับวางแผนรอบซ้อมและช่วงหยุดระบบ

บริการดูแลและปรับปรุงระบบเก่าของ UNIXDEV เริ่มจากสำรวจ source code, dependencies, วิธี deploy, ข้อมูล และผู้ถือสิทธิ์ แล้ววางแผนปรับปรุงแบบค่อยเป็นค่อยไปพร้อมแผน rollback เมื่อต้องสร้างระบบใหม่แทนระบบเดิม การย้ายข้อมูลเป็นส่วนหนึ่งของขอบเขตงานพัฒนาซอฟต์แวร์องค์กร และสำหรับ Microsoft Dynamics AX เรามีงานย้ายข้อมูลจาก AX ไป ERP รุ่นใหม่ เราไม่รับประกัน zero downtime ช่วงหยุดระบบที่ต้องใช้ประเมินได้หลังตรวจข้อมูลและสถาปัตยกรรมจริง

ส่งข้อมูลเท่าที่มี เช่น ชนิดและรุ่นของฐานข้อมูล จำนวนตารางโดยประมาณ ระบบปลายทาง และอาการที่พบ ผ่านแบบฟอร์มส่งโจทย์ได้ โดยยังไม่ต้องส่งข้อมูลจริงหรือรหัสผ่าน

แหล่งอ้างอิงและอ่านต่อ

บทความโดย UNIXDEV Team · 8 พฤศจิกายน 2026 · ตัวอย่าง mojibake สร้างด้วย codec ของ Python และเลขประจำตัวในบทความเป็นตัวอย่างสมมติ เรื่อง PDPA เป็นการตีความเพื่อประกอบการวางแผน ไม่ใช่คำแนะนำทางกฎหมาย

คำถามที่พบบ่อย

การย้ายข้อมูลออกจากระบบเก่า (legacy data migration) คืออะไร?

การย้ายข้อมูลออกจากระบบเก่าคือการดึงข้อมูลจากระบบเดิม แปลงให้เข้ากับโครงสร้างของระบบใหม่ ทำความสะอาดตามกติกาที่เจ้าของข้อมูลตกลง ซ้อมย้ายจนผลซ้ำได้ แล้วพิสูจน์ด้วยการกระทบยอดว่าข้อมูลครบและความหมายไม่เปลี่ยน ก่อน cutover ที่มีช่วงหยุดรับข้อมูลและทางถอยกลับ และจบด้วยการเก็บรักษาและลบข้อมูลของระบบเก่าตามกำหนด

ทำไมภาษาไทยเพี้ยนเป็นภาษาต่างดาวหลังย้ายฐานข้อมูล และแก้อย่างไร?

ภาษาไทยเพี้ยนเพราะไบต์ถูกอ่านด้วย encoding ที่ไม่ใช่ตัวที่ใช้เขียน ระบบเก่ามักเก็บภาษาไทยเป็น TIS-620 หรือ Windows-874 หนึ่งไบต์ต่อตัวอักษร ส่วนระบบใหม่ใช้ UTF-8 สามไบต์ต่อตัว ถ้าเห็น เธ หรือ เน ซ้ำทุกตัว แปลว่าไบต์ UTF-8 ถูกแสดงเป็น cp874 ถ้าเห็น ÀÒÉÒ แปลว่าไบต์ TIS-620 ถูกแสดงเป็น Latin-1 ให้ตรวจที่ไบต์ด้วย HEX() ภาษาไทย UTF-8 ที่ถูกต้องขึ้นต้นด้วย E0B8 หรือ E0B9 แล้วแปลงครั้งเดียวจาก encoding ที่ตรวจแล้ว โดยนับอักขระที่แปลงไม่ได้ และไม่ใช้ตัวเลือก -c ของ iconv ที่ทิ้งอักขระโดยไม่แจ้ง

ปี พ.ศ. ที่บันทึกในช่องวันที่ แปลงเป็น ค.ศ. อย่างไร?

หาแถวที่ปีมากกว่าปีปัจจุบัน ยืนยันกับเจ้าของข้อมูลว่าคอลัมน์นั้นบันทึกเป็น พ.ศ. แล้วลบ 543 จากปี ฐานข้อมูลไม่เตือน เพราะปี 2567 อยู่ในช่วงที่ชนิด DATE ของ MySQL, PostgreSQL และ SQL Server ยอมรับ ถ้าระบบเก่าเก็บวันที่เป็นข้อความ ให้แยกปีออกมาลบ 543 ก่อนสร้างวันที่ เพราะ 29 กุมภาพันธ์ปี 2567 ไม่มีอยู่ในปฏิทินเกรกอเรียน และคอลัมน์ที่มีทั้ง พ.ศ. และ ค.ศ. ต้องแยกตามแหล่งที่มา ไม่ใช้กติกาเดียวทั้งคอลัมน์

ตรวจสอบข้อมูลหลังย้ายระบบด้วยวิธีใดบ้าง?

ใช้หลายชั้นประกอบกัน ได้แก่ นับจำนวนแถวต่อตารางและต่อสถานะ ยอดรวมควบคุมรายงวด hash ต่อระเบียน การตรวจข้อความไทยโดยเฉพาะ การสุ่มเทียบรายการกับผู้ใช้ฝั่งธุรกิจ และการเทียบรายงานจากระบบเก่ากับระบบใหม่ เครื่องมืออย่าง data validation ของ AWS DMS เทียบได้ทีละแถว แต่ต้องมี primary key หรือ unique index และไม่รู้ว่าข้อมูลถูกตามความหมายของธุรกิจหรือไม่

ใช้ข้อมูลส่วนบุคคลจริงซ้อมย้ายข้อมูลได้ไหม?

PDPA ไม่มีมาตราที่พูดถึงสภาพแวดล้อมทดสอบโดยตรง จากการตีความของเรา สำเนาที่ใช้ซ้อมยังเป็นข้อมูลส่วนบุคคล ควรมีเฉพาะตารางและคอลัมน์ที่จำเป็นตามหลักของมาตรา 22 และมีมาตรการตามมาตรา 37 (1) และประกาศมาตรการรักษาความมั่นคงปลอดภัย พ.ศ. 2565 เช่น ควบคุมสิทธิตามหลัก need-to-know บันทึกการเข้าถึง และลบเมื่อจบงาน ผู้รับจ้างย้ายข้อมูลมีหน้าที่ของผู้ประมวลผลตามมาตรา 40 ข้อสรุปนี้ไม่ใช่คำแนะนำทางกฎหมาย ให้ยืนยันกับ DPO หรือที่ปรึกษากฎหมายขององค์กร