2013-03-28 3 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 ежемесячном юбилейных дней, так как этого не происходит. В идеале, когда это будет 28 февраля, я просто хотел бы окунуться в людей с 29, 30 и 31 датами.

  2. На каждый другой месяц, когда дата заканчивается на 30-м, я не стал бы посылать по электронной почте людей с 31-й датой. В идеале здесь я просто хотел бы окунуться в людей с 30 и 31 датами.

Может ли любая из этих вещей быть выполнена с помощью SQL-запроса?

+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-й.

0

попробовать что-то вроде этого:

Создание постоянной таблицы М с одной колонке [месяцев] заполняется целыми числами от 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; 

Результат для 2/28/2013:

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 

Результат для 3/27/2013:

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

Результат для 4/30/2013:

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

... и т.п.

Edit:

Мой выше ответ может быть применен, обернув его в КТР, а затем присоединиться к исходному запросу простым способом.Обратите внимание, что вызовы встроенных функций всегда ограничивается четырьмя рядами для всего запроса, поэтому влияние на производительность функций даты должны быть несущественными:

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

+0

Это имеет силу использования логики, уже реализованной и проверенной годами и годами. DATEADD обрабатывает все правильно, и я сам его тестировал, но поскольку ваша репутация может быть на линии, если вы используете этот код, всегда разумно тестировать его самостоятельно. Это также очень легко проверить - создайте UDF, затем выполните udf, используя любые даты, которые вы хотите. Вы увидите, что '2012-12-31', '2013-02-28' возвращает 1, например. – Moho

+0

Ницца, я буду помнить об этом. – AakashM

Смежные вопросы