5

我正在尝试编写一个查询来查找与我的公司一起庆祝每月周年纪念的用户,以便我们可以向他们发送电子邮件(即,如果今天的日期是 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 的人混为一谈。

这些事情中的任何一个都可以通过 SQL 查询来完成吗?

4

4 回答 4

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

如果是 2 月,请寻找 28 日。

于 2013-03-28T02:35:07.157 回答
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() ) )
于 2013-03-28T03:53:32.363 回答
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

...ETC。

编辑:

我的上述答案可以通过将其包装到 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
于 2013-03-28T03:20:08.373 回答
0

尝试这样的事情:

创建一个包含从 1 到 1000 的整数填充的单列 [months] 的永久表 M,并使用如下查询:

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 列表中并获取精确的周年月数。

于 2013-03-28T03:00:34.157 回答