March 27th, 2008เขียนฟังก์ชันหาจำนวนสัปดาห์ภายในเดือนด้วย PL/SQL
นานๆ ต้องมาเขียนโค้ดเองเสียที ก็ชักขึ้นสนิมเหมือนกัน เช้านี้เริ่มต้นด้วยโจทย์ที่ว่าต้องการเขียน function บน Oracle PL/SQL ที่รับข้อมูลเป็นวันที่ แล้วส่งค่ากลับมาเป็นจำนวนสัปดาห์ในเดือนที่วันที่นั้นอยู่ ดูตัวอย่างดีกว่า
จากปฏิทินที่ว่านี้ สมมติว่าเรากำหนดให้วันเริ่มต้นของสัปดาห์เป็นวันอาทิตย์ หมายถึงว่าหนึ่งสัปดาห์มีตั้งแต่วันเสาร์จนถึงวันอาทิตย์ เพราะฉะนั้น วันนี้ (27 มีนา) ก็จะเป็นวันที่อยู่ในสัปดาห์ที่ 5 ของเดือนมีนาคม
วิธี นับ week แบบนี้มีให้เห็นอยู่เหมือนกัน แต่ที่ควรระวังก็คือ บางทีมันก็ทำให้เำกิดสัปดาห์ที่ 6 ของเดือนได้เหมือนกัน อย่างเดือนนี้ ตามนิยามข้างต้น วันที่ 30 กับ 31 จะตกอยู่ในสัปดาห์ที่ 6
ดังนั้นฟังก์ชันนี้ควรจะทำงานดังนี้
- ใส่ค่าวันที่ 27 มีนา ส่งค่าคืนเป็น 5
- ใส่ค่าวันที่ 31 มีนา ส่งค่าคืนเป็น 6
- ใส่ค่าวันที่ 1 มีนา คืนค่าเป็น 1
ตอน แรกก็กะจะเขียนเอง แต่พอลองร่างคร่าวๆ สงสัยต้องเขียนเป็น loop แฮะ อย่ากระนั้นเลย มันน่าจะมีใครซักคนเคยเขียนฟังก์แบบนี้ออกมาแล้วแน่ๆ ก็เลยค้น google ด้วยคำว่า plsql counting number of weeks ก็เลยมาเจอบทความชิ้นนี้ SQL: Find the Week Number in a Month ผมยกโค้ดของเขามาอธิบายเลยก็แล้วกันนะครับ เพราะเข้าใจได้ไม่ยากเลย
เริ่ม แรกก็หาวันเริ่มต้นของเดือนก่อน โดยใช้ฟังก์ชัน trunc ซึ่งจะปัดเศษวันและเวลาตามพารามิเตอร์ที่ใส่เข้าไป ‘MM’ นี่หมายถึงปัดเศษเป็นเดือนนะครับ
SQL> select trunc(sysdate, 'MM') from dual;
TRUNC(SYS
———
01-FEB-06
แล้ว ก็ใช้ฟังก์ชัน NEXT_DAY เพื่อหาวันในสัปดาห์ถัดไป ฟังก์ชันนี้จะรับพารามิเตอร์ตัวที่สองเป็น วันของสัปดาห์ เช่น Sunday เพราะฉะนั้น select next_day(trunc(sysdate, 'MM'), 'Sunday') from dual ก็จะให้ค่าเป็น วันอาทิตย์แรกของเดือน พอนับย้อนหลังไปเจ็ดวัน ก็จะได้วันเริ่มต้นสัปดาห์แรกของเดือน
SQL > select next_day(trunc(sysdate, 'MM') - 7, 'Sunday') from dual;
NEXT_DAY(
———
29-JAN-06
จาำก จุดนี้เราก็สามารถหาได้แล้วว่าวันที่ปัจจุบัน ห่างจากวันเริ่มต้นของสัปดาห์แรกของเดือนเป็นจำนวนกี่วัน และคิดเป็นกี่สัปดาห์ได้ด้วยกันหาร 7 ปัดเศษทิ้งแล้วบวกด้วย 1 เพื่อให้เริ่มนับสัปดาห์แรกเป็นสัปดาห์ที่ 1
SQL> select sysdate - next_day(trunc(sysdate, 'MM') - 7, 'Sunday') from dual;
SYSDATE-NEXT_DAY(TRUNC(SYSDATE,’MM’)-7,’SUNDAY’)
————————————————
3.55945602
SQL> select (sysdate - next_day(trunc(sysdate, ‘MM’) - 7, ‘Sunday’))/7 from dual;
(SYSDATE-NEXT_DAY(TRUNC(SYSDATE,’MM’)-7,’SUNDAY’))/7
—————————————————-
.508627646
SQL> select trunc(((sysdate - next_day(trunc(sysdate, ‘MM’) - 7, ‘Sunday’))/7),0) + 1
from dual;
TRUNC(((SYSDATE-NEXT_DAY(TRUNC(SYSDATE,’MM’)-7,’SUNDAY’))/7),0)+1
—————————————————————–
1
ถัด จากนี้ก็เอา logic ที่ว่านี่แหละ มาเขียนเป็นฟังก์ชัน โดยกำหนด default parameter และกำหนดให้สามารถเปลี่ยนวันเริ่มต้นของสัปดาห์ได้ด้วย
CREATE OR REPLACE FUNCTION week_in_month
(check_date DATE DEFAULT sysdate, week_start CHAR DEFAULT ‘Sunday’)
RETURN number
IS
week_number NUMBER;
BEGIN
select trunc(((check_date - next_day(trunc(check_date, ‘MM’) - 7, week_start))/7),0) + 1 into week_number from dual;
RETURN week_number;
END;
/
ลองเอาไปใช้ดูนะครับ ถ้าใช้แล้วถูกใจยังไง ตามไป comment ขอบคุณคุณ Jon เจ้าของโค้ดหน่อยก็ดีนะครับ เค้าจะได้มีกำลังใจ