آموزش تابع DATEADD در SQL Server برای محاسبات تاریخ و زمان
آموزش تابع DATEADD در SQL Server برای محاسبات تاریخ و زمان
مقدمه
DATEADD یکی از پرکاربردترین توابع تاریخ و زمان در SQL Server است. این تابع یک بازه مانند روز، ماه، سال، ساعت یا دقیقه را به یک مقدار تاریخ اضافه میکند. اگر عدد بازه منفی باشد، همان مقدار از تاریخ کم میشود. DATEADD در محاسبه تاریخ سررسید، زمان انقضای اشتراک، گزارش بازههای زمانی، محاسبه مهلت تحویل و تولید تقویم کاربرد دارد.
کار با تاریخ تنها اضافه کردن چند روز نیست. باید نوع داده، مرز ماهها، سال کبیسه، منطقه زمانی و نحوه نوشتن شرطهای قابل استفاده توسط ایندکس را نیز در نظر گرفت. در این آموزش مثالها بر اساس SQL Server نوشته شدهاند.
تعریف و نحو DATEADD
DATEADD ( datepart, number, date )
پارامترها
- datepart: واحد زمانی مانند year، quarter، month، day، hour، minute یا second.
- number: تعداد واحدی که باید اضافه یا کم شود. مقدار منفی باعث کاهش میشود.
- date: تاریخ مبنا که میتواند ستون، متغیر یا عبارت تاریخ باشد.
نوع خروجی
نوع خروجی معمولاً بر اساس نوع آرگومان date تعیین میشود. برای دقت بیشتر میتوان از datetime2 استفاده کرد. اگر نتیجه از محدوده نوع داده خارج شود، SQL Server خطای Overflow تولید میکند.
مثالهای پایه
DECLARE @BaseDate date = '2026-07-17';
SELECT
DATEADD(day, 10, @BaseDate) AS TenDaysLater,
DATEADD(month, 1, @BaseDate) AS OneMonthLater,
DATEADD(year, -1, @BaseDate) AS OneYearEarlier;
| عبارت | نتیجه |
| ده روز بعد | 2026-07-27 |
| یک ماه بعد | 2026-08-17 |
| یک سال قبل | 2025-07-17 |
رفتار در انتهای ماه
SELECT
DATEADD(month, 1, CAST('2026-01-31' AS date)) AS ResultDate;
چون ماه فوریه روز سیویکم ندارد، SQL Server تاریخ معتبر انتهای ماه را برمیگرداند. هنگام طراحی اقساط ماهانه یا اشتراکها، این رفتار باید با قوانین کسبوکار مقایسه شود. گاهی لازم است EOMONTH نیز در کنار DATEADD استفاده شود.
SELECT EOMONTH(DATEADD(month, 1, CAST('2026-01-15' AS date))) AS NextMonthEnd;
محاسبه تاریخ سررسید سفارش
SELECT
OrderID,
OrderDate,
DeliveryDays,
DATEADD(day, DeliveryDays, OrderDate) AS DueDate
FROM dbo.SalesOrders;
در این مثال تعداد روز تحویل برای هر سفارش میتواند متفاوت باشد. DATEADD ستون عددی را به تاریخ سفارش اضافه میکند و سررسید هر ردیف را محاسبه مینماید.
فیلتر کردن رکوردهای سی روز اخیر
DECLARE @Now datetime2 = SYSDATETIME();
SELECT
NewsID,
NewsTitle,
PublishedDate
FROM dbo.tblNewsContent
WHERE PublishedDate >= DATEADD(day, -30, @Now)
AND PublishedDate < @Now;
در این الگو تابع روی مقدار ثابت یا متغیر اجرا شده است، نه روی ستون PublishedDate. بنابراین SQL Server شانس بیشتری برای استفاده از ایندکس روی PublishedDate دارد.
الگوی نامناسب
WHERE DATEDIFF(day, PublishedDate, @Now) <= 30
این شرط تابع را روی ستون اجرا میکند و ممکن است باعث Scan شود. استفاده از مرزهای تاریخ معمولاً بهتر است.
ساخت بازه نیمهباز برای یک روز
DECLARE @TargetDate date = '2026-07-17';
SELECT *
FROM dbo.tblNewsContent
WHERE PublishedDate >= @TargetDate
AND PublishedDate < DATEADD(day, 1, @TargetDate);
این روش تمام ساعتهای روز هدف را پوشش میدهد و از مشکلات مقایسه بخش زمان جلوگیری میکند. استفاده از BETWEEN با انتهای 23:59:59 ممکن است برای نوعهای دقیقتر بخشی از رکوردها را از دست بدهد.
ایجاد تقویم ساده با CTE
DECLARE @StartDate date = '2026-07-01';
DECLARE @EndDate date = '2026-07-07';
WITH Calendar AS
(
SELECT @StartDate AS CalendarDate
UNION ALL
SELECT DATEADD(day, 1, CalendarDate)
FROM Calendar
WHERE CalendarDate < @EndDate
)
SELECT CalendarDate
FROM Calendar
OPTION (MAXRECURSION 100);
برای بازههای بزرگ بهتر است جدول تقویم دائمی یا روش تولید اعداد استفاده شود. CTE بازگشتی برای نمونه آموزشی مناسب است، اما در گزارشهای سنگین همیشه بهترین انتخاب نیست.
اشتباهات رایج
- نوشتن تاریخ در قالب مبهم وابسته به زبان یا DATEFORMAT سرور.
- استفاده از مقدار بسیار بزرگ و ایجاد Overflow.
- فرض اینکه اضافه کردن یک ماه همیشه تعداد ثابتی روز است.
- اعمال تابع روی ستون ایندکسشده داخل WHERE.
- نادیده گرفتن بخش زمان در datetime و datetime2.
- استفاده از GETDATE برای دادههای جهانی بدون تصمیم روشن درباره UTC.
GETDATE در برابر SYSDATETIME
| تابع | نوع خروجی | دقت تقریبی |
| GETDATE | datetime | کمتر |
| SYSDATETIME | datetime2 | بیشتر |
برای سیستمهای جدید معمولاً datetime2 و SYSDATETIME انتخاب دقیقتری هستند. برای ذخیره زمان جهانی، استفاده از SYSUTCDATETIME یا datetimeoffset را بر اساس معماری بررسی کنید.
نکات کارایی و بهترین روشها
- مرز زمانی را یک بار در متغیر محاسبه کنید.
- در فیلترها تابع را روی مقدار ثابت اعمال کنید، نه روی ستون.
- برای قالب تاریخ ورودی از ISO مانند YYYYMMDD یا نوع date استفاده کنید.
- برای بازهها از شرط نیمهباز بزرگتر یا مساوی شروع و کوچکتر از پایان استفاده کنید.
- نوع داده date، datetime2 یا datetimeoffset را آگاهانه انتخاب کنید.
- قواعد انتهای ماه و سال کبیسه را در تستها پوشش دهید.
سؤالات متداول و مصاحبه
چگونه هفت روز از تاریخ کم کنیم؟
SELECT DATEADD(day, -7, SYSDATETIME());
تفاوت DATEADD و DATEDIFF چیست؟
DATEADD یک بازه را به تاریخ اضافه میکند، اما DATEDIFF تعداد مرزهای زمانی بین دو تاریخ را محاسبه میکند.
چرا شرط نیمهباز بهتر است؟
چون مستقل از دقت بخش زمان است و احتمال حذف رکوردهای انتهای روز را کاهش میدهد.
چکلیست و جمعبندی
- واحد datepart صحیح انتخاب شده است.
- عدد مثبت یا منفی مطابق هدف است.
- نوع داده خروجی ظرفیت لازم را دارد.
- مرز ماه و سال کبیسه تست شده است.
- شرط WHERE قابل استفاده توسط ایندکس نوشته شده است.
DATEADD ابزار اصلی محاسبات تاریخ در SQL Server است. با انتخاب نوع داده مناسب، نوشتن بازههای نیمهباز و خودداری از اعمال تابع روی ستونهای فیلتر، میتوان کوئریهای دقیق، سریع و قابل نگهداری ساخت.