PHP กับจัดการฐานข้อมูลหมวดหมู่สินค้า MySQL แบบใช้ตารางเพียงตารางเดียวเท่านั้น

โดย SONGCHAI SAETERN

การเขียนโปรแกรม PHP แสดงหมวดหมู่สินค้า



สำหรับโครงสร้างฐานข้อมูลแบบทั่วไปเมื่อมีรายการย่อย เราจะใช้หลักการ One -> Many คือมี 1 ตารางหมวดหมู่หลัก และมีอีก 1 ตารางเป็นหมวดหมู่ย่อย






แต่ปัญหาของกรณีแยกตารางออกจากกันนี้ ตัวผู้เขียนพบปัญหาว่าเมื่อมีหมวดหมู่ย่อยลงไปอีก  3 ชั้นบ้าง 4 ชั้นบ้าง หรืออาจจะมีหมวดย่อยไม่จำกัด ก็จะทำให้การเขียนโปรแกรมนั้นยากขึ้น



เช่น การเขียนคำสั่ง SQL JOIN เพื่อดึงข้อมูลตารางที่ 2 มาแสดง

SELECT
       id, name
FROM
       tb_cate1 AS tbMaster
INNER JOIN
       tb_cate2 AS tbDetail ON tbMaster.id= tbDetail.ref_id
WHERE
       {เงื่อนไขที่ใช้ค้นหา}

และเมื่อมีการเชื่อมหลายๆตาราง ก็จะทำให้หน้าเว็บทำงานได้ช้าลง (อ่านเรื่อง "การทำ Index ให้ MySQL Database เพื่อเพิ่มความเร็ว")


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


เรามาดูกันว่า จะเขียนโปรแกรม PHP เพื่อแสดงข้อมูลหมวดหมู่เหล่านี้ได้อย่างไร


[ โค้ด PHP ]
<?php
try {
$user = 'tobedev';
$pass = 'abcd.1234';
$db = 'test';
$charset = 'utf8';
$dbh = new PDO("mysql:host=localhost;dbname=$db;charset=$charset", $user, $pass);
} catch (PDOException $e) {
    print "Error!: " . $e->getMessage() . "<br/>";
    die();
}
//Query Data
$sth = $dbh->prepare("SELECT * FROM tb_category");
$sth->execute();
$result = $sth->fetchAll(PDO::FETCH_ASSOC);
$data = array();
$sub_data = array();
//Group data with parent_id
foreach($result as $row){
if($row['ref_parent_id'] > 0){
$sub_data[$row['ref_parent_id']][$row['id']] = $row;
}else{
$data[$row['id']] = $row;
}
}
// SET sub category
foreach($data as $row){
if($sub = findSubCategory($row['id'], $sub_data)){
$data[$row['id']]['sub'] = $sub;
}
}
//echo '<pre><h2>MAIN</h2>', print_r($data,true), '</pre>';
//echo '<pre><h2>SUB</h2>', print_r($sub_data,true), '</pre>';

function displayCategory($data, $sub=1){
echo '<br/>' . str_repeat("&nbsp;",$sub*4) . '- ' . $data['name'];
if(isset($data['sub'])){
$sub++;
//Recursive Function
foreach($data['sub'] as $row){
displayCategory($row, $sub);
}
}
}
function findSubCategory($id, $sub_data){
if(isset($sub_data[$id])){
foreach($sub_data[$id] as $row){
//Recursive Function
if($sub = findSubCategory($row['id'], $sub_data)){
$sub_data[$id][$row['id']]['sub'] = $sub;
}
}
return $sub_data[$id];
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
  <title>PHP - Category : PhpCodeMania.Blogspot.Com</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
  <h1>PHP - Product Category</h1>
  <pre>
  <?php
  foreach($data as $row){
displayCategory($row);
  }
  ?>
  </pre>
</div>
</body>
</html> 



ผลลัพธ์จากโปรแกรมที่ได้

การทำงานของโค้ด


$sth = $dbh->prepare("SELECT * FROM tb_category");
$sth->execute();
$result = $sth->fetchAll(PDO::FETCH_ASSOC);

ตัวแปร $result จะเก็บค่าเป็นอาร์เรย์ ที่ได้จาก tb_category

foreach($result as $row){
if($row['ref_parent_id'] > 0){
$sub_data[$row['ref_parent_id']][$row['id']] = $row;
}else{
$data[$row['id']] = $row;
}
}
โค้ดด้านบนนี้จะจัดรูปแบบข้อมูล เพื่อแยกระหว่าง
รายการหมวดหมู่หลัก = $data
รายการหมวดหมู่ย่อย = $sub_data


foreach($data as $row){
if($sub = findSubCategory($row['id'], $sub_data)){
$data[$row['id']]['sub'] = $sub;
}
}

การเรียกฟังก์ชั่น findSubCategory() เป็นการนำหมวดหมู่ย่อยใส่ลงไปในอาร์เรย์ sub ของ $data (หมวดหม่หลัก) แต่ละตัว


  foreach($data as $row){
displayCategory($row);
  }

ในส่วนของ <body> จะนำโค้ดด้านบนนี้ไปวางในตำแหน่งที่ต้องการแสดงผลหมวดหมู่ทั้งหมด โดยฟังก์ชั่น displayCategory() จะแสดงผลทั้งหมด

echo '<br/>' . str_repeat("&nbsp;",$sub*4) . '- ' . $data['name'];

ส่วนที่ต้องปรับแต่เพิ่มเติมคือการแสดงผลเมนูให้สวยงามอาจจะจัดรูปแบบด้วยแท็ก <li> หรือหา UI สวยๆจาก Bootstrap snip



[ โค้ด SQL สำหรับสร้างตารางในฐานข้อมูล ]



CREATE TABLE IF NOT EXISTS `tb_category` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `ref_parent_id` int(11) DEFAULT '0' COMMENT 'อ้างอิง id',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8;


INSERT IGNORE INTO `tb_category` (`id`, `name`, `ref_parent_id`) VALUES
(1, 'วัสดุอุปกรณ์สำนักงาน', 0),
(2, 'วัสดุอุุปกรณ์ทำสวน', 0),
(3, 'วัสดุอุปกรณ์ไฟฟ้า', 0),
(4, 'วัสดุุอุปกรณ์ในครัว', 0),
(5, 'กรรไกร', 1),
(6, 'กระดาษ', 1),
(7, 'แม็ก', 1),
(8, 'จอบ', 2),
(9, 'มีดถาง', 2),
(10, 'สายไฟ', 3),
(11, 'กรรไกร 2 นิ้ว', 5),
(12, 'กรรไกร 4 นิ้ว', 5),
(13, 'กรรไกร 5 นิ้ว', 5),
(14, 'กระดาษ A3', 6),
(15, 'กระดาษ A4', 6),
(16, 'แม็กเบอร์ 4', 7),
(17, 'จอบด้ามไม้', 8),
(18, 'จอบด้ามเหล็ก', 8),
(19, 'มีปลายงอ', 9),
(20, 'มีดปลายแหลม', 9),
(21, 'เบอร์ 4/1', 16),
(22, 'เบอร์ 4/2', 16),
(23, 'ธรรมดา', 21),
(24, 'พิเศษ', 21);



แหล่งอ้างอิง

ความสัมพันธ์ของฐานข้อมูล
http://www.tbacud.ac.th/caidb/home/unit11.html

PHP Data Objects
http://php.net/manual/en/book.pdo.php

Bootstrap UI สวยๆ
https://bootsnipp.com/tags


PHP CI MANIA PHP Code Generator 
โปรแกรมช่วยสร้างโค้ด ลดเวลาการเขียนโปรแกรม เขียนโปรแกรมง่ายและสะดวกขึ้น
สนใจสั่งซื้อราคาสุดคุ้ม >> http://fastcoding.phpcodemania.com/