ปัญหาอย่างหนึ่ง และ เป็นเรื่องที่สำคัญมากของการพัฒนางานระบบฐานข้อมูล คือ ไม่รู้เรื่อง ไม่เข้าใจการออกแบบตารางข้อมูล จากที่ผมได้ลองวิเคราะห์ปัญหานี้ดู ซึ่งก็ล้วนแล้วแต่มาจากการที่ผู้เรียนไปยึดมั่น ยึดถือ หลักการตามตำรา เช่น ทฤษฎี Normalization กันมากเกินไป ... อนึ่ง โปรดเข้าใจน่ะครับว่า การที่ผมเขียนโปรแกรมเป็นเนี่ย ในขณะนั้นผมยังไม่ได้เข้ามาศึกษาคอมพิวเตอร์ในระดับปริญญาตรี ที่ มจพ. แต่อย่างใด เพราะตัวผมต้องฝึกฝนเอาเองโดยลำพังในช่วงที่ทำงานอยู่ แต่สิ่งที่ผมเรียนรู้นั้น ไม่ว่าจะเป็นเรื่องของฐานข้อมูล เรื่องของการโปรแกรมมิ่ง ก็ล้วนแล้วแต่ค้นคิดหาแนวทางของตัวเองแทบทั้งสิ้น หลายท่านก็คงจะเห็นแล้วว่าการเขียนโค้ดของผมมันไม่ (ปกติ ... 55555+) เหมือนชาวบ้าน ชาวเมืองเขาเลย ... หันมาดูเรื่องของตารางข้อมูล เพราะที่ผ่านๆมาผมเองยังไม่ได้สาธยาย ให้เห็นถึงกระบวนการขั้นตอนแนวคิด (ของผม) ออกมาได้อย่างเด่นชัดนัก ดังนั้นก่อนที่จะก้าวเข้าไปลงโค้ดโปรแกรม ผมจะร่าย (มนต์ดำ ... อีกแล้ว) ถึงขั้นตอนต่างๆให้ละเอียด เท่าที่ผมจะทำได้ในเวลานี้ ... อย่าลืม เราออกแบบตารางข้อมูลยังไง ก็ต้องเขียนโปรแกรมไปตามนั้น
 |
- ตารางข้อมูล - Table
- ขั้นตอนกระบวนการคิด
- แต่ละหลัก (Column) เรียกว่า ฟิลด์ข้อมูล (Field) แต่ละฟิลด์ที่ได้มานั้น ก็มาจากความต้องการในการจัดเก็บข้อมูลแต่ละโปรเจค
- แต่ละแถว (Row) เรียกว่า รายการ (Record) จะเป็นส่วนในเรื่องการจัดเก็บข้อมูลแล้ว
- นำเอา Field มาเป็นตัวหลักในการออกแบบตารางข้อมูล เพื่อกำหนดชื่อฟิลด์ และชนิดของข้อมูล
- ในตารางใดๆ จะมี Primary Key หรือ PK หรือ คีย์หลัก เพื่อใช้ในการอ้างถึงข้อมูลที่ต้องการ โดยค่านี้ควรจะเป็นตัวเลข (Number) เพื่อให้ง่าย สะดวก รวดเร็ว แม่นยำ ต่อการเข้าถึงข้อมูล และที่สำคัญจะต้องไม่เกิดค่าซ้ำกันขึ้น (ยกเว้นบางกรณี เอาไว้จะกล่าวถึงภายหลัง)
- ในตารางใดๆ อาจจะมี Foreign Key หรือ FK หรือ คีย์รอง เพื่อใช้ในการเชื่อมความสัมพันธ์เข้าไปหาตารางอื่นๆได้ ค่านี้ต้องเป็นตัวเลขเท่านั้น (หรือใครอยากจะใช้แบบอื่นก็ทำไปเหอะ)
- หลักๆก็มีเพียงเท่านี้เอง ... เพราะผมจะไม่อ้างถึงศัพท์อื่นๆแต่อย่างใด
- การออกแบบตารางข้อมูลขั้นพื้นฐาน
โครงสร้างตารางข้อมูลแบบบ้านๆ ... ล้วนแล้วมีแต่ Text ... 
- นี่คือตารางหลัก (ต่อไปผมจะเรียกมันว่า Master) ชื่อตาราง tblAsset
- ซึ่งฟิลด์ AssetName, BrandName และ GroupName (ยกฟิลด์มาบางส่วน) ล้วนแล้วแต่เก็บข้อมูลแบบ Text
- จะเห็นได้ว่าเกิดการซ้ำกันของข้อมูล ซึ่งหากออกแบบเช่นนี้
- ไฟล์ฐานข้อมูล จะโตวันโตคืน และรอเวลาพังยับเยิน ยู่ยี่
- ยากต่อการพัฒนา หรือ ปรับปรุงให้มีประสิทธิภาพ
- จะก่อให้เกิดผลเสียต่อระบบงานตามหลังมาอีกมากมาย
- และที่แน่นอนที่สุดของที่สุด ผู้ใช้งานย่อมต้องเสียเวลาคีย์ข้อมูลใหม่ ซ้ำๆซากๆ โปรแกรมจึงไม่เป็นมิตรกับผู้ใช้งานนัก (แบบว่า ... มันเป็นมิตรกะผู้เขียนโปรแกรมเพียงคนเดียว ... 55555+)
- จากกฏข้อที่ 1 (ของผม) ฟิลด์ใดที่มีการซ้ำกันของข้อมูล ให้จับฟิลด์นั้นแยกออกไป เพื่อสร้างเป็นตารางใหม่ ... ตัวอย่างนี้จะใช้ฟิลด์ "ยี่ห้อ - BrandName" มาพิจารณาเป็นตัวอย่างให้ได้รับชมกัน
- การแยกฟิลด์ข้อมูลออกมาสร้างตารางใหม่ ให้ชื่อว่า tblBrandName หรือ กลายมาเป็นตารางย่อย (ต่อไปผมจะเรียกมันว่า Detail)
- ประกอบด้วย
- BrandNamePK เป็นแบบตัวเลขจำนวนเต็ม (Integer) เพื่อเป็น Primary Key ของตารางตัวมันเอง
- BrandName เป็นข้อมูลแบบ Text ขนาด 80 ตัวอักษร (ข้อมูลเดิมที่มันเคยซ้ำกันนั่นเอง) ... ซึ่งข้อมูลที่ถูกเก็บในแต่ละรายการ (Record) ก็ต้องมีเพียงรายการเดียว ห้ามซ้ำ (หากมันซ้ำกันอีก แล้วจะแยกออกมาทำไมล่ะ) เช่น BrandNamePK ซึ่งเป็น Primary Key มีค่าเท่ากับ 2 จะมีข้อมูลยี่ห้อเป็น IBM Thailand (ขั้นตอนนี้เราควรหาตัวอย่างข้อมูลมาทดสอบดูด้วย)
- เทคนิคของการป้องกันความผิดพลาด ... ให้สังเกตว่าทุกตารางย่อย ที่ผมออกแบบ จะมี Primary Key = 0 เอาไว้ เพื่อป้องกันการไม่เลือกรายการใดๆเลยของผู้ใช้งาน มิเช่นนั้นมันจะหาความสัมพันธ์กันไม่เจอนั่นเอง (คงจะมีผมคนเดียวที่ใช้แบบนี้มั้งในประเทศ ... 55555+)
- ตามกฏข้อที่ 2 (ของผม) ฟิลด์ไหนที่ถูกแยกออกไป ให้นำกลับมาเชื่อมโยงความสัมพันธ์กันใหม่ ซึ่งการเชื่อมโยงเข้าหากันนั้น จะต้องใช้ข้อมูลชนิดที่เป็นตัวเลข (Number) เท่านั้น ... กลับมาพิจารณา ตารางหลัก (tblAsset) ใหม่อีกครั้ง
- ขั้นตอนการเชื่อมโยงความสัมพันธ์
- เพิ่มฟิลด์ใหม่เข้าไป นั่นคือ BrandNameFK (การที่ผมต่อท้ายด้วย FK = Foreign Key เพื่อระบุว่ามันเป็นคีย์รอง ไม่ใช่คีย์หลักในตาราง tblAsset)
- ชนิดของข้อมูล BrandNameFK กำหนดเป็นแบบตัวเลขจำนวนเต็ม (Integer) เพื่อให้ตรงกันกับ Primary Key ในตารางย่อย (tblBrandName)
- จาก MS Access ให้เลือก วัตถุ --> แบบสอบถาม (Query) --> สร้างแบบสอบถามในมุมมองออกแบบ เพื่อเชื่อมความสัมพันธ์ (Relation) ระหว่างตารางข้อมูล
- เลือกตาราง 2 ตารางเข้ามา คือ tblAsset กับ tblBrandName
- การเชื่อมความสัมพันธ์ (Relation) ระหว่างตารางข้อมูล
- จากตาราง tblBrandName กดเมาส์ซ้ายเลือกฟิลด์ BrandNamePK แล้วลากไปหาฟิลด์ BrandNameFK ที่อยู่ในตาราง tblAsset ... นี่คือเกิดการสร้างความสัมพันธ์ (Relation) เป็นที่เรียบร้อย (จะลากจากตัวไหนไปหาตัวไหนก็ได้)
- เลือกฟิลด์ที่ต้องการในแต่ละตาราง แล้วลากมาใส่ไว้ในเขตข้อมูลทางด้านล่าง
- เลือกมุมมองแผ่นข้อมูลในการแสดงผล
- การแสดงผลตารางที่เกิดความสัมพันธ์ขึ้นมา
- บทสรุป
- จะเห็นว่าฟิลด์ BrandNameFK ของตารางหลัก tblAsset จะมีค่าเท่ากันกับ BrandNamePK ของตาราง tblBrandName ... เพราะนี่แหละที่เราเรียกว่า "ความสัมพันธ์ - Relation"
สิ่งที่ต้องจดจำไว้
- ข้อมูลในตารางหลัก tblAsset (Master) จะต้องมีอยู่ในตารางย่อย tblBrandName (Detail) เสมอ ... ถึงจะเกิดความสัมพันธ์ขึ้นได้
- ข้อมูลในตารางย่อย (tblBrandName) ไม่จำเป็นต้องมีอยู่ในตารางหลัก (tblAsset)
- การพิสูจน์
บทสรุป ...
- ในการเชื่อมความสัมพันธ์ ข้อมูล (หรือ Foreign Key - FK) ที่อยู่ในตารางหลัก (Master) ในที่นี้ คือ tblAsset จะต้องมีค่าที่ชี้เข้าไปหา Primary Key ของตารางย่อย (Detail) ในที่นี้ คือ tblBrandName ให้ตรงกัน
- สังเกตว่า ... หากเราเปลี่ยนค่าในฟิลด์ BrandName โดยมันจะเปลี่ยนเป็นชื่อยี่ห้ออะไรก็แล้วแต่ตามทีเหอะ แต่ค่า Primary Key และ Foreign Key มันไม่ได้เปลี่ยนแปลงตามไปเลย มันยังคงสภาวะของความสัมพันธ์ไว้อย่างเหนียวแน่น (ตามตำราไทยๆเขาเรียกอะไรผมก็ไม่แน่ใจนัก ... 55555+)
- การเชื่อมความสัมพันธ์ของตารางหลัก (Master) เข้ากับตารางย่อย (Detail) ... สำหรับใช้งานจริง
 ทุกๆตารางย่อย (Detail) ก็จะออกแบบ และ กระทำขั้นตอนต่างๆเช่นเดียวกันกับตารางยี่ห้อสินค้า (tblBrandName) จากนั้นก็รวมกันเข้ามาทั้งหมดจากแบบสอบถาม แหละที่ผมอธิบายแบบแจกแจง แยกแยะมาให้ดูทั้งหมด แท้ที่จริงแล้วมันเกิดความสัมพันธ์ในลักษณะแบบ 1 : 1 นั่นเอง แต่ผมอยากให้พี่น้องได้ลองพยายามทำความเข้าใจ โดยไม่ต้องผ่านหลักการ หรือ ทฤษฎีของการทำ Normalization เพราะเรื่องราวของการเชื่อมความสัมพันธ์ในแบบลักษณะ 1 : MANY ผมก็ใช้หลักการเดียวกันนี่แหละมาอธิบายให้ตัวเองเข้าใจ
- การคัดลอก SQL Statement เพื่อนำไปใช้งานใน MS Visual Basic 6.0
 เลือกฟิลด์ต่างๆที่ต้องการเพื่อนำไปใช้งาน ... สำหรับฟิลด์ Primary Key ของตารางย่อย ไม่ต้องนำเข้ามาใช้งาน ในการแสดงผล เพราะหากเราเชื่อมความสัมพันธ์ได้ถูกต้อง จึงไม่มีความจำเป็นต้องดึงฟิลด์นี้มา รวมไปถึงตอนที่ Save หรือ บันทึกข้อมูล ลงไปด้วย ( จะใช้ Foreign Key อย่างเดียว)
Statement = "SELECT tblAsset.*, tblAssetName.AssetName, tblBrandName.BrandName, " & _
" tblGroup.GroupName, tblUnit.UnitName, tblSource.SourceName, " & _
" tblStatus.StatusName, tblLocation.LocationName " & _
" FROM tblStatus INNER JOIN (tblSource INNER JOIN ((tblUnit INNER JOIN " & _
" (tblBrandName INNER JOIN (tblGroup INNER JOIN (tblAssetName INNER JOIN " & _
" tblAsset ON tblAssetName.AssetNamePK = tblAsset.AssetNameFK) ON " & _
" tblGroup.GroupNamePK = tblAsset.GroupNameFK) ON tblBrandName.BrandNamePK = " & _
" tblAsset.BrandNameFK) ON tblUnit.UnitPK = tblAsset.UnitFK) INNER JOIN " & _
" tblLocation ON tblAsset.LocationFK = tblLocation.LocationPK) ON tblSource.SourcePK = " & _
" tblAsset.SourceFK) ON tblStatus.StatusPK = tblAsset.StatusFK " & _
" ORDER BY AssetPK "
ตัดเข้ามาใส่ใน MS Visual Basic 6.0 จะง่าย และ รวดเร็ว เที่ยงตรง แม่นยำ ... แค่ปรับรูปแบบการเชื่อมคำสั่งในแต่ละบรรทัด สังเกตได้เลยว่า ณ เวลานี้ เราไม่ได้ไปจด ไปจำคำสั่งของ SQL Statement (Query) แต่อย่างใดแล้ว
 จาก SQL Statement ทางด้านบน เมื่อนำไปใช้ในโปรแกรม และ Run ออกมา ... หน้าจอที่ได้จึงเป็นเช่นนี้ครับ ... พี่น้อง
Conclusion: จะเห็นได้อย่างชัดเจนเลยว่า การออกแบบตารางข้อมูลแบบนี้ จะทำให้ลดปริมาณของข้อมูลลงไปได้เยอะมากๆ เพราะเราสร้างความสัมพันธ์ให้ตัวเลขจำนวนเต็ม Integer ซึ่งมีขนาด 2 ไบต์ มาทดแทนการใช้งานข้อมูลแบบ Text ที่เราอาจต้องจับจองพื้นที่เอาไว้นับหลายสิบไบต์ ... แต่ก็นั่นแหละ การออกแบบเช่นนี้ ก็จะทำให้การเขียนโค้ดเข้าไปควบคุมการทำงาน ยากลำบากขึ้นไปอีก ... มาดูกันต่อเลยดีกว่าว่า "มันยากจริงอย่างที่คิดไว้หรือเปล่า"
อ่านรายละเอียดโปรแกรมระบบฐานข้อมูลครุภัณฑ์ ภาคเขียนโปรแกรม
|