Posted by: siamnobita | 12/29/2009

Function to count weekend

ช่วงนี้ไม่ค่อยมีเวลามาเขียนหัวข้อใหม่ ๆ เท่าไหร่ ต้องขออภัยคนอ่านเป็นอย่างยิ่งครับ

หัวข้อวันนี้บังเอิญไปเจอคำถามในเว็บ narisa ที่น่าสนใจข้อหนึ่ง ต้องการนับวันหยุดที่อยู่ภายในช่วงวันที่ที่กำหนด โดยเจ้าของกระทู้สนใจนับเฉพาะเสาร์-อาทิตย์เท่านั้น

ในกรณีทั่ว ๆ ไปแล้ว หากโจทย์ต้องการนับวันหยุด ผมจะสร้างตารางเก็บวันหยุดทั้งหมดขึ้นมา แล้วก็ใช้ count ธรรมดา ก็เพียงพอ แถมรองรับกรณีวันหยุดตามประเพณีต่าง ๆ ได้ด้วย แต่อาจต้องการการ maintenance ตารางในแต่ละปีบ้าง

อย่างไรก็ดี วันนี้ผมนึกสนุกอยากลองดูว่า ถ้าจะเขียน sql ใช้ built-in function ล้วน ๆ เพื่อตอบโจทย์การนับวันหยุดเสาร์ อาทิตย์นี้จะทำได้ไหม ผลปรากฏเป็น sql นี้ครับ

create table weekend_count
( d1  date
, d2  date
) ;
select d1, d2
  , greatest((next_day(d1,7)-d1)-5,0)
  + ((next_day(d2,7)-7)-next_day(d1,7))/7*2
  + least ((d2+1) – (next_day(d2,7)-7),2)
from weekend_count
/

หลักการคือ หาวันเสาร์แรก และ เสาร์สุดท้ายในช่วงมาโดยใช้ฟังก์ชั่น next_day(d1,7) และ next_day(d2,7)-7

นับ weekend ช่วงที่หนึ่งคือ ตั้งแต่วันแรกจนถึงวันเสาร์แรก จะมีเสาร์อาทิตย์เท่ากับจำนวนวันที่เกิน 5 วัน
นับ weekend ช่วงที่สองคือ ตั้งแต่วันเสาร์แรกจนถึงวันเสาร์สุดท้าย จะมีเสาร์อาทิตย์เท่ากับจำนวนวันหารเจ็ดคูณสอง
นับ weekend ช่วงที่สามคือ ตั้งแต่วันเสาร์สุดท้ายจนถึงวันสุดท้าย จะมีเสาร์อาทิตย์เท่ากับจำนวนวัน แต่ไม่เกินสอง

จริง ๆ logic นี้ อาจมีจุดอ่อนในกรณีที่ ช่วงวันที่ยาวไม่พอที่จะแบ่งเป็นสามช่วงได้ แต่เท่าที่ทดสอบดูหลาย ๆ เคส พบว่าจำนวนวันจากช่วงที่สองจะติดลบ และชดเชยกันจนได้ผลลัพธ์ที่ถูกต้องอยู่ดี ถ้าใครลองทดสอบดูแล้วเจอเคส ที่ใช้ไม่ได้ รบกวนแจ้งด้วยก็จะเป็นพระคุณยิ่งครับ

ก่อนจบหัวข้อ ขอกลับมาที่เฉลยที่อยู่ในเว็บนั้นอีกนิด จริง ๆ แล้วเจ้าของกระทู้ต้องการคำนวณช่วงวันที่ที่ user กรอกเข้ามาผ่าน forms ดังนั้นหากคำนวณด้วย pl/sql ล้วน ๆ น่าจะเหมาะสมกว่า การใช้ sql ที่ผมแสดงให้ดู แต่อาจสามารถปรับเอา logic ไปประยุกต์ใช้ได้ ซึ่งจะตัดเรื่องการวนลูปออกไป เหลือแต่การคำนวณล้วน ๆ ซึ่งเร็วกว่า

การใช้ sql แบบนี้นั้น จะเหมาะในกรณีที่เราเก็บช่วงวันที่อยู่ในตาราง และมีจำนวนหลาย ๆ ช่วง ต้องการ select และคำนวณไปพร้อม ๆ กันเลย ซึ่งการใช้ built-in function ก็จะเร็วกว่า การเขียน user-defined function ตามที่เคยแสดงให้ดูในครั้งก่อนแล้ว

สุขสันต์ปีใหม่นะครับ


Responses

  1. ในกรณีทั่ว ๆ ไปแล้ว หากโจทย์ต้องการนับวันหยุด ผมจะสร้างตารางเก็บวันหยุดทั้งหมดขึ้นมา แล้วก็ใช้ count ธรรมดา ก็เพียงพอ แถมรองรับกรณีวันหยุดตามประเพณีต่าง ๆ ได้ด้วย แต่อาจต้องการการ maintenance ตารางในแต่ละปีบ้าง

    จากข้อความข้างต้น รบกวนคุณ siamnobita ยกตัวอย่างให้ดูได้ไหมค่ะ … programmer มือใหม่ค่ะ เมตตาแนะนำด้วยค่ะ

    • create table holidays
      ( holiday_date date primary key
      , holiday_name varchar2(30)
      , weekend_flag varchar2(1)
      , government_flag varchar2(1)
      , bank_flag varchar2(1)
      , company_flag varchar2(1)
      )
      สร้างตารางประมาณนี้ครับ
      แล้วอยากนับวันหยุดแบบไหน ก็ select count(*) from holidays where …
      แต่ตารางนี้ ก็ต้องมีคนมาคอย insert ข้อมูลวันหยุดตามประเพณี


ใส่ความเห็น

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / เปลี่ยนแปลง )

Twitter picture

You are commenting using your Twitter account. Log Out / เปลี่ยนแปลง )

Facebook photo

You are commenting using your Facebook account. Log Out / เปลี่ยนแปลง )

Google+ photo

You are commenting using your Google+ account. Log Out / เปลี่ยนแปลง )

Connecting to %s

หมวดหมู่

%d bloggers like this: