2013-03-28 35 views
5

我正在尝试编写一个查询,以查找与我的公司一起庆祝月度周年纪念的用户,以便我们可以触发电子邮件给他们(例如,如果今天的日期是3/27,它会发现无论年份为1/27,2/27,3/27,4/27等都签了名的人)。查询月度周年用户的SQL查询

我的方法是查找其注册日期的“天”部分等于今天的“日”部分的用户。

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

然而,这当然不会为这些方案的工作:

  1. 在二月底,我不会以电子邮件的人与29,30和31月的机会周年纪念日,因为不会发生。理想的情况是,在2月28日的时候,我只想要29,30和31日的人。

  2. 对于日期在30日结束的其他月份,我不会收到第31个日期的电子邮件。理想情况下,我只想在30和31日期的人群中。

可以任意的那些东西用SQL查询来实现的呢?

+0

什么的,而不是每月的第一个(或15日)? – 2013-03-28 02:38:59

回答

1

您需要更复杂的where子句。这是一个强制的方法:

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)) 

如果它的二月,寻找28位。

0

尝试这样:

与单个列创建一个永久表M [月]与整数人口从1至1000,并使用这样的查询:

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] 

虽然这是对于少数员工来说效率不高,每天运行一次也没有问题。您还可以将M.months添加到SELECT列表中,并根据需要获得确切的周年数。

0

减去一个月,并包括最多4天范围内的每个后续日期,其中添加月份不超过当前日期。

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; 

结果为2013年2月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 

结果为2013年3月27日:

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

结果为二零一三年四月三十零日:

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

...等。

编辑:

我上面的回答可以用它包装成一个CTE,然后在一个简单的方式加入到原始查询应用。需要注意的是内联函数调用总是有限的四行整个查询,这样的日期函数性能的影响可以忽略不计:

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

一些复杂的答案在这里!我们可以大大简化:

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())) 
为您的使用情况

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

你确定这在月末和闰年是否正确?我不是说没有,我只是问你是否确定。像[@ GordonLinoff的回答](http://stackoverflow.com/a/15673272),虽然可能“更复杂”,但具有透明度的优点。 – AakashM 2013-03-28 08:55:09

+0

这具有利用已经实施和测试多年和多年的逻辑的优点。 DATEADD可以正确处理所有事情,并且我自己对其进行了测试,但是如果您使用此代码,您的声誉可能在线,那么自己测试它总是明智的。测试也很容易 - 创建UDF,然后使用任何你想要的日期执行udf。例如,你会发现'2012-12-31','2013-02-28'返回1。 – Moho 2013-03-28 09:09:51

+0

不错,我会记住这一点。 – AakashM 2013-03-28 09:32:42