تابع  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بررسی سناریو کاربردیفرض کنید یک جدولی به نام 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, shipcountryFROM CTE_OrderWHERE 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 روش دوم