2013-03-28 3 views
5

Ich versuche, eine Abfrage zu schreiben, die Benutzer finden, die einen monatlichen Jahrestag mit meiner Firma feiern, so können wir eine E-Mail an sie auslösen (dh, wenn das heutige Datum 3/27 ist, es würde Leute finden, die sich auf 1/27, 2/27, 3/27, 4/27, etc., unabhängig vom Jahr) angemeldet haben.SQL-Abfrage, um Benutzer für den monatlichen Jahrestag zu finden

Meine Methode ist Benutzer zu finden, deren "Tag" Teil ihres Anmeldedatums gleich dem "Tag" Teil des heutigen Datums ist.

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

Dies ist jedoch natürlich nicht für diese Szenarien funktioniert:

  1. Am Ende Februar würde ich die Chance bekommen, die Menschen nicht per E-Mail mit 29, 30 und 31 monatlich Jahrestagstage, als die nicht passieren. Im Idealfall, wenn es der 28. Februar ist, würde ich gerne Leute mit 29, 30 und 31 Dates aufnehmen.

  2. Für jeden anderen Monat, wo das Datum in einem 30. endet, würde ich nicht Leute mit 31. Daten per E-Mail schicken. Im Idealfall würde ich hier nur Leute mit 30 und 31 Dates aufnehmen.

Kann eines dieser Dinge mit einer SQL-Abfrage erreicht werden?

+0

Was auf den ersten (oder 15.) des Monats statt? –

Antwort

1

Sie benötigen eine kompliziertere where Klausel. Hier ist eine Brute-Force-Methode:

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

Wenn es ist, suchen Sie nach 28.

0

versuchen, etwas wie folgt aus:

Erstellen Sie eine permanente Tabelle M mit einer einzigen Spalte [Monate] 1-1000 mit den ganzen Zahlen bevölkert, und eine Abfrage wie folgt verwenden:

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] 

Während es nicht sehr effizient, für eine kleine Anzahl von Mitarbeitern ist es kein Problem, einmal am Tag zu laufen. Sie können auch M.months zur SELECT-Liste hinzufügen und erhalten die genaue Anzahl der Jahrestag von Monaten, wenn Sie möchten.

0

Subtrahieren Sie einen Monat und fügen Sie jeden folgenden Tag aus einem Bereich von bis zu 4 Tagen hinzu, wobei das Hinzufügen des Monats das aktuelle Datum nicht überschreitet.

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; 

Ergebnis für 2013.02.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 

Ergebnis für 2013.03.27:

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

Ergebnis für 2013.04.30:

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

... usw.

Edit:

Meine oben Antwort angewendet werden könnte, indem sie in einem WAK Einwickeln und dann auf einfache Art und Weise zu Ihrer ursprünglichen Abfrage verbindet.Beachten Sie, dass die Inline-Funktion Anrufe werden immer für die ganze Abfrage auf vier Reihen beschränkt, so Auswirkungen auf die Leistung der Datumsfunktionen sollte vernachlässigbar sein:

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

einige komplizierte Antworten hier! Wir können erheblich vereinfachen:

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

für Ihre Nutzung:

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

Sind Sie sicher, dass dies am Monatsende und in Schaltjahren richtig ist? Ich sage es nicht, ich frage nur, ob du dir sicher bist. Etwas wie [@ GordonLinoffs Antwort] (http://stackoverflow.com/a/15673272), obwohl vielleicht "komplizierter", hat den Vorteil der Transparenz. – AakashM

+0

Dies hat den Vorteil, Logik zu nutzen, die bereits seit Jahren implementiert und getestet wird. DATEADD behandelt alles richtig, und ich habe es selbst getestet, aber da Ihr Ruf in der Leitung liegt, wenn Sie diesen Code verwenden, ist es immer ratsam, es selbst zu testen. Es ist auch sehr einfach zu testen - Erstellen Sie die UDF, dann führen Sie die UDF mit den gewünschten Daten aus. Sie werden feststellen, dass "2012-12-31", "2013-02-28" beispielsweise 1 zurückgibt. – Moho

+0

Schön, ich werde mich daran erinnern. – AakashM

Verwandte Themen