เทคนิค การจัดตัวเลขที่มีรูปแบบ (Running Number)

ตัวอย่างตัวเลขที่ ที่มีรูปแบบ ก็ได้แก่ รหัสสินค้า เลขที่เอกสารเป็นต้น ซึ่งการสร้างตัวเลขที่ต่อเนื่องกันโดยอัตโนมัติ สามารถทำได้โดย PHP และ SQL

ก่อนอื่นเรามาดูวิธีการสร้างรหัสก่อน
จริงๆแล้วถ้าเป็นไปได้ ผมแนะนำให้จัดการรหัสสินค้าด้วยวิธีนี้ เทคนิคการกำหนดรหัสสินค้า แต่วิธีนี้เราจะไม่สามารถจัดการรหัสสินค้าโดยอัตโนมัติได้ แต่ในกรณีที่ต้องการสร้างรหัสสินค้า (หรือรหัสต่อเนื่อง ใดๆ) ด้วยตัวเองก็สามารถสร้างรหัสได้ด้วยคำสั่งนี้
<?php
$id = 1;
$code = sprintf('P-%04d', $id);
echo $code; // P-0001
?>

คำสั่งที่ใช้คือ sprinf() ครับ โดยที่ P-%04d แยกออกดังนี้
  • %04d เป็นคำสั่งกำหนดรูปแบบให้ ให้เติม 0 ด้านหน้าตัวเลขให้ครบ 4 หลัก (รายละเอียดเพิ่มเติม http://php.net/...unction.sprintf.php)
  • P- อันนี้เป็น prefix ที่ใช้เติมด้านหน้าเฉยๆ ครับ จะมีหรือไม่ก็ได้ ที่สำคัญคือต้องไม่ตรงกับรูปแบบคำสั่งของ sprinf
คำสั่งด้านบน จะให้ผลลัพท์เป็น P-0000 ถึง P-9999

$id คือค่าตัวเลขที่ต้องการ มีค่าระหว่าง 0-9999 ซึ่งจะได้รหัสเป็น P-0000 ถึง P-9999 ซึ่งค่าตัวเลขนี้เราต้องกำหนดเอง หรือเอามาจากฐานข้อมูลครับ ซึงวิธีอ่านค่านี้จากฐานข้อมูล มี วิธีหลักๆที่เป็นที่นิยม 3 วิธี

วิธีแรกคืออ่าน ID จากคอลัมน์ ID ที่เป็น AUTO_INCREMENT ของตาราง วิธีนี้จะได้ ID ของข้อมูลตรงกันกับ ID ของรหัสสินค้าอัตโนมัติ
<?php
     $sql = "SHOW TABLE STATUS LIKE 'table_name";
     $result = @mysql_query($sql);
     $row = @mysql_fetch_assoc($result);
     $id = (int)$row['Auto_increment']; // คืนค่า id จากค่า AUTO_INCREMENT ของฐานข้อมูล
?>
วิธีที่สอง คล้ายๆกันกับวิธีแรก แต่ใช้วิธีอ่านค่าสูงสุดของ ID ออกมา เสร็จแล้ว + 1 ได้เป็น ID ใหม่นำไปใช้งานได้
SELECT MAX(`id`) AS `lastid` FROM `table`

ทิป ID ที่ได้สามารถนำไปใช้กับสินค้าใหม่ได้ทันทีเหมือนกับวิธีแรกนะครับ ซึ่งวิธีนี้มีข้อดีกว่าวิธีแรกคือ เลขรหัสจะต่อเนื่องกว่าหากมีการลบข้อมูลรายการล่าสุดออกไป (ถ้ามีการลบรายการล่าสุดออก ID ที่อ่านได้ใหม่จะได้เป็น ID ที่ถูกลบออก) แต่ในกรณีอื่นๆ เลขรหัสจะไม่ได้รหัสเดิมที่ลบนะครับ อย่าสับสน

วิธีที่ 3 บันทึกข้อมูลรหัสสินค้าไว้อีกตาราง คล้ายๆวิธีแรกครับ โดยการสร้างตาราง number และเก็บข้อมูลไว้ 1 record ดังโค้ด
CREATE TABLE `table_number` (
  `id` int(11) NOT NULL,
  `product_no` int(11),
  `order_no` int(11)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

INSERT INTO `table_number` (`id`, `product_no`, `order_no`) VALUES (1, 1, 1);

product_no ใช้เก็บ ID ของสินค้าล่าสุด
order_no ใช้เก็บ ID ของ Order ล่าสุด
ในกรณีที่มีรหัสอื่นๆอีกก็สามารถเพิ่มได้ตามที่ต้องการนะครับ

วิธีใช้ ให้อ่าน id ของรหัสที่ต้องการ ออกมาใช้งานได้เลย
SELECT `product_no` FROM `table_number` WHERE `id`=1

ผลลัพท์ที่ได้ก็จะเป็น ID ของสินค้าที่สามารถนำไปใช้ได้เลย ซึ่งหลังจากนำรหัสไปใช้งานแล้ว จะต้องกลับมาอัปเดทข้อมูลว่าใช้งานไปแล้วด้วย
UPDATE `table_number` SET `product_no`=`product_no`+1 WHERE `id`=1
คำเตือน การอ่านข้อมูล ID จากฐานข้อมูลออกมาก่อน อาจเกิดกรณีเลข ID ซ้ำได้ หากมีการอ่านข้อมูลพร้อมๆกันจากหลายๆคน (เช่นการเข้าเว็บพร้อมกัน) ซึ่งหลายๆคนชอบแนะนำให้ทำการป้องกันด้วย SELECT .... FOR UPDATE หรือ เทคนิคอื่นใดที่สามารถ ROLLBACK หรือยกเลิกการบันทึกข้อมูลได้ แต่ผมกลับไม่ชอบวิธีเหล่านี้เลยเพราะ
  1. เมื่อมีการใช้คำสั่ง ตารางจะถูกล๊อก (ในกรณีที่ดีหน่อยจะถูกล๊อกแค่แถว) ซึ่งมีผลให้คำสั่งต่อไป (จากบุคคลอื่น) ต้องรอ
  2. หากมีข้อมูลซ้ำขึ้นมาจริงๆ การบันทึกข้อมูลจะถูกยกเลิก และทำให้การบันทึกไม่สำเร็จ ซึ่งอาจมีปัญหากับผู้ใช้ เช่นในกรณ๊ที่มีผู้ใช้จำนวนมากรอคิวพร้อมๆกัน
  3. การตรวจสอบข้อมูลซ้ำก่อนการบันทึก อาจทำให้เกิด Query ที่ไม่จำเป็นเป็นจำนวนมากและอาจต้องรอนานขึ้น
ซึ่งวิธีที่ผมแนะนำให้ใช้จริง ๆคือ การบันทึกข้อมูลลงไปก่อน เพื่อจอง ID เสร็จแล้วค่อยนำ ID ที่ได้จากการบันทึกออกมาสร้างรหัสสินค้าแล้วถึงจะบันทึกข้อมูลกลับลงไปที่ข้อมูลเดิม
^