ทำความรู้จัก Primary Key ในฐานข้อมูล
เวลาเราเก็บข้อมูลลงในตาราง (Table) ของฐานข้อมูล เราต้องการวิธีระบุตัวตนของแต่ละแถวให้ชัดเจน เหมือนกับการที่เรามีเลขบัตรประชาชนเพื่อบอกว่าใครเป็นใครในประเทศนี้ ในโลกของฐานข้อมูลเราเรียกสิ่งนี้ว่า Primary Key (คีย์หลักที่ใช้ระบุข้อมูลแต่ละแถวให้ไม่ซ้ำกัน)
ถ้าเราไม่มีสิ่งนี้ เราจะเจอปัญหาใหญ่เวลาต้องการแก้ไขหรือลบข้อมูลที่หน้าตาเหมือนกันเป๊ะ เพราะฐานข้อมูลจะไม่รู้ว่าเราหมายถึงแถวไหนกันแน่ การกำหนด Primary Key จึงเปรียบเสมือนการแปะป้ายชื่อให้ข้อมูลแต่ละชิ้น เพื่อให้ระบบจัดการข้อมูลได้อย่างแม่นยำและรวดเร็ว
ในการเลือก Primary Key ที่ดี ควรเป็นค่าที่ไม่ซ้ำกันเลยตลอดกาล และไม่ควรเป็นค่าที่มีโอกาสเปลี่ยนแปลงได้ในอนาคต เช่น รหัสนักศึกษา หรือรหัสสินค้า มักจะถูกเลือกมาทำหน้าที่นี้เพราะมันคงที่และชัดเจนที่สุดสำหรับระบบงานของเรา
-- สร้างตารางใหม่พร้อมกำหนด Primary Key
CREATE TABLE Students (
StudentID INT PRIMARY KEY, -- กำหนดให้คอลัมน์นี้เป็นคีย์หลัก
StudentName NVARCHAR(50)
);
คำสั่ง CREATE TABLE ใช้สร้างตาราง ส่วน StudentID INT คือการบอกว่าให้เก็บตัวเลขจำนวนเต็ม และ PRIMARY KEY คือการสั่งให้คอลัมน์นี้เป็นตัวระบุตัวตนหลัก ห้ามมีค่าซ้ำกันเด็ดขาด
ผลลัพธ์ที่ได้คือตารางชื่อ Students ที่พร้อมเก็บข้อมูลนักเรียน โดยที่ระบบจะบังคับให้เราใส่ค่า StudentID ที่ไม่ซ้ำกันเสมอ ถ้าเราพยายามใส่เลขเดิมซ้ำ ระบบจะแจ้งเตือนความผิดพลาด (Error) ทันที
ใช้งาน IDENTITY(1,1) เพื่อรันเลขอัตโนมัติ
การนั่งพิมพ์เลข ID เองทุกครั้งที่เพิ่มข้อมูลเป็นเรื่องน่าเบื่อและเสี่ยงต่อการพิมพ์เลขซ้ำโดยไม่ได้ตั้งใจ MS-SQL จึงมีตัวช่วยที่ชื่อว่า IDENTITY (คุณสมบัติที่ให้ฐานข้อมูลสุ่มหรือรันเลขให้เองอัตโนมัติ) เพื่อลดภาระของโปรแกรมเมอร์
รูปแบบการใช้คือ IDENTITY(1,1) โดยตัวเลขตัวแรกหมายถึงเลขเริ่มต้น และตัวเลขตัวที่สองหมายถึงจำนวนที่จะเพิ่มขึ้นในแต่ละครั้ง ถ้าเราตั้งไว้แบบนี้ ระบบจะเริ่มจาก 1 แล้วบวกเพิ่มทีละ 1 ไปเรื่อยๆ เป็น 1, 2, 3 และ 4 ตามลำดับ
การใช้ IDENTITY ช่วยให้เราโฟกัสกับการเก็บข้อมูลเนื้อหาจริงๆ โดยไม่ต้องกังวลเรื่องการจัดการเลข ID ในโค้ดของแอปพลิเคชัน ทำให้โค้ดของเราสะอาดขึ้นและลดโอกาสเกิดบั๊ก (ข้อผิดพลาดในโปรแกรม) จากการจัดการเลขลำดับด้วยตัวเอง
-- สร้างตารางที่รันเลข ID อัตโนมัติ
CREATE TABLE Products (
ProductID INT IDENTITY(1,1) PRIMARY KEY, -- เริ่มที่ 1 และบวกทีละ 1
ProductName NVARCHAR(50)
);
-- เพิ่มข้อมูลโดยไม่ต้องใส่เลข ID
INSERT INTO Products (ProductName) VALUES ('Laptop');
INSERT INTO Products (ProductName) VALUES ('Mouse');
บรรทัด IDENTITY(1,1) บอกให้ฐานข้อมูลจัดการเลข ProductID เองตั้งแต่อันแรก ส่วนคำสั่ง INSERT เราไม่ต้องระบุค่าในคอลัมน์ ProductID เลย เพราะฐานข้อมูลจะจัดการให้เราเอง
ผลลัพธ์คือเมื่อเราดูข้อมูลในตาราง Products แถวแรกจะมี ProductID เป็น 1 และแถวที่สองจะเป็น 2 โดยอัตโนมัติ ทำให้เรามั่นใจได้ว่าเลขจะไม่ซ้ำกันแน่นอน
สร้างความยืดหยุ่นด้วย SEQUENCE
บางครั้งเราอาจต้องการเลขชุดที่ใช้ร่วมกันหลายตาราง หรือต้องการควบคุมการรันเลขที่ซับซ้อนกว่าปกติ SEQUENCE (ตัวสร้างลำดับเลขที่ทำงานแยกจากตาราง) จึงเป็นเครื่องมือที่ยืดหยุ่นกว่า IDENTITY เพราะมันไม่ได้ผูกติดอยู่กับตารางใดตารางหนึ่ง
ลองจินตนาการว่าคุณมีระบบออกใบเสร็จและระบบออกใบสั่งซื้อที่ต้องการรันเลขลำดับแยกกัน แต่คุณอยากให้มันดึงเลขจากแหล่งเดียวกันเพื่อความเป็นระเบียบ SEQUENCE จะทำหน้าที่เป็นตัวคอยแจกเลขให้แต่ละตารางตามคำสั่งของเรา
เราสามารถตั้งค่าให้ SEQUENCE เริ่มต้นที่เลขไหนก็ได้ หรือกำหนดให้กระโดดข้ามทีละกี่เลขก็ได้ตามความต้องการของธุรกิจ การใช้มันทำให้เรามีอิสระในการออกแบบโครงสร้างฐานข้อมูลที่ซับซ้อนได้มากขึ้นโดยไม่ถูกจำกัดด้วยกฎของตารางเดียว
-- สร้างตัวรันลำดับเลข
CREATE SEQUENCE OrderSeq
START WITH 1000 -- เริ่มต้นที่ 1000
INCREMENT BY 1; -- เพิ่มทีละ 1
-- เรียกใช้เลขจาก Sequence
SELECT NEXT VALUE FOR OrderSeq;
คำสั่ง CREATE SEQUENCE สร้างตัวกำเนิดเลขขึ้นมาลอยๆ ส่วน NEXT VALUE FOR คือคำสั่งดึงเลขถัดไปออกมาใช้ในคำสั่ง INSERT หรือการคำนวณอื่นๆ ในแอปพลิเคชัน
ผลลัพธ์คือทุกครั้งที่รันคำสั่ง SELECT เราจะได้เลข 1000, 1001, 1002 ไปเรื่อยๆ ซึ่งเลขเหล่านี้เราสามารถนำไปใส่ในตารางต่างๆ ได้ตามต้องการ
การจัดการ IDENTITY_INSERT เมื่อต้องย้ายข้อมูล
ชีวิตโปรแกรมเมอร์มักต้องเจอกับการย้ายข้อมูลจากฐานข้อมูลเก่ามาใหม่ บางครั้งเราจำเป็นต้องรักษาเลข ID เดิมไว้เพื่อไม่ให้ข้อมูลเชื่อมโยงกันผิดพลาด แต่ IDENTITY ปกติจะไม่อนุญาตให้เราใส่เลขเข้าไปเองตามใจชอบ
เราจึงต้องใช้คำสั่ง IDENTITY_INSERT (คำสั่งเปิด-ปิดโหมดอนุญาตให้ใส่เลข ID เอง) เพื่อบอกฐานข้อมูลว่า "ขออนุญาตนะ ครั้งนี้ผมขอจัดการเลข ID เอง" ซึ่งต้องใช้ด้วยความระมัดระวังสูงสุดเพื่อป้องกันเลขซ้ำ
ขั้นตอนคือต้องเปิดโหมดนี้ก่อนทำการเพิ่มข้อมูล แล้วต้องปิดทันทีหลังจากทำเสร็จ ถ้าลืมปิดอาจทำให้เกิดปัญหาตามมาได้หากมีคนอื่นพยายามเพิ่มข้อมูลในตารางนั้นในอนาคต
-- เปิดโหมดให้ใส่ ID เองได้
SET IDENTITY_INSERT Products ON;
-- ใส่ข้อมูลพร้อมระบุ ID
INSERT INTO Products (ProductID, ProductName) VALUES (99, 'Keyboard');
-- ปิดโหมดทันทีหลังใช้งานเสร็จ
SET IDENTITY_INSERT Products OFF;
คำสั่ง SET IDENTITY_INSERT ON คือการปลดล็อก ส่วน OFF คือการล็อกกลับเหมือนเดิม การใส่ค่า ProductID ต้องทำควบคู่กับ ProductName ทุกครั้งเมื่อเปิดโหมดนี้
ผลลัพธ์คือข้อมูลใหม่จะถูกบันทึกด้วย ProductID เป็น 99 แทนที่จะเป็นเลขลำดับถัดไปตามปกติ ช่วยให้การย้ายข้อมูลหรือการแก้ไขข้อมูลย้อนหลังทำได้โดยไม่เสียความสัมพันธ์เดิม
จุดที่มือใหม่มักพลาดและวิธีป้องกัน
สิ่งที่มือใหม่พลาดบ่อยที่สุดคือการลืมใส่ Primary Key ตั้งแต่แรก ทำให้ข้อมูลในตารางไม่มีตัวตนที่แน่นอน หรือการพยายามใส่ค่าในคอลัมน์ IDENTITY โดยไม่ใช้ IDENTITY_INSERT ซึ่งจะโดนฐานข้อมูลปฏิเสธทันที
อีกเรื่องคือการสับสนระหว่าง IDENTITY กับ SEQUENCE ถ้างานของคุณเป็นงานง่ายๆ การใช้ IDENTITY ก็เพียงพอแล้ว อย่าพยายามทำให้ระบบซับซ้อนเกินความจำเป็นด้วยการใช้ SEQUENCE ตั้งแต่เริ่มต้นโปรเจกต์
คำแนะนำคือให้จดบันทึกโครงสร้างฐานข้อมูลไว้เสมอว่าตารางไหนใช้การรันเลขแบบใด เพื่อป้องกันความงงเวลาต้องกลับมาเขียนโค้ดแก้ไขในอีกสามเดือนข้างหน้า การจัดระเบียบฐานข้อมูลตั้งแต่ตอนเริ่มจะช่วยให้ชีวิตคุณง่ายขึ้นมากในระยะยาว
- ตรวจสอบให้แน่ใจว่าทุกตารางมี Primary Key เสมอ
- อย่าใช้ IDENTITY_INSERT พร่ำเพรื่อเพราะเสี่ยงข้อมูลซ้ำ
- ใช้ SEQUENCE เฉพาะเมื่อจำเป็นต้องใช้เลขร่วมกันหลายตาราง
สรุป: การเลือกใช้ให้เหมาะกับงาน
การเข้าใจเรื่อง Primary Key, IDENTITY และ SEQUENCE คือพื้นฐานสำคัญของโปรแกรมเมอร์มืออาชีพ การเลือกใช้เครื่องมือให้ถูกกับสถานการณ์จะช่วยให้ระบบของคุณมีเสถียรภาพและขยายตัวได้ง่ายในอนาคต
หากคุณกำลังทำแอปพลิเคชันทั่วไป การใช้ IDENTITY(1,1) เป็นวิธีที่ง่ายและเร็วที่สุดในการจัดการเลข ID แต่ถ้าคุณต้องจัดการระบบที่มีหลายตารางเชื่อมโยงกันอย่างซับซ้อน SEQUENCE จะเป็นตัวเลือกที่ดูเป็นมืออาชีพมากกว่า
จำไว้ว่าฐานข้อมูลที่ดีต้องมีความถูกต้องและชัดเจน การกำหนดค่าเหล่านี้ให้ถูกต้องตั้งแต่เริ่มฝึกฝน จะช่วยสร้างนิสัยการเขียนโค้ดที่รัดกุมและเป็นระเบียบ ซึ่งเป็นคุณสมบัติที่บริษัทซอฟต์แวร์มองหาในตัวโปรแกรมเมอร์ทุกคนครับ