Monday, September 14th, 2009
วันนี้ผมจะมาพูดถึงฟังก์ชั่นง่ายๆที่มีให้ใช้ใน MySQL กันบ้าง หลังจากที่ไม่ได้เขียน Blog แบบที่มาสาระมานาน วันนี้ขอเขียนหน่อย พอดีเอามาใช้กับเว็บ และ เห็นมีน้องๆและเพื่อนๆหลายๆคนถามผมมาว่า “พี่แม็คขอไอเดียการทำแบบนี้ให้หน่อยสิ” ก็เลยจัดไป
จะว่าไปฟังก์ชั่นที่ผมจะพูดถึงนี้มันก็เป็นฟังก์ชั่นมาตรฐานใน MySQL นี่แหล่ะ แต่บางคนอาจจะไม่เคยทำ แต่ไปใช้การคำนวนในรูปแบบอื่นๆแทน ซึ่งคำสั่งพวกนี้ไปหาอ่านกันได้เพิ่มเติมใน MySQL Manual ได้ครับ
ไอเดียที่มีคนถามผมมาก็คือ
- ไอเดียในการกำหนดวัน เวลา ในการแสดงข่าวสาร
- ไอเดียในการกำหนดวันหมดอายุของแบนเนอร์ต่างๆ
สมัยก่อนตอนที่ผมเขียน PHP แบบมั่วๆในแบบของผมเอง ผมก็มักจะใช้วิธีการคำนวนจากค่า TIMESTAMP แล้วเอาไปบวก ไปลบ ค่าของวินาทีต่างๆ เพื่อให้ได้ผลลัพธ์ตามที่ผมต้องการ แต่เมื่อเริ่มใช้ PHP ไปนานๆเข้าก็ได้เห็นจากใน Manual ของ MySQL ในการใช้คำสั่งในการ Query ข้อมูลเพื่อให้ได้ผลลัพธ์ในแบบที่เราต้องการ ทำให้เขียนโค๊ดได้ไวขึ้น และ แม่นยำมากยิ่งขึ้น
มาดูอันดับแรกเลยก็คือ ฟังก์ชั่นในการหาผลต่างของวันนะครับ ก็เลือกใช้ตัวนี้เลย
DATEDIFF(expr1,expr2)
โดยที่ expr1 ก็คือ ค่าวันเวลาช่วงที่ 1 และ expr2 ก็คือช่วงเวลาที่ 2 เพื่อหาความต่างของเวลา มาลองดูตัวอย่างดีกว่า
SELECT DATEDIFF(’1997-12-31 23:59:59′,’1997-12-30′);
ก็จะได้ผลต่างของเวลาทั้งสองเท่ากับ 1 วัน
SELECT DATEDIFF(’1997-11-30 23:59:59′,’1997-12-31′);
ก็จะได้ผลต่างของเวลาทั้งสองเท่ากับ -31 วันครับ
นำมาประยุกต์กับการใช้งานอะไร?? ก็เอามานับจำนวนวันของข้อมูลได้ เช่น กระทู้นี้ลงประกาศมากี่วันแล้ว

มาดูฟังก์ชั่นต่อไปที่อยู่ในคำถามที่มีคนถามไอเดียเกี่ยวกับว่าจะกำหนดวันที่แสดงข่าว หรือ วันหมดอายุของแบนเนอร์ จริงๆแล้วมันง่ายมากมายนัก เอาให้คนที่ไม่รู้ละกันนะครับ ไม่รู้ไอเดียแต่ละคนจะเหมือนกันไหม แต่ไอเดียผมจะเป็นแบบนี้
- กำหนดฟิลล์ขึ้นมา 1 ฟิลล์ในตารางที่เราต้องการกำหนดให้มีการกำหนดวันแสดงผลข่าว เช่นผมกำหนดชื่อฟิลล์ว่า date_show_content ซึ่งผมจะกำหนดให้เป็น DATETIME นะครับ หรือใครจะกำหนดเป็น DATE เฉยๆก็ไม่ว่ากัน
- เวลา Admin เพิ่มข่าวสาร และจะกำหนดวันที่จะแสดงก็อาจจะทำ Javascript ที่เป็นพวกสคริป DateTime Picker มาเลือกวันและเวลาในการลงประกาศ
ซึ่ง 2 ข้อนี้ก็อาจจะง่ายมากในการทำ ซึ่งผมจะไม่พูดถึง แต่สิ่งที่ผมจะพูดถึงก็คือการกำหนดแบบว่ากำหนดจำนวนวันเข้าไป เช่น เราเพิ่มข้อมูลวันนี้ แต่อยากให้มันแสดงผลในอีก 5 วันข้างหน้า เราจะเขียนแบบใด ซึ่งอาจจะเอาไปประยุกต์กับการกำหนดการหมดอายุของแบนเนอร์ได้ว่าให้แบนเนอร์นี้ลงโฆษณาได้ 7 วัน เป็นต้น
DATE_ADD และ DATE_SUB คำสั่งนี้เคยใช้กันบ้างไหม ?
สองฟังก์ชั่นนี้มีประโยชน์มากๆเลยในการหาวันข้างหน้า และ วันย้อนหลัง โดยลักษณะการเรียกใช้จะเป็นแบบนี้
DATE_ADD(date,INTERVAL expr unit)
DATE_SUB(date,INTERVAL expr unit)
DATE_ADD ชื่อก็บอกแล้วว่า ADD นั่นก็คือเอาเพิ่มวันแน่นอน มาดูกันว่าเป็นอย่างไร
SELECT DATE_ADD(’1997-12-31 23:59:59′,INTERVAL 1 SECOND);
ก็จะได้ 1998-01-01 00:00:00
SELECT DATE_ADD(’1997-12-31 23:59:59′,INTERVAL 1 DAY);
ก็จะได้ผลของการเพิ่มวันไป 1 วัน คือ 1998-01-01 23:59:59
DATE_SUB ก็ตรงกันข้ามครับ ก็คือหาวันย้อนหลัง
SELECT DATE_SUB(’1998-01-01 00:00:00′,INTERVAL ‘1 1:1:1′ DAY_SECOND);
ก็คือการหาวันเวลาย้อนหลัง 1 วัน 1 ชั่วโมง 1 นาที 1 วินาที ก็จะได้ผลคือ 1997-12-30 22:58:59
แนวทางในการใช้ของผมก็คือ ผมเอาไปใช้กับระบบสมาชิก VIP ในเว็บผมโดยผู้ลงโฆษณาสามารถเลือกจำนวนวันลงประกาศได้ ว่าจะลงโฆษณากี่วัน แล้วเมื่อครบวันที่กำหนดระบบก็จะไม่แสดงผลรายการโฆษณานั้นๆ ได้ตรงเวลาเปะๆครับ ลองเล่นดูนะครับ ของแบบนี้มันต้องลองเล่นดูครับ ถึงจะเข้าใจนะครับ ขอให้มีความสุขกับการเขียนโปรแกรมครับ

Posted in PHP, ความรู้ | 1 Comment »
Thursday, May 15th, 2008
หลายๆคนชอบถามผมว่าทำไมผมเขียนโค๊ดผมไม่ชอบเขียนโค๊ดติดต่อดาต้าเบส แบบเทพๆ ผมก็มาคิดในใจ
เทพยังไงว่ะ!!!
ก็เขียนแบบ JOIN TABLE อะไรแบบนี้ ทำไมผมต้องมาเขียน Select ตั้ง 2 รอบ อะไรแบบนี้ มีคนถามผมว่าทำไมผมไม่เขียนแบบนี้
$result = mysql_query(”SELECT * FROM orders_to_item LEFT JOIN items ON orders_to_item.item_id=items.item_id WHERE orders_to_item.order_id = ‘”.$_GET[’order_id’].”‘ “);
พี่เขียนไม่เป็นใช่ม๊า ???? (มีคนถามผม)
ไอ้เขียนหน่ะเขียนเป็น แต่ไม่ใช้ (กรูไม่ใช้ใครจะทำไม)
แต่ที่ไม่ใช้มันก็มีเหตุผลของมัน อาจจะเพราะว่าผมไม่ได้เดินมากะสายคอมโดยตรง ที่นั่งเรียนทฤษฏีดาต้าเบส จากรั้วมหาวิทยาลัย ที่วันๆอาจารย์ก็สอนเรื่องเดิมๆก็พวกการออกแบบดาต้าเบส การติดต่อดาต้าเบส การ JOIN TABLE อะไรพวกนี้ ซึ่งจะว่ากันจริงๆ
อาจารย์ส่วนมากไม่ได้มาจับกับ Database ใหญ่ๆกันหรอก โดยมากก็สอนให้รู้ถึงทฤษฏี และ บอกข้อดีก็เท่านั้น ซึ่งคนที่เรียนๆมาก็คงได้ยินอาจารย์พูดว่า
“การ JOIN ทำให้เราเขียนโค๊ดคิวรี่ข้อมูลได้สั้นขึ้น ไวขึ้น ง่ายขึ้น”
ก็ถูกอย่างที่อาจารย์พูดนะ เขียนโค๊ดสั้นๆ ง่ายขึ้น จริงๆว่ะ
แต่บังเอิญว่าผมเดินมาคนละสายกัน ผมวุ่นกับเรื่องการแก้ไขดาต้าเบสบ่อยมากๆ มากซะจนผมคืดว่าการเอาข้อมูลมาแสดงผลจากดาต้าเบสยังไงให้เอามาได้ไวที่สุด และ ส่งผลกระทบกับ Server ให้น้อยที่สุด และผมก็พบทางสว่าง(มานานแล้ว)
หากคนเรียนดาต้าเบสแล้วทำพวก JOIN ไรเก่งๆก็คงได้ A ไปตามๆกัน แต่หากมาทำให้ประสิทธิภาพโดยรวมของระบบนั้นท่านคงได้ C D กันเป็นแถวๆ
ผมเคยทำมาหมดครับพวก JOIN เนี่ย มันเป็นทฤษฏีที่น่าสนใจ แต่ไม่น่านำมาใช้เลยให้ตาย เพราะผมลองจับ Process มาหมดครับ ยังไงการ คิวรี่ข้อมูลสองครั้ง สามครั้ง ก็ไวกว่าการ JOIN TABLE ครับ ยืนยัน และ ฟันธง
อ้างจากคำพูดนายเปิ้ล Apsserv ที่เคยพูดกะผมนานแล้วว่า
“ดาต้าเบสมีไว้เก็บข้อมูล ไม่ได้มีไว้เอามาคำนวน ทำไงก็ได้ให้ดึงออกมาแสดงให้ไวที่สุดก็พอ”
และปัญหาจากเร่องการ JOIN ก็เกิดขึ้น กับ Server จนได้ เมื่อนายเปิ้ลมาคุยกับผมว่า
apples : AppServ 2.6.0 เลือก…สิ่งใหม่…ให้ชีวิตที่ไม่หยุดนิ่ง says:
หิหิ
apples : AppServ 2.6.0 เลือก…สิ่งใหม่…ให้ชีวิตที่ไม่หยุดนิ่ง says:
เจออีกแล้ว
apples : AppServ 2.6.0 เลือก…สิ่งใหม่…ให้ชีวิตที่ไม่หยุดนิ่ง says:
JOIN นรก
ได้เห็นคำพูดก็รู้เลยว่าเรื่องอะไร แล้วก็ดู Stats ของ Server ทันที ผลเป็นแบบนี้

พอดีลูกค้าออกแบบระบบเว็บใหม่ นี่คือผลแค่ 1 เว็บเท่านั้นนะ เว็บเขาออกแบบระบบใหม่ให้ JOIN TABLE ผลที่ได้ดูครับ Traffic เท่าเดิม แต่ลองดูที่ CPU LOAD กับ SERVER LOAD ดูสิครับ พุ่งขึ้นทันตา
เห็นไหมหล่ะครับ คำว่าเขียนโค๊ดติดต่อ Database แบบเทพๆ สุดท้ายเมื่อเขียนโค๊ดแบบนี้ ก็ต้องอาศัยของเทพๆอีกเช่นกันก็คือ
Server แบบเทพๆ
ซึ่งก็ต้องแลกมาด้วย ราคาขั้นเทพอีกด้วย 5555
ผมไม่ได้รู้เรื่องสถาปัตยกรรมคอมมากนักหรอก แต่สิ่งที่นายเปิ้ลเคยบอกผมไว้ว่า
“การ Select ในแบบปกติระบบจะทำงานบน เมมโมรี่ แต่หาก JOIN เมื่อไหร่ มันจะไปทำงานบนฮาร์ดดิสก์แทน สมัยก่อนแรมอาจจะน้อยคนเลยหันไปทำงานบนฮาร์ดดิสก์ แต่ปัจจุบัน Server มีแรมในระดับ GB ทั้งนั้น ดังนั้นลองมาคิดดูว่า เมมโมรี่ เทียบกับฮาร์ดดิสก์ที่ทำงานในระดับไม่กี่พัน หรือ หมื่น rpm จะทำงานเร็วได้เท่าเมมโมรี่ได้ เพราะการอ่านบนฮาร์ดดิสก์ ไหนจะอ่านไฟล์เว็บ ไหนจะอ่านนู่นๆนี่ๆอีก”
เว็บ Mocyc.com ผมเมื่อก่อน(5-6 ปีก่อน)คนเข้าน้อยกว่านี้ แต่ทำไม Server แทบรับไม่ได้ พอมาเขียนระบบการใช้งาน Database ใหม่ ตอนนี้คนเข้าเยอะกว่าตอนนั้น 3-4 เท่า แต่ Server ทำงานเบาลงกว่าเดิมมาก
บางครั้งทฤษฏีที่ร่ำเรียนมา มันก็สู้ประสบการณ์ไม่ได้ สู้ๆๆๆ
วันนี้มาเพิ่มซะหน่อย ลองดูผลหลังจากเอา JOIN ออก ดีนะที่เจ้าของเว็บเชื่อ และ แก้ไขโค๊ดให้ โดยเปลี่ยนการคิวรี่ข้อมูล ไม่ใช้ JOIN ผลออกมาแบบนี้ครับ

ดูกราฟเทียบกันสิครับ
หากเป็นเว็บไซต์ใหญ่ๆหล่ะ คนเข้าวันนึงเป็นหลายหมื่น หรือ เป็นแสน ผลกระทบย่อมมากตาม สุดท้ายก็มีแค่คำแก้ตัวคำเดียวว่า “Server รับไม่ไหว” เหอๆๆๆ
Posted in PHP, ความรู้ | 4 Comments »
Wednesday, May 7th, 2008
เหอๆๆ ชื่อหัวข้อ งงๆ ป่าว ผมอ่านผมก็ยัง งงๆ เลยครับ แต่เอาเป็นว่าคุณๆที่เคยเขียนโปรแกรมที่ต้องมีการนำเอาค่า id ของตารางไปใช้งานต่อไป และค่า id ที่จะเอาไปนั้นเองในดาต้าเบสก็ดันเป็นข้อมูลแบบ ‘Auto_increment’ หรือ รันขึ้นไปเรื่อยๆอัตโนมัติอีกหล่ะทำไง
นี่ไงๆ เขียนแบบนี้เลย
$result = mysql_query(”SELECT MAX(order_id) AS now_id FROM orders “);
$row = mysql_fetch_assoc($result);
echo $row[’now_id’]+1;
หรือ
$result = mysql_query(”SELECT MAX(order_id)+1 AS next_id FROM orders “);
$row = mysql_fetch_assoc($result);
echo $row[’next_id’];
ก็ได้ค่าของ id ลำดับต่อไปแล้ว
ง่ายดีไหมครับ…….
แต่……มันไม่ใช่แค่นั้นนะสิ
สมมุติละกันว่า ตอนนี้ มีแถวอยู่แบบนี้ โดยที่ข้อมูลยังครบถ้วน id เป็นฟิลล์แบบ Auto_increment
+—-+————+————+
| id | txt | date |
+—-+————+————+
| 1 | wqwmo | 0211041039 |
| 2 | mote | 0210120016 |
| 3 | phpbuilder | 0211161642 |
| 4 | txt1 | 0211181109 |
| 5 | txt2 | 0211181109 |
+—-+————+————+
หากเราใช้คำสั่ง mysql_query(”SELECT MAX(order_id) AS now_id FROM orders “);
ค่า now_id จะต้องเท่ากับ 5 ใช่หรือไม่ ?
ถูกต้องนะครับ…
แต่หากว่าเกิดเราลบ id ที่ 5 ไปหล่ะ มันก็จะเหลือข้อมูลแบบนี้
+—-+————+————+
| id | txt | date |
+—-+————+————+
| 1 | wqwmo | 0211041039 |
| 2 | mote | 0210120016 |
| 3 | phpbuilder | 0211161642 |
| 4 | txt1 | 0211181109 |
+—-+————+————+
และเมื่อเราใช้คำสั่ง mysql_query(”SELECT MAX(order_id) AS now_id FROM orders “);
ค่า now_id จะต้องเท่ากับ 4 ใช่หรือไม่ ?
ก็ถูกต้องนะครับ…
แต่จริงๆแล้ว id ที่จะถูกใช้งานเมื่อถูก insert ครั้งต่อไปมันคือ 6 ครับ
อ่าว เวร แล้วสิ งี้ทำไงดี
บางคนอาจจะใช้วิธี insert ข้อมูลเข้าไปก่อน แล้วค่อยใช้วิธี query ออกมาอีกครั้งหนึ่ง เพ่ือเอาค่า id ล่าสุดไปใช้งานต่อไป
สำหรับคนที่เคยทำแล้วอาจจะบอก ง่ายจริงๆ แต่หลายๆคนที่ไม่เคยใช้งาน ก็ลองเอาไปใช้งานนะ
$q = mysql_query(”show table status from DATABASE_NAME like ‘TABLE_NAME’ “) or die(mysql_error());
echo mysql_result($q, 0, ‘Auto_increment’);
รับรองคราวนี้ได้ค่า id ต่อไปของข้อมูลแบบ Auto_increment ที่ถูกต้องและแน่นอน
วิธีนี้เหมาะกับการต้อวงการทราบค่า id ต่อไป เหมือนที่แสดงใน phpmyadmin ที่บอกว่า
ต่อไป Autoindex 4
ประมาณนี้ครับ
Posted in PHP, ความรู้ | 4 Comments »