SQL查询查找用户的月度周年纪念日

时间:2013-03-28 02:30:30

标签: sql sql-server tsql

我正在尝试编写一个查询,查找与我公司一起庆祝月度周年纪念的用户,以便我们可以向他们发送电子邮件(即,如果今天的日期是3/27,则会找到注册的人无论年份如何,1 / 27,2 / 27,3 / 27,4 / 27等。

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

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

但是,这当然不适用于这些情况:

  1. 2月底,我没有机会通过电子邮件向29,30和31个月周年纪念日的人发送电子邮件,因为这不会发生。理想情况下,当它是2月28日时,我只想把29,30和31个日期的人混为一谈。

  2. 对于日期在30日结束的其他每个月,我都不会给第31个日期的人发送电子邮件。理想情况下,我只想把30和31个日期的人混在一起。

  3. 可以使用SQL查询完成其中任何一项吗?

4 个答案:

答案 0 :(得分: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))

如果它的feb,请寻找第28位。

答案 1 :(得分: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() ) )

答案 2 :(得分:0)

尝试这样的事情:

创建一个永久表M,其中一列[months]填充了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列表中,并根据需要获得精确的周年纪念日数。

答案 3 :(得分: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

2013年4月30日的结果:

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