|  
  
     
      |  
         
           
            |  | 
 
  php - หลักการสร้างรายงานยอดที่พนักงานทำได้ในแต่ละเดือน แบบลดจำนวนการคิวรี่ โดยการพักค่าไว้ในอาร์เรย์ก่อนนำมาแสดงผล หลักจากที่ได้ลองจับลองเล่น CodeIgniter ก็เริ่มติดใจตัวช่วยด้านการติดต่อฐานข้อมูล (Database Class) ในส่วนของการคิวรี่ข้อมูลด้วยคลาสที่มีมาให้ (Generating Query Results) จนทำให้ลืมคำสั่ง PHP ไปพักหนึ่ง ^__^ ก็เริ่มมองเห็นรูปแบบการใช้งานอาร์เรย์ให้เกิดประโยชน์มาแนะนำ ให้ลองประยุกต์ใช้กันดูว่าจะช่วยให้ลดภาระให้เซิร์ฟเวอร์ (หรือเพิ่มภาระหนักกว่าเดิม) ได้จริงหรือไม่ 
    |  
        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 |  |  |  |   |