2013-03-28 7 views
5

Próbuję napisać zapytanie, które znajdzie użytkowników, którzy obchodzą rocznicę z moją firmą, abyśmy mogli wysłać do nich wiadomość e-mail (np. Jeśli dzisiejsza data to 3/27, znajdzie ludzi, którzy zapisali się na 1/27, 2/27, 3/27, 4/27 itd., niezależnie od roku).Zapytanie SQL, aby znaleźć użytkowników na comiesięczną rocznicę

Moja metoda polega na znalezieniu użytkowników, których "dzień" jest częścią daty rejestracji równej "dziennej" części dzisiejszej daty.

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

Jednak to oczywiście nie działa dla tych scenariuszy:

  1. Pod koniec lutego, nie będę miał szansę Email Ludzie z 29, 30 i 31 miesięcznych rocznice, bo tak się nie stało. Idealnie, gdy jest 28 lutego, chciałbym po prostu załatwić ludzi z 29, 30 i 31 datami.

  2. Za każdy inny miesiąc, w którym data kończy się na 30., nie będę mógł wysyłać e-maili z 31 datami. Idealnie tutaj, chciałbym po prostu zgrupować ludzi z 30 i 31 datami.

Czy można wykonać jedną z tych czynności za pomocą zapytania SQL?

+0

Co o na pierwszy (lub 15-ty) miesiąca w zamian? –

Odpowiedz

1

Potrzebujesz bardziej skomplikowanej klauzuli where. Oto metoda brutalnej siły:

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

Jeśli jest, sprawdź 28.

0

spróbować czegoś takiego:

utworzyć stały stół M z pojedynczej kolumny [miesiące] wypełniona liczb całkowitych od 1 do 1000, i użyć kwerendy tak:

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] 

Chociaż to niezbyt wydajna, dla niewielkiej liczby pracowników, nie ma problemu z uruchomieniem raz dziennie. Możesz również dodać M.months do listy SELECT i otrzymać dokładną liczbę miesięcy, jeśli chcesz.

0

Odejmij miesiąc i dołącz każdy następny dzień z zakresu do 4 dni, w którym dodanie miesiąca nie przekracza aktualnej daty.

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; 

Wynik dla 28.02.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 

Wynik dla 27.03.2013:

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

Wynik dla 30.04.2013:

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

... itd.

Edit:

Moja odpowiedź powyżej mogą być stosowane przez owinięcie go w WRC, a następnie przystąpienie do oryginalnego zapytania w prosty sposób.Należy zauważyć, że wywołania funkcji inline są zawsze ograniczone do czterech wierszy dla całego zapytania, więc wpływ na wydajność funkcji data powinna być znikoma:

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

pewnych skomplikowanych odpowiedzi tutaj! Możemy uprościć znacznie:

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

dla wykorzystania:

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

Czy jesteś pewien, że to dobrze na koniec miesiąca i lata przestępne? Nie mówię, że nie, pytam tylko, czy jesteś tego pewien. Coś w stylu [@ GordonLinoff's answer] (http://stackoverflow.com/a/15673272), chociaż być może "bardziej skomplikowane", ma zalety przejrzystości. – AakashM

+0

Ma to zalety polegające na wykorzystaniu logiki już wdrożonej i przetestowanej przez wiele lat. DATEADD obsługuje wszystko poprawnie i przetestowałem to sam, ale ponieważ Twoja reputacja może być na linii, jeśli używasz tego kodu, zawsze mądrze jest przetestować to samemu. Jest również bardzo łatwy do przetestowania - utwórz UDF, a następnie wykonaj udf używając dat, które chcesz. Przekonasz się, że "2012-12-31", "2013-02-28" zwraca 1, na przykład. – Moho

+0

Dobrze, będę o tym pamiętać. – AakashM

Powiązane problemy