การใช้งานความสัมธ์แบบ M:N ภาคปฏิบัติ จัดทำโดย : อ้ายคำปัน
การใช้งานความสัมธ์แบบ M:N ภาคปฏิบัติ บทความนี้ทีแรกผมตั้งใจจะเขียนเกี่ยวกับ "การทำ output buffering" แต่ก็พบความไม่ชัดเจนหลายอย่างจึงขอยกไปเขียนในโอกาสต่อไป

....หลายท่านที่มีความรู้พื้นฐานเกี่ยวกับฐานข้อมูลเชิงสัมพันธ์(Relational Database)
หรือเคยผ่านการเรียนวิชาเกี่ยวกับ Database ในมหาวิทยาลัยมาคงจะรู้จัก
"ความสัมพันธ์แบบ M:N (Many to Many)" ดี แต่หากท่านใดยังไม่รู้จักหรือยังไม่มีความรู้ก็อย่าเพิ่งน้อยใจแล้วก็ไม่ต้องไปหาซื้อหนังสือที่ไหนนะครับ ไปหาอ่านได้ที่เว็ป uni.net หรือใช้ google หาดูก็ได้ครับมีเยอะแยะเลย

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


ผมขอกล่าวเฉพาะ M:N และไม่ขอกล่าวทางทฤษฎีเพราะมีคนเขียนไปไว้เยอะแล้ว ส่วนความสัมพันธ์แบบอื่นนั้นคือ 1:M (One to Many) และ M:1 (Many to One) เป็นลักษณะของการ JOIN TABLE ปกติครับคิดว่าคงทำกันได้อยู่แล้วถ้า JOIN TABLE เป็น แต่ M:N นั้นมันมีทริคเพิ่มเติมอีกเล็กน้อยที่ผมกำลังจะนำเสนอ


เอาละครับมาเริ่มกันเลย
ถ้าโจทย์มีอยู่ว่า สำนักเขียนโปรแกรมสุดยอดโปรแกรมมิ่ง มีอาจารย์สอนเขียนโปรแกรมและแต่ละคนรับผิดชอบวิชาที่สอนดังนี้
อาจารย์ วิชาที่สอน
อ.อีโก้ Java, C#.NET, PHP
อ.เซียน เซียน PHP, VB, VB.NET
อ.เทพ VB,VB.NET
อ.แอดวานซ์ Java,C/C++,PHP
อ.คัมภีร์ คัมภีร์ Java, คัมภีร์ PHP, คัมภีร์ OOP
(ดูจากชื่อแล้วแต่ละคนสุดยอดทั้งนั้นเลยนะครับ ^^ ปล.นอกเรื่อง)

ถ้าเจอโจทย์แบบนี้ท่านจะออกแบบ Database อย่างไรครับ อาจเป็นแบบนี้
tb_teaching
teacher [varchar(50)] subject [text]
XXXXX XXXXX, XXXX, XXXX
ลักไก่แบบนี้ขอบอกว่าผิดครับเพราะกฏข้อแรกของ Database คือห้ามมีกลุ่มของข้อมูลซ้ำครับ

หลายท่านอาจคิดได้ดีขึ้นหน่อย อาจเป็นแบบนี้

tb_teacher
teacher_id [int(3)] teacher [varchar(50)]
XXX XXXXXX

tb_subject
subject_id [int(3)] subject [varchar(50)]
XXX XXXXXX

tb_teaching
teacher_id [int(3)] subject1_id [int(3)] subject2_id [int(3)] subject3_id [int(3)]
XXXXX XXXXX XXXXX XXXXX
จำนวนฟิลด์ subjectX_id เพิ่มตามจำนวนวิชาสูงสุดที่อาจารย์แต่ละท่านจะสามารถสอนได้
กรณีที่สองนี้เป็นปัญหาที่พบเห็นได้บ่อย คือ รู้จักการ JOIN และเข้าใจว่า Database ห้ามมีกลุ่มของข้อมูลซ้ำ แต่ไม่รู้ว่าจะออกแบบให้มีความสัมพันธ์แบบ M:N อย่างไร ดังนั้นทางออกจึงเป็นอย่างที่เห็น

ทีนี้เรามาดูคำตอบที่ถูกต้องกันครับ
tb_teacher
teacher_id [int(3)] teacher [varchar(50)]
XXX XXXXXX

tb_subject
subject_id [int(3)] subject [varchar(50)]
XXX XXXXXX

rel_tb_teacher_subject
teacher_id [int(3)] subject_id [int(3)]
XXX XXX

ทริคของการใช้งานความสัมพันธ์แบบ M:N คือการสร้าง Relation Table (หาความหมายเพิ่มเติมได้ตามเว็ปที่เขียนเกี่ยวกับ Database) ขึ้นมาเก็บคีย์หลัก (Primary Key) ของ Table ที่ต้องการสร้างความสัมพันธ์ไว้ พูดอีกอย่างก็คือ Relation Table คือ Table ที่มี คีย์หลักเป็นคีย์นอก(Foreign Keys) นั้นเอง เพราะ M:N = M:1+1:M พอจะเห็นภาพหรือยังครับ Relation Table ก็คือเครื่องหมายบวกในสมการนั้นเอง จึงเป็นตารางที่นิยมเก็บแต่คีย์ไม่เก็บข้อมูลเพราะจะมีปัญหาตอนที่ทำการ JOIN TABLE

ทำความเข้าใจเบี้องต้นกันแล้วก็มาลงมือปฏิบัติกันเลย
ขั้นแรก สร้าง Table ในฐานข้อมูลตามที่กล่าวไว้เมื่อกี้ คำสั่ง SQL ที่เห็น เป็นของ MySQL 4.0 แต่สามารถใชัในเวอร์ชันสูงกว่าได้ครับ เคยลองใช้ MySQL 5.0 แล้วพบว่าคำสั่ง SQL ใหม่ ๆ เพิ่มขึ้นเยอะมาก

CREATE TABLE `tb_teacher` (
`teacher_id` int(3) NOT NULL auto_increment,
`teacher` varchar(50) default NULL,
PRIMARY KEY (`teacher_id`)
) TYPE=MyISAM;

INSERT INTO `tb_teacher` VALUES (1,'อ.อีโก้');
INSERT INTO `tb_teacher` VALUES (2,'อ.เซียน');
INSERT INTO `tb_teacher` VALUES (3,'อ.เทพ');
INSERT INTO `tb_teacher` VALUES (4,'อ.แอดวานซ์');
INSERT INTO `tb_teacher` VALUES (5,'อ.คัมภีร์');

CREATE TABLE `tb_subject` (
`subject_id` int(3) NOT NULL auto_increment,
`subject` varchar(50) default NULL,
PRIMARY KEY (`subject_id`)
) TYPE=MyISAM;

INSERT INTO `tb_subject` VALUES (1,'Java');
INSERT INTO `tb_subject` VALUES (2,'C#.NET');
INSERT INTO `tb_subject` VALUES (3,'PHP');
INSERT INTO `tb_subject` VALUES (4,'เซียน PHP');
INSERT INTO `tb_subject` VALUES (5,'VB');
INSERT INTO `tb_subject` VALUES (6,'VB.NET');
INSERT INTO `tb_subject` VALUES (7,'C/C++');
INSERT INTO `tb_subject` VALUES (8,'คัมภีร์ Java');
INSERT INTO `tb_subject` VALUES (9,'คัมภีร์ PHP');
INSERT INTO `tb_subject` VALUES (10,'คัมภีร์ OOP');

CREATE TABLE `rel_tb_teacher_subject` (
`teacher_id` int(3) NOT NULL auto_increment,
`subject_id` int(3) NOT NULL default '0',
PRIMARY KEY (`teacher_id`,`subject_id`)
) TYPE=MyISAM;

INSERT INTO `rel_tb_teacher_subject` VALUES (1,1);
INSERT INTO `rel_tb_teacher_subject` VALUES (1,2);
INSERT INTO `rel_tb_teacher_subject` VALUES (1,3);
INSERT INTO `rel_tb_teacher_subject` VALUES (2,4);
INSERT INTO `rel_tb_teacher_subject` VALUES (2,5);
INSERT INTO `rel_tb_teacher_subject` VALUES (2,6);
INSERT INTO `rel_tb_teacher_subject` VALUES (3,5);
INSERT INTO `rel_tb_teacher_subject` VALUES (3,6);
INSERT INTO `rel_tb_teacher_subject` VALUES (4,1);
INSERT INTO `rel_tb_teacher_subject` VALUES (4,3);
INSERT INTO `rel_tb_teacher_subject` VALUES (4,7);
INSERT INTO `rel_tb_teacher_subject` VALUES (5,8);
INSERT INTO `rel_tb_teacher_subject` VALUES (5,9);
INSERT INTO `rel_tb_teacher_subject` VALUES (5,10);


ขั้นที่สอง สร้างไฟล์ php ขึ้นมา 1 ไฟล์แล้วก็เขียนโค้ดดังนี้
<?
$link = mysql_connect("localhost","user","password"); #อย่าลืมเปลี่ยนให้เป็นของเครื่องตัวเองก่อนทดลอง ^^
mysql_select_db("test"); #ฐานข้อมูลที่ใช้

$sql = "SELECT tb_teacher.teacher_id, teacher, tb_subject.subject_id, subject FROM rel_tb_teacher_subject
INNER JOIN tb_teacher ON rel_tb_teacher_subject.teacher_id=tb_teacher.teacher_id
INNER JOIN tb_subject ON rel_tb_teacher_subject.subject_id=tb_subject.subject_id
ORDER BY tb_teacher.teacher_id, tb_subject.subject_id ASC"
; #คำสั่ง SQL ที่ใช้ในการ JOIN TABLE

$result =
mysql_query($sql) or die("Error : ".mysql_error());
?>
<strong>ตารางวิชาสอนของอาจารย์สำนักเขียนโปรแกรมสุดยอดโปรแกรมมิ่ง</strong><br>
<br>
<table width="600" border="1" cellspacing="0" cellpadding="0">
<tr align="center">
<td><strong>
ลำดับที่</strong></td>
<td><strong>รหัสอาจารย์</strong></td>
<td><strong>ชื่ออาจารย์</strong></td>
<td><strong>รหัสวิชา</strong></td>
<td><strong>วิชาที่สอน</strong></td>
</tr>
<?
$i = 1;
while($value = mysql_fetch_array($result)){
?>
<tr>
<td><?=$i?></td>
<td><?=$value['teacher_id']?></td>
<td><?=$value['teacher']?></td>
<td><?=$value['subject_id']?></td>
<td><?=$value['subject']?></td>
</tr>
<?
$i++;
}
//end while
mysql_free_result($result);
mysql_close($link);
?>
</table>

ก็จะได้ผลลัพธ์ดังนี้


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

-----------------------------------------------------------------------------------------------------------

ตั้งใจมาซะนานเลยกว่าจะเขียนบทความนี้เสร็จ (ผ่านการเพาะบ่มจนได้ที่) ....อยากให้นำไปประยุกต์กันนะครับ เพราะบทความของผมเป็นแนวทำความเข้าใจเชิงลึกเพื่อการต่อยอด มีหลายท่านเข้ามาอ่านบทความของผมแล้วส่งโปรแกรมเป็นตัว ๆ มาให้แก้บั๊ก อันนี้ขออณุญาตไม่ตอบกลับเพราะเป็นการช่วยตัวท่านเองด้วยให้พยายามเอาชนะปัญหาแล้วท่านก็จะสามารถพัฒนาฝีมือตัวเองขี้นได้ แต่หากเป็นการขอคำชี้แนะหรือแนวทางอันนี้พอได้ครับ
...เป็นกำลังใจให้เว็ปไทยดี ๆ สร้างสรรค์งานดี ๆ เพื่อสังคมอย่างนี้ตลอดไปครับ


บทความหน้ายังมีอีกหลายเรื่องที่ผมอยากจะเขียน...ห้ามพลาด! ติดตามได้ที่นี่ที่เดียว (เพราะผมเขียนที่เดียว^^)


Download Source Code

ผู้จัดทำ : วิวัฒน์ มณีจันสุข
ที่อยู่อีเมลล์ :
winnerww@hotmail.com
website : http://computerpsycho.saiyaithai.org
คุณอาจสนใจ
วิธีค้นหา Serial No. ของโปรแกรมในเครื่อง
เว็บไทยดีดี (20,513 - 03 พ.ย. 50)
เทคนิคการเปลี่ยนภาพขาวดำให้เป็นภาพสี
Mr.GuruZ (70,626 - 04 มิ.ย. 49)
วางแผนรับมือจากการโดนโจมตีเครื่องในเน็ตเวิร์ก
เว็บไทยดีดี (14,977 - 29 ก.ย. 50)
ยกเลิกการสร้างไฟล์ .bak ไม่ให้มากวนใจในการทำเว็บ
Mr.GuruZ (19,480 - 08 มี.ค. 51)
การสร้าง Site เพื่อเก็บเว็บเพจ
Mr.GuruZ (27,017 - 26 พ.ย. 50)
คำอธิบาย error ที่เกี่ยว PHP ที่มักจะพบกันบ่อย ๆ
first (43,067 - 21 ม.ค. 51)
Herizontal Type Mask Tool (T)
Mr.GuruZ (45,570 - 22 ก.ย. 50)
การจัดระเบียบ code
Mr.GuruZ (55,647 - 31 มี.ค. 50)