2013-03-28 20 views
5

Tôi đang cố viết truy vấn tìm người dùng đang kỷ niệm hàng tháng với công ty của tôi để chúng tôi có thể kích hoạt email cho họ (ví dụ: nếu ngày hôm nay là 3/27, nó sẽ tìm thấy những người đăng ký trên 1/27, 2/27, 3/27, 4/27, vv, bất kể năm).Truy vấn SQL để tìm người dùng cho kỷ niệm hàng tháng

Phương pháp của tôi là tìm người dùng có phần "ngày" trong ngày đăng ký bằng phần "ngày" của ngày hôm nay.

SELECT [User Id],[Sign Up Date] 
    FROM [Monthly Account Update] 
WHERE DATEPART(DAY,[Sign Up Date]) = DAY(GETDATE()) 

Tuy nhiên, điều này tất nhiên không làm việc cho các kịch bản:

  1. Vào cuối tháng Hai, tôi sẽ không có cơ hội để gửi email cho những người có 29, 30 và 31 hàng tháng ngày kỷ niệm, như không xảy ra. Lý tưởng nhất, khi đó là ngày 28 tháng 2, tôi chỉ muốn một lần ở những người có 29, 30 và 31 ngày.

  2. Đối với mỗi tháng mà ngày kết thúc vào ngày 30, tôi sẽ không nhận được email cho những người có ngày 31. Lý tưởng nhất ở đây, tôi chỉ muốn một lần ở những người có 30 và 31 ngày.

Có thể một trong những điều đó được thực hiện bằng truy vấn SQL không?

+0

gì về vào ngày đầu tiên (hoặc 15) của tháng để thay thế? –

Trả lời

1

Bạn cần một mệnh đề where phức tạp hơn. Đây là phương pháp bạo lực:

SELECT [User Id],[Sign Up Date] 
FROM [Monthly Account Update] 
WHERE day([Sign Up Date]) = DAY(GETDATE()) or 
     (month(getdate()) in (4, 6, 9, 11) and day(getdate()) = 30 and DAY([Sign Up Date]) = 31) or 
     (month(getdate()) in (2) and day(getdate()) = 28 and DAY([Sign Up Date]) in (29, 30, 31)) 

Nếu feb của nó, hãy tìm 28.

0

Hãy thử một cái gì đó như thế này:

Tạo M bảng vĩnh viễn với một cột duy nhất [tháng] dân cư với các số nguyên 1-1000, và sử dụng một truy vấn như thế này:

SELECT [User Id],[Sign Up Date] 
FROM [Monthly Account Update] AS U 
JOIN M 
ON CAST(getdate() AS DATE) = DATEADD(month,M.months,U.[Sign Up Date] 

Trong khi đó là không phải là rất hiệu quả, đối với một số ít nhân viên, không có vấn đề gì để chạy một lần một ngày. Bạn cũng có thể thêm M.months vào danh sách SELECT và nhận số ngày kỷ niệm chính xác của tháng nếu bạn muốn.

0

Trừ một tháng và bao gồm mỗi ngày tiếp theo trong phạm vi tối đa 4 ngày khi thêm tháng không vượt quá ngày hiện tại.

DECLARE @Today DATE = '2/28/2013'; 
SELECT [Current] = @Today, [MonthAgo] = DATEADD(DAY,t.v,DATEADD(MONTH,-1,@Today)) 
FROM (VALUES(0),(1),(2),(3)) as t(v) 
WHERE DATEADD(MONTH,1,DATEADD(DAY,t.v,DATEADD(MONTH,-1,@Today))) <= @Today; 

Kết quả cho 2013/02/28:

Current MonthAgo 
---------- ---------- 
2013-02-28 2013-01-28 
2013-02-28 2013-01-29 
2013-02-28 2013-01-30 
2013-02-28 2013-01-31 

Kết quả cho 2013/03/27:

Current MonthAgo 
---------- ---------- 
2013-03-27 2013-02-27 

Kết quả cho 2013/04/30:

Current MonthAgo 
---------- ---------- 
2013-04-30 2013-03-30 
2013-04-30 2013-03-31 

... v.v.

Edit:

câu trả lời trên của tôi có thể được áp dụng bằng cách gói nó vào một CTE và sau đó tham gia vào truy vấn ban đầu của bạn một cách đơn giản.Lưu ý rằng các lệnh gọi hàm nội tuyến luôn bị giới hạn ở bốn hàng cho toàn bộ truy vấn, do đó tác động hiệu suất của các hàm ngày phải không đáng kể:

DECLARE @Today DATE = GETDATE(); 

; WITH CTE AS (
    SELECT [Current] = @Today, [MonthAgo] = DATEADD(DAY,t.v,DATEADD(MONTH,-1,@Today)) 
    FROM (VALUES(0),(1),(2),(3)) as t(v) 
    WHERE DATEADD(MONTH,1,DATEADD(DAY,t.v,DATEADD(MONTH,-1,@Today))) <= @Today 
) 
SELECT [User Id],[Sign Up Date] 
FROM [Monthly Account Update] 
JOIN CTE ON CTE.[MonthAgo] = [Sign Up Date]; 
GO 
1

Một số câu trả lời phức tạp ở đây! Chúng ta có thể đơn giản hóa đáng kể:

create function dbo.fnIsMonthlyAnniversary(
    @startDate date, 
    @comparisonDate date 
) 
returns bit 
as 
begin 
    declare @retVal bit 
    set @retVal = 0 

    declare @deltaMonth int 

    set @deltaMonth = datediff(mm, @startDate, @comparisonDate) 

    if dateadd(mm, @deltaMonth, @startDate) = @comparisonDate 
    begin 
     set @retVal = 1 
    end 

    return @retVal 
end 

-- usage: 
select dbo.fnIsMonthlyAnniversary('2012-12-31', CONVERT(date, getdate())) 

cho sử dụng của bạn:

SELECT [User Id],[Sign Up Date] 
    FROM [Monthly Account Update] 
WHERE 1 = dbo.fnIsMonthlyAnniversary([Sign Up Date], CONVERT(date, getdate())) 
+0

Bạn có chắc điều này có đúng vào cuối tháng và trong những năm nhuận không? Tôi không nói nó không, tôi chỉ hỏi nếu bạn chắc chắn. Một cái gì đó giống như câu trả lời của [@ ​​GordonLinoff] (http://stackoverflow.com/a/15673272), trong khi có lẽ 'phức tạp hơn', có tính chất minh bạch. – AakashM

+0

Điều này có đức hạnh thúc đẩy logic đã được thực hiện và thử nghiệm trong nhiều năm và nhiều năm. DATEADD xử lý tất cả mọi thứ đúng cách, và tôi đã thử nghiệm nó bản thân mình, nhưng như danh tiếng của bạn có thể được trên dòng nếu bạn sử dụng mã này, nó luôn luôn khôn ngoan để kiểm tra nó cho mình. Nó cũng thực sự dễ dàng để kiểm tra - tạo UDF, sau đó thực hiện udf bằng cách sử dụng bất kỳ ngày nào bạn muốn. Bạn sẽ thấy rằng '2012-12-31', '2013-02-28' trả về 1, ví dụ. – Moho

+0

Rất đẹp, tôi sẽ ghi nhớ điều này. – AakashM

Các vấn đề liên quan