|
php - หลักการสร้างรายงานยอดที่พนักงานทำได้ในแต่ละเดือน แบบลดจำนวนการคิวรี่ โดยการพักค่าไว้ในอาร์เรย์ก่อนนำมาแสดงผล |
php - หลักการสร้างรายงานยอดที่พนักงานทำได้ในแต่ละเดือน แบบลดจำนวนการคิวรี่ โดยการพักค่าไว้ในอาร์เรย์ก่อนนำมาแสดงผล หลักจากที่ได้ลองจับลองเล่น CodeIgniter ก็เริ่มติดใจตัวช่วยด้านการติดต่อฐานข้อมูล (Database Class) ในส่วนของการคิวรี่ข้อมูลด้วยคลาสที่มีมาให้ (Generating Query Results) จนทำให้ลืมคำสั่ง PHP ไปพักหนึ่ง ^__^ ก็เริ่มมองเห็นรูปแบบการใช้งานอาร์เรย์ให้เกิดประโยชน์มาแนะนำ ให้ลองประยุกต์ใช้กันดูว่าจะช่วยให้ลดภาระให้เซิร์ฟเวอร์ (หรือเพิ่มภาระหนักกว่าเดิม) ได้จริงหรือไม่
เมื่อเราเรียก $this->db->query("YOUR QUERY"); เพียงบรรทัดเดียว เราก็จะได้ข้อมูลทั้งหมดตามเงื่อนไข SQL ที่กำหนดไว้ เห็นมั้ยล่ะว่ามันง่ายขนาดไหน ข้อมูลที่ได้ก็จะถูกส่งกลับมาเก็บไว้ในรูปแบบอาร์เรย์
และเมื่อจะนำอาร์เรย์ที่ได้มาใช้งานก็จะใช้คำสั่ง foreach()
foreach ($query->result_array() as $row)
{
echo $row['title'];
echo $row['name'];
echo $row['body'];
}
พอทำงานกับอาร์เรย์บ่อยๆ เลยเริ่มมีแนวคิดในการลดการคิวรี่ในลูป ที่ทำให้การทำงานช้าอย่างมาก โดยเฉพาะหน้ารายงานที่บางครั้งคิวรี่ครั้งหนึ่งต้องคำนวณหลายร้อยเรคอร์ด ส
สำหรับคำว่าการคิวรี่ภายในลูปในความหมายของผมนั้นเป็นยังไงลองทำความเข้าใจไปพร้อมๆกันที่
มาเข้าเรื่อง การเขียนโค๊ด PHP เพื่อทำรายงานประจำเดือนกันเลยครับ
1. การเขียนแบบตามลำดับขั้น แบบเดิมที่ผมเคยใช้
- วนลูปดึงข้อมูลรายชื่อพนักงานทั้งหมด จากตารางที่เก็บข้อมูลผู้ใช้ทั้งหมด
- สร้างคอลัมน์ แสดงชื่อ และ วันที่ ตามจำนวนวันของเดือนนั้นๆ
- วนลูปดึงข้อมูลของพนักงานทีละคน โดยเริ่มจากวันที่ 1 ถึง วันที่สุดท้ายของเดือน
- แสดงจำนวนยอดที่พนักงานได้ ลงในแต่ละคอลัมน์ ตามวันที่นั้นๆ
2. การเขียนแบบพักข้อมูลไว้ในตัวแปรอาร์เรย์ แบบใหม่ที่อยากจะแนะนำ)
- วนลูปดึงข้อมูลรายชื่อพนักงานขายทั้งหมด
- สร้างคอลัมน์วันที่ ตามจำนวนวันของเดือนนั้นๆ
- เก็บข้อมูลยอดจองของพนักงานแต่ละคน ในแต่ละวัน ไว้ในอาร์เรย์
- วนลูปข้อมูลในอารเรย์ออกมาแสดงในรูปแบบตาราง
มาดูซอร์สโค๊ดตัวอย่างกัน Code (PHP)
<html>
<head>
<title>รายงานประจำเดือน</title>
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
<style>
.number{ text-align : right;}
.number div{
background: #91F7A4;
color : #ff0000;
}
#test_report th{ background-color : #21BBD6; color : #ffffff;}
#test_report{
border-right : 1px solid #eeeeee;
border-bottom : 1px solid #eeeeee;
}
#test_report td,#test_report th{
border-top : 1px solid #eeeeee;
border-left : 1px solid #eeeeee;
padding : 2px;
}
#txt_year{ width : 70px;}
.fail{ color : red;}
</style>
</head>
<body>
<form method="POST" action="<?php echo $_SERVER['PHP_SELF'];?>">
<table>
<tr>
<td>ระบุเดือน-ปี : </td>
<td>
<select name="txt_month">
<option value="">--------------</option>
<?php
$month = array('01' => 'มกราคม', '02' => 'กุมภาพันธ์', '03' => 'มีนาคม', '04' => 'เมษายน',
'05' => 'พฤษภาคม', '06' => 'มิถุนายน', '07' => 'กรกฎาคม', '08' => 'สิงหาคม',
'09' => 'กันยายน ', '10' => 'ตุลาคม', '11' => 'พฤศจิกายน', '12' => 'ธันวาคม');
$txtMonth = isset($_POST['txt_month']) && $_POST['txt_month'] != '' ? $_POST['txt_month'] : date('m');
foreach($month as $i=>$mName) {
$selected = '';
if($txtMonth == $i) $selected = 'selected="selected"';
echo '<option value="'.$i.'" '.$selected.'>'. $mName .'</option>'."\n";
}
?>
</select>
</td>
<td>
<select name="txt_year">
<option value="">--------------</option>
<?php
$txtYear = (isset($_POST['txt_year']) && $_POST['txt_year'] != '') ? $_POST['txt_year'] : date('Y');
$yearStart = date('Y');
$yearEnd = $txtYear-5;
for($year=$yearStart;$year > $yearEnd;$year--){
$selected = '';
if($txtYear == $year) $selected = 'selected="selected"';
echo '<option value="'.$year.'" '.$selected.'>'. ($year+543) .'</option>'."\n";
}
?>
</select>
</td>
<td><input type="submit" value="ค้นหา" /></td>
</tr>
</table>
</form>
<?php
//รับค่าตัวแปรที่ส่งมาจากแบบฟอร์ม HTML
$year = isset($_POST['txt_year']) ? mysql_real_escape_string($_POST['txt_year']) : '';
$month = isset($_POST['txt_month']) ? mysql_real_escape_string($_POST['txt_month']) : '';
if($year == '' || $month == '') exit('<p class="fail">กรุณาระบุ "เดือน-ปี" ที่ต้องการเรียกรายงาน</p>');
//เปิดการเชื่อมต่อฐานข้อมูล sunzandesign
mysql_connect("localhost","root","abcd1234"); //ข้อมูลนี้ได้มาจากตอนติดตั้งเว็บเซิร์ฟเวอร์
mysql_select_db("sunzandesign");
mysql_query("SET NAMES UTF8");
//ดึงข้อมูลพนักงานทั้งหมด
$allEmpData = array();
$strSQL = "SELECT user_code,user_fullname FROM `tb_user` ";
$qry = mysql_query($strSQL) or die('ไม่สามารถเชื่อมต่อฐานข้อมูลได้ Error : '. mysql_error());
while($row = mysql_fetch_assoc($qry)){
$allEmpData[$row['user_code']] = $row['user_fullname'];
}
//เรียกข้อมูลการจองของเดือนที่ต้องการ
$allReportData = array();
$strSQL = "SELECT bk_user_code, DAY(`bk_date`) AS bk_day, COUNT(*) AS numBook FROM `tb_report_booking` ";
$strSQL.= "WHERE `bk_date` LIKE '$year-$month%' ";
$strSQL.= "GROUP by bk_user_code,DAY(`bk_date`)";
$qry = mysql_query($strSQL) or die('ไม่สามารถเชื่อมต่อฐานข้อมูลได้ Error : '. mysql_error());
while($row = mysql_fetch_assoc($qry)){
$allReportData[$row['bk_user_code']][$row['bk_day']] = $row['numBook'];
}
echo "<table border='0' id='test_report' cellpadding='0' cellspacing='0'>";
echo '<tr>';//เปิดแถวใหม่ ตาราง HTML
echo '<th>รายชื่อพนักงาน</th>';
//วันที่สุดท้ายของเดือน
$timeDate = strtotime($year.'-'.$month."-01"); //เปลี่ยนวันที่เป็น timestamp
$lastDay = date("t", $timeDate); //จำนวนวันของเดือน
//สร้างหัวตารางตั้งแต่วันที่ 1 ถึงวันที่สุดท้ายของดือน
for($day=1;$day<=$lastDay;$day++){
echo '<th>' . substr("0".$day, -2) . '</th>';
}
echo "</tr>";
foreach($allEmpData as $empCode=>$empName){
echo '<tr>';//เปิดแถวใหม่ ตาราง HTML
echo '<td>'. $empName .'</td>';
//เรียกข้อมูลการจองของพนักงานแต่ละคน ในเดือนนี้
for($j=1;$j<=$lastDay;$j++){
$numBook = isset($allReportData[$empCode][$j]) ? '<div>'.$allReportData[$empCode][$j].'</div>' : 0;
echo "<td class='number'>", $numBook, "</td>";
}
echo '</tr>';//ปิดแถวตาราง HTML
}
echo "</table>";
mysql_close();//ปิดการเชื่อมต่อฐานข้อมูล
?>
วิเคราะห์โค๊ดแบบที่ 2
- การคิวรี่จะเกิดขึ้นเพียงครั้งเดียว
- ข้อมูลทั้งหมดเก็บไว้ใน $allReportData
- และเรียกใช้งานในลูปโดยเทียบว่ามีข้อมูลตามคีย์ที่เป็นวันที่ตรงกันหรือไม่
เพิ่มเติม
- หากตารางอื่นๆ ที่จำเป็นต้องนำข้อมูลมาแสดงนั้น จะมีจำนวนเรคอร์ดที่เท่ากันเสมอ ให้ใช้คำสั่ง SQL INNER JOIN มาช่วยแทนครับ ไม่ต้องใช้วิธีนี้ เพราะ INNER JOIN ทำงานเร็วอยู่แล้ว
- หากข้อมูลตารางอื่นๆที่ต้องเอามาแสดงมีจำนวนน้อยกว่า หรือขาดบางรายการ ไม่ควรใช้ INNER JOIN ครับเพราะยอดจะขาดหายไปตามจำนวนเรคอร์ดที่ไม่สามารถ JOIN กันได้
- หากเมื่อใดที่ใช้ LEFT JOIN แล้วแสดงผลช้ามากๆ และตารางที่ JOIN มีข้อมูลคงที่ หรือไม่มากเกินไป แนะนำให้ใช้วิธีแยกคิวรี่เก็บไว้ในอาร์เรย์แทนครับ
สรุป
แนวคิดนี้ ยังไม่สามารถยืนยันอย่างเป็นทางการได้ว่า ช่วยทำให้คิวรี่ได้เร็วและประหยัดทรัพยากรได้เต็มประสิทธิภาพ เป็นต้องวิเคราะห์เป็นกรณีไป ว่าตารางอื่นๆที่ต้องดึงข้อมูลมาแสดงนั้นมีข้อมูลมากเพียงใด หรือคงที่พอที่จะดึงมาเก็บไว้ในอาร์เรย์โดยไม่เปลืองหน่วยคำจำเกินไปหรือไม่
แต่เหนือสิ่งอื่นใด รายงานที่ผมเคยนั่งรอนานหลายวินาทีเพราะใช้ LEFT JOIN (ที่ทำ INDEX ฟิลด์ที่ใช้ WHERE ไปแล้ว) เครื่องสเปกต่ำๆ แทบจะค้าง กลับทำงานได้เร็วขึ้นในไม่ถึง 10 วินาที
Reference : http://sunzandesign.blogspot.com/2013/06/php.html
|
|
|
By : |
To Be Developer
|
|
Article : |
บทความเป็นการเขียนโดยสมาชิก หากมีปัญหาเรื่องลิขสิทธิ์ กรุณาแจ้งให้ทาง webmaster ทราบด้วยครับ |
|
Score Rating : |
|
|
Create Date : |
2013-07-18 |
|
Download : |
No files |
|
Sponsored Links |
|
|
|
|
|
|