นานๆ ต้องมาเขียนโค้ดเองเสียที ก็ชักขึ้นสนิมเหมือนกัน เช้านี้เริ่มต้นด้วยโจทย์ที่ว่าต้องการเขียน 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 เจ้าของโค้ดหน่อยก็ดีนะครับ เค้าจะได้มีกำลังใจ