۱۴۰۴/۰۷/۱۷ Nebular

استفاده از توابع Date

میخواهیم کاری کنیم که روز تولد هر کارمند را مطلع شویم .

این یک سناریوی واقعی و خیلی کاربردی برای SQL Server و پایگاه داده است 😎
بیایم راهکار استاندارد و حرفه‌ای را مرحله به مرحله بررسی کنیم.


۱️ داده‌ها و جدول نمونه

فرض کن جدول Employees داریم:

CREATE TABLE Employees (
    EmployeeID INT PRIMARY KEY,
    FirstName NVARCHAR(50),
    LastName NVARCHAR(50),
    BirthDate DATE
);
  • ستون BirthDate شامل تاریخ تولد کارمند است

۲️ سناریو: اطلاع رسانی یک هفته قبل تولد

🔹 روش ساده با Query روزانه

  • هر روز (مثلاً با SQL Agent Job) Query زیر اجرا می‌شود:
SELECT EmployeeID, FirstName, LastName, BirthDate
FROM Employees
WHERE 
    DATEPART(MONTH, BirthDate) = DATEPART(MONTH, GETDATE() + 7)
    AND DATEPART(DAY, BirthDate) = DATEPART(DAY, GETDATE() + 7);

✅ توضیح:

  • GETDATE() + 7 → تاریخ امروز + 7 روز
  • شرط چک می‌کند که ماه و روز تولد برابر با تاریخ ۷ روز بعد باشد
  • توجه: سال تولد مهم نیست → فقط ماه و روز تولد

نسخه بهبودیافته :

sql

SELECT EmployeeID, FirstName, LastName, BirthDate
FROM Employees
WHERE DATEPART(MONTH, BirthDate) = DATEPART(MONTH, DATEADD(DAY, 7, CAST(GETDATE() AS DATE)))
  AND DATEPART(DAY, BirthDate) = DATEPART(DAY, DATEADD(DAY, 7, CAST(GETDATE() AS DATE)));

تغییرات:

CAST(GETDATE() AS DATE) → فقط تاریخ، بدون زمان DATEADD(DAY, 7, …) → دقیقاً ۷ روز بعد


۳️ اتوماسیون با SQL Server Agent

  • می‌توانیم یک Job روزانه بسازیم که این Query را اجرا کند
  • خروجی Query → ایمیل، ذخیره در جدول Notify یا Trigger روی اپلیکیشن

مثال با ایمیل:

EXEC msdb.dbo.sp_send_dbmail
    @profile_name = 'HRMail',
    @recipients = 'hr@example.com',
    @subject = 'Upcoming Employee Birthday',
    @body = 'Some employees have birthday in 7 days!',
    @query = N'SELECT FirstName, LastName, BirthDate FROM Employees WHERE DATEPART(MONTH,BirthDate)=DATEPART(MONTH, GETDATE()+7) AND DATEPART(DAY,BirthDate)=DATEPART(DAY, GETDATE()+7)';

۴️ نکته مهم: سال تولد و Leap Year

  • اگر بخواهیم سن کارمند را هم محاسبه کنیم:
SELECT FirstName, LastName, BirthDate,
       DATEDIFF(YEAR, BirthDate, GETDATE()) AS AgeNextBirthday
FROM Employees
WHERE 
    DATEPART(MONTH, BirthDate) = DATEPART(MONTH, GETDATE() + 7)
    AND DATEPART(DAY, BirthDate) = DATEPART(DAY, GETDATE() + 7);
  • اینطوری هم سن و هم تاریخ تولد مشخص می‌شود
  • برای سال کبیسه (Leap Year) → اگر کسی 29 Feb تولد دارد، می‌توانیم با CASE مدیریت کنیم:
WHERE 
    (DATEPART(MONTH, BirthDate) = 2 AND DATEPART(DAY, BirthDate) = 29 AND DATEPART(MONTH, GETDATE()+7)=2 AND DATEPART(DAY, GETDATE()+7)=28)
    OR
    (DATEPART(MONTH, BirthDate) = DATEPART(MONTH, GETDATE()+7) AND DATEPART(DAY, BirthDate) = DATEPART(DAY, GETDATE()+7))

۵️ روش پیشرفته با Event / Trigger یا Scheduled Task

  • SQL Server خودکار trigger برای تولد ندارد
  • ولی می‌توان:
    1. یک SQL Server Agent Job روزانه بسازی
    2. SP بسازی که Query را اجرا و ایمیل/اطلاعیه می‌فرستد
    3. اپلیکیشن هر روز این SP را فراخوانی کند

🔹 جمع‌بندی

  1. Query اصلی: چک کردن تولد ۷ روز بعد با DATEPART
  2. اتوماسیون: SQL Server Agent Job
  3. اطلاع‌رسانی: ایمیل، جدول Notify یا اپلیکیشن
  4. مزیت: ساده، قابل فهم، قابل توسعه برای سن کارمند و سال کبیسه

حالا اگر بخایم اول هر هفته لیست کارمندانی که این هفته تولدشون هست رو بیگریم باید چکار کینم ؟

تعریف مسئله

  • می‌خواهیم لیست کارمندانی که تاریخ تولدشان در هفته جاری است را استخراج کنیم.
  • هفته جاری = از اول هفته (مثلاً Monday) تا آخر هفته (Sunday)
  • ستون BirthDate شامل تاریخ تولد کامل (سال، ماه، روز) است.
  • فقط ماه و روز تولد مهم است (سال تولد برای سن محاسبه می‌شود).

۲️ محاسبه شروع و پایان هفته جاری

SQL Server:

-- شروع هفته (Monday)
DECLARE @StartOfWeek DATE = DATEADD(DAY, 1 - DATEPART(WEEKDAY, GETDATE()), CAST(GETDATE() AS DATE));

-- پایان هفته (Sunday)
DECLARE @EndOfWeek DATE = DATEADD(DAY, 7 - DATEPART(WEEKDAY, GETDATE()), CAST(GETDATE() AS DATE));
  • نکته: DATEPART(WEEKDAY, GETDATE()) بر اساس SET DATEFIRST تعیین می‌کند که هفته از چه روزی شروع می‌شود.
  • اگر بخواهیم هفته از Monday شروع شود:
SET DATEFIRST 1; -- 1 = Monday

۳️ استخراج لیست تولدها در هفته جاری

راه استاندارد: تبدیل ماه و روز به تاریخ جاری سال و چک بین شروع و پایان هفته:

SET DATEFIRST 1; -- هفته از Monday شروع می‌شود

DECLARE @StartOfWeek DATE = DATEADD(DAY, 1 - DATEPART(WEEKDAY, GETDATE()), CAST(GETDATE() AS DATE));
DECLARE @EndOfWeek DATE = DATEADD(DAY, 7 - DATEPART(WEEKDAY, GETDATE()), CAST(GETDATE() AS DATE));

SELECT EmployeeID, FirstName, LastName, BirthDate,
       DATEPART(YEAR, GETDATE()) - DATEPART(YEAR, BirthDate) AS AgeThisYear
FROM Employees
WHERE 
    -- تاریخ تولد این سال را می‌سازیم
    DATEFROMPARTS(YEAR(GETDATE()), MONTH(BirthDate), DAY(BirthDate))
    BETWEEN @StartOfWeek AND @EndOfWeek
ORDER BY BirthDate;

✅ توضیح:

  • DATEFROMPARTS(YEAR(GETDATE()), MONTH(BirthDate), DAY(BirthDate)) → تاریخ تولد امسال کارمند
  • سپس با BETWEEN بین شروع و پایان هفته مقایسه می‌کنیم

تولد کارمندانی که در هفته اینده تولدشون هست
ساده‌ترین کوئری SQL:

SELECT 
    EmployeeID, 
    FirstName, 
    LastName, 
    BirthDate,
    DATEPART(YEAR, GETDATE()) - DATEPART(YEAR, BirthDate) AS AgeThisYear
FROM Employees
WHERE 
    DATEFROMPARTS(YEAR(GETDATE()), MONTH(BirthDate), DAY(BirthDate))
    BETWEEN CAST(GETDATE() AS DATE) AND DATEADD(DAY, 7, CAST(GETDATE() AS DATE))
ORDER BY MONTH(BirthDate), DAY(BirthDate);

ساده‌ترین کوئری SQL برای تولدهای ماه جاری

SELECT 
EmployeeID,
FirstName,
LastName,
BirthDate,
DATEPART(YEAR, GETDATE()) - DATEPART(YEAR, BirthDate) AS AgeThisYear
FROM Employees
WHERE
MONTH(BirthDate) = MONTH(GETDATE())
AND YEAR(GETDATE()) = YEAR(DATEFROMPARTS(YEAR(GETDATE()), MONTH(BirthDate), DAY(BirthDate)))
ORDER BY MONTH(BirthDate), DAY(BirthDate);

or

SELECT
EmployeeID,
FirstName,
LastName,
BirthDate,
DATEPART(YEAR, GETDATE()) - DATEPART(YEAR, BirthDate) AS AgeThisYear
FROM Employees
WHERE
MONTH(BirthDate) = MONTH(GETDATE())
ORDER BY DAY(BirthDate);

ساده‌ترین کوئری SQL برای تولدهای ماه آینده

sql

SELECT 
    EmployeeID, 
    FirstName, 
    LastName, 
    BirthDate,
    DATEPART(YEAR, GETDATE()) - DATEPART(YEAR, BirthDate) AS AgeThisYear
FROM Employees
WHERE 
    MONTH(BirthDate) = MONTH(DATEADD(MONTH, 1, GETDATE()))
ORDER BY DAY(BirthDate);

۴️ نکات عملی

  1. سن کارمند → می‌توانیم محاسبه کنیم:
DATEDIFF(YEAR, BirthDate, GETDATE()) AS AgeThisYear
  1. Leap Year → اگر کسی 29 Feb باشد، می‌توانیم شرط اضافی اضافه کنیم تا در سال غیرکبیسه، 28 Feb نمایش داده شود.
  2. اتوماسیون → همانند قبل:
  • SQL Server Agent Job هفتگی اجرا شود
  • SP یا Query بالا را اجرا و جدول Notify یا ایمیل HR را پر کند

۵️ مثال SP هفتگی

CREATE PROCEDURE dbo.GetWeeklyBirthdays
AS
BEGIN
    SET NOCOUNT ON;
    SET DATEFIRST 1; -- هفته از Monday شروع شود

    DECLARE @StartOfWeek DATE = DATEADD(DAY, 1 - DATEPART(WEEKDAY, GETDATE()), CAST(GETDATE() AS DATE));
    DECLARE @EndOfWeek DATE = DATEADD(DAY, 7 - DATEPART(WEEKDAY, GETDATE()), CAST(GETDATE() AS DATE));

    SELECT EmployeeID, FirstName, LastName, BirthDate,
           DATEDIFF(YEAR, BirthDate, GETDATE()) AS AgeThisYear
    FROM Employees
    WHERE DATEFROMPARTS(YEAR(GETDATE()), MONTH(BirthDate), DAY(BirthDate))
          BETWEEN @StartOfWeek AND @EndOfWeek
    ORDER BY BirthDate;
END;
  • SP را می‌توان هر هفته اجرا کرد یا در SQL Server Agent Job گذاشت
  • خروجی → جدول یا ایمیل هفتگی

یک گزارش کلی از تولدهای هر ماه در سال جاری داشته باشیم، به طوری که بتوانیم ببینیم هر ماه چه کارمندانی تولد دارند. این کار خیلی ساده با GROUP BY یا ORDER BY ماه تولد قابل انجام است. بیایم کامل بررسی کنیم:


۱️ جدول نمونه

فرض کنیم جدول Employees داریم:

CREATE TABLE Employees (
    EmployeeID INT PRIMARY KEY,
    FirstName NVARCHAR(50),
    LastName NVARCHAR(50),
    BirthDate DATE
);

۲️ کوئری برای لیست کارمندان هر ماه

روش ۱: فقط با ماه تولد

SELECT 
    DATEPART(MONTH, BirthDate) AS BirthMonth,
    FirstName,
    LastName,
    BirthDate
FROM Employees
ORDER BY BirthMonth, DAY(BirthDate);

✅ توضیح:

  • DATEPART(MONTH, BirthDate) → شماره ماه تولد (1 تا 12)
  • ORDER BY BirthMonth, DAY(BirthDate) → مرتب‌سازی کارمندان در هر ماه بر اساس روز تولد

روش ۲: گروه‌بندی ماه‌ها (هر ماه یک گروه)

اگر بخواهیم یک ماه و لیست کارمندانی که در آن ماه تولد دارند داشته باشیم:

SELECT 
    DATENAME(MONTH, BirthDate) AS MonthName,
    COUNT(*) AS TotalBirthdays,
    STRING_AGG(FirstName + ' ' + LastName, ', ') AS Employees
FROM Employees
WHERE YEAR(BirthDate) <= YEAR(GETDATE())  -- می‌توان شرط دلخواه گذاشت
GROUP BY DATENAME(MONTH, BirthDate), DATEPART(MONTH, BirthDate)
ORDER BY DATEPART(MONTH, BirthDate);

✅ توضیح:

  • DATENAME(MONTH, BirthDate) → نام ماه انگلیسی (January, February, …)
  • STRING_AGG() → لیست کارمندان در همان ماه را به صورت یک رشته جدا شده با کاما می‌سازد
  • GROUP BY → هر ماه یک ردیف

خروجی مثال:

MonthNameTotalBirthdaysEmployees
January3John Doe, Jane Smith, Bob Lee
February2Alice Green, Tom Brown

روش ۳: ترتیب بر اساس ماه

  • با ORDER BY DATEPART(MONTH, BirthDate) مطمئن می‌شویم که ماه‌ها از 1 تا 12 مرتب شوند، نه به ترتیب حروف.

۳️ نکات حرفه‌ای

  1. می‌توان از YEAR(GETDATE()) برای محدود کردن فقط تولدهای سال جاری استفاده کرد.
  2. اگر بخواهید تاریخ تولد واقعی و سن فعلی کارمند در این سال را هم نشان دهید:
SELECT 
    DATENAME(MONTH, BirthDate) AS MonthName,
    FirstName,
    LastName,
    BirthDate,
    DATEPART(YEAR, GETDATE()) - DATEPART(YEAR, BirthDate) AS AgeThisYear
FROM Employees
ORDER BY DATEPART(MONTH, BirthDate), DAY(BirthDate);
  1. اگر بخواهید برای گزارش اپلیکیشن یا ایمیل → می‌توانید خروجی را در View یا SP قرار دهید.

💡 جمع‌بندی:

  • DATEPART(MONTH, BirthDate) → شماره ماه تولد
  • DATENAME(MONTH, BirthDate) → نام ماه تولد
  • STRING_AGG → ترکیب کارمندانی که در یک ماه تولد دارند
  • با GROUP BY → هر ماه یک ردیف داشته باشیم
  • با ORDER BY DATEPART(MONTH) → ماه‌ها را از 1 تا 12 مرتب کنیم
Accept Cookies
Accept Cookies
[your-shortcode]