علیرضا حیدری
علیرضا حیدری
خواندن ۴ دقیقه·۳ سال پیش

تابع EOMONTH

مقدمه

بعضی اوقات وقتی ما میخواهیم کوئری هایی در ارتباط با تاریخ در دیتابیس ها بنویسیم ممکن است با یکسری مشکلات مرسوم روبرو شویم در واقع اگر به این موضوع کمی دقت کنیم متوجه میشویم که این ها مشکلات نیستند بلکه نکاتی را در این خصوص رعایت نکرده ایم. تابع EOMONTH هم یکی دیگر از این مواردی است که باید در استفاده از آن دقت کنیم. در این مقاله سعی بر آن شده است که به بررسی تابع EOMONTH و نحوه استفاده از آن در SQL Server بپردازیم و در آخر یک سناریو کاربردی را مطرح کنیم.



تابع EOMONTH

اگر بخواهیم این تابع را بصورت ساده تعریف کنیم میتوان گفت: به ازای یک تاریخ خاص , آخرین روز ماه را بر میگرداند. به syntax زیر توجه فرمایید.

EOMONTH(start_date [, offset] );

تابع EOMONTH دو ورودی میگیرد:

  • ورودی اول (start_date) شامل یک تاریخ میباشد و تابع EOMONTH موظف است آخرین روز ماه ذکر شده در این تابع را برگرداند
  • ورودی دوم شامل یک offset میباشد که اصطلاحا با یک square brackets نشان داده شده است (این [ ] علامت حکایت از اختیاری بودن آن دارد). offset یک عدد صحیح میباشد که به ماه تاریخ مورد نظر در ورودی اول تابع (start_date) اضافه یا کم میکند.

مثال هایی از تابع EOMONTH:

فرض کنید میخواهیم آخرین روز از ماه را در تاریخ 10-02-2020 را بدست آوریم

SELECT EOMONTH('2020-02-10') AS End_Of_Month

با توجه به دستور بالا خروجی بصورت زیر میباشد.

حال فرض کنید این بار شما تصمیم گرفتید آخرین روز ماه را در همان تاریخ ولی در سال 2021 یعنی 10-02-2021 را بدست آورید.

SELECT EOMONTH('2021-02-10') AS End_Of_Month

خروجی دستور بالا بصورت زیر میباشد.


اگر به خروجی دو دستور بالا نگاه کنید متوجه میشوید که دو جواب متفاوت است و این تفاوت فقط با تغییر سال بوجود آمده است. اما چرا؟ اگر به جدول زیر با دقت نگاه کنید متوجه میشوید که تعداد روز ها در ماه های مختلف و یا بعضا در سال ها مختلف متفاوت است به عنوان مثال ژانویه (January) دارای 31 روز می باشد اما فوریه (February) در سال 2020 , 29 روز است ولی در سال 2021 , 28 روز است که به اضای هر 4 سال متفاوت است


جدول 1-1
جدول 1-1

بررسی سناریو کاربردی

فرض کنید یک جدولی به نام Orders وجود دارد این جدول شامل سفارشات هر مشتری - کارمند و تاریخ درج یک سفارش در این جدول میباشد. به ما گفته شده است که آخرین سفارش موجود که در آخرین روز از هر ماه است را بدست آوریم

روش اول استفاده از تابع EOMONTH

همانطور که ذکر شد این تابع آخرین روز از ماه را به ازای تاریخ مربوطه برمیگرداند

SELECT * FROM Orders
WHERE orderdate = EOMONTH(orderdate)

همانطور که میبینید به ازای هر تاریخ آخرین روز را محاسبه میکند. توجه داشته باشد که اگر یک مشتری در یک تاریخ خاص دو عدد سفارش داشته باشد تابع EOMONTH هر دوی آن را بر میگرداند


روش دوم استفاده از Ranking Function است. ما به این دلیل از() DENSE_RANK استفاده کرده ایم که اگر یک مشتری در یک تاریخ خاص دو عدد سفارش داشته باشد هر دوی آن را در خروجی نشان دهد

;WITH CTE_Order AS
(
SELECT *,
DENSE_RANK()OVER(PARTITION BY YEAR(orderdate), MONTH(orderdate)
ORDER BY DAY(orderdate) DESC) AS rw
FROM Orders
)
SELECT
orderid, custid, empid, orderdate, shipcountry
FROM CTE_Order
WHERE rw = 1

خروجی دستور بالا بصورت زیر است

هر دو این دستور آخرین روز از هر ماه را بر میگرداند اما تعداد خروجی ها متفاوت است همانطور که میبینید EOMONTH خروجی 26 رکورد و روش دوم خروجی 42 رکورد دارد .

نکته بسیار مهمی که شما باید به آن توجه ویژه کنید این است که EOMONTH آخرین روز از جدول 1-1 که در بالا توضیح داده شده است را بر میگرداند اگر این روز در Table شما (Orders) باشد در خروجی نشان میدهد اگر نباشد صرف نظر میکند ولی روش دوم آخرین روز از تاریخ موجود که در Table میباشد را بر میگرداند به عبارت دیگر اگر شما در تاریخ 25-01-2021 سفارشی در جدول خود درج کرده باشید تابع EOMONTH آن را بر نمیگرداند چون تابع EOMONTH آخرین روز یعنی 31 را میشناسد و کاری ندارد که شما آخرین روز درج سفارشتان در آن تاریخ 25 است اما روش دوم میگوید من آخرین تاریخی که در جدول سفارشات وجود دارد بر میگردانم به شرطی که بزرگترین باشد. همانطور که میبینید در روش اول خبری از ماه 8 نیست چون آخرین درج سفارشش 30 ام بوده ولی جدول 1-1 برای ماه 8, 31 روز را نشان میدهد پس شامل خروجی نمیباشد ولی روش دوم میگوید بزرگترین روز در ماه 8 , 30 است پس در خروجی می آید.

به عنوان مثال تکمیلی فرض کنید ما یک رکورد در تاریخ 26-09-2013 در جدول Orders درج میکنیم

INSERT INTO Orders(custid,empid,orderdate,shipcountry)
VALUES(10,3,'2013-09-26','Iran')

خروجی روش اول باز هم 26 رکورد می باشد چون آخرین روز ماه 9, 30 روز است ولی آخرین روزی که ما در ماه 9 درج کردیم 26 است پس در خروجی ظاهر نمیشود . خروجی روش دوم این دفعه 43 رکورد میشود چون تاریخ جدید درج شده است .

روش اول EOMONTH
روش اول EOMONTH


 روش دوم
روش دوم








sql server
SQL Server Database Administration, Programmer
شاید از این پست‌ها خوشتان بیاید