Holen Sie sich die Datensätze des letzten Monats in SQL Server


75

Ich möchte die Datensätze des letzten Monats basierend auf meinem Feld "date_created" in der Datenbanktabelle [member] abrufen.

Was ist die SQL, um dies zu tun?

Zur Verdeutlichung im letzten Monat - 08.01.2009 bis 31.8.2009

Wenn heute der 01.03.2010 ist, muss ich die Aufzeichnungen vom 12.01.2009 bis zum 31.12.2009 erhalten.


2
Bedeutet "letzter Monat" die "letzten 30 Tage", "alle Tage im Vormonat" oder "alle Tage im aktuellen Monat"?
Cellfish

Die beste Syntax hängt auch davon ab, ob Sie SQL 2005 (oder früher) mit einem DATETIME-Feld oder SQL 2008 mit einem DATE-Feld verwenden.
Eidylon

4
Was ist mit DATEDIFF(month, date_created, GETDATE()) = 1? Würde das nicht auch funktionieren?
Philipp M

Antworten:


113
SELECT * 
FROM Member
WHERE DATEPART(m, date_created) = DATEPART(m, DATEADD(m, -1, getdate()))
AND DATEPART(yyyy, date_created) = DATEPART(yyyy, DATEADD(m, -1, getdate()))

Sie müssen den Monat und das Jahr überprüfen.


2
in meinem Fall SELECT * FROM Member WHERE DATEPART(m, date_created) = DATEPART(m, DATEADD(m, -1, getdate())) AND DATEPART(yy, date_created) = DATEPART(yy, DATEADD(m, -1, getdate()))funktioniert perfekt
gofor.net

9
Dieser Ansatz ignoriert alle Indizes in der Tabelle und führt bei jeder Ausführung einen Tabellen- (oder Clustered-Index-) Scan durch. Je größer die Tabelle wird, desto länger dauert die Abfrage.
Mrdenny

5
Sie müssen yyyy statt y verwenden
inser

103

Alle vorhandenen (Arbeits-) Antworten haben eines von zwei Problemen:

  1. Sie ignorieren Indizes in der gesuchten Spalte
  2. Das wird (möglicherweise) Daten auswählen, die nicht beabsichtigt sind, und Ihre Ergebnisse stillschweigend verfälschen.

1. Ignorierte Indizes:

Wenn für eine durchsuchte Spalte eine Funktion aufgerufen wird (einschließlich implizit wie für CAST), muss der Optimierer zum größten Teil die Indizes in der Spalte ignorieren und jeden Datensatz durchsuchen. Hier ist ein kurzes Beispiel:

Wir haben es mit Zeitstempeln zu tun, und die meisten RDBMS speichern diese Informationen in der Regel als zunehmenden Wert, normalerweise als longoder BIGINTEGERin Milli- / Nanosekunden. Die aktuelle Zeit sieht also so aus / wird wie folgt gespeichert:

1402401635000000  -- 2014-06-10 12:00:35.000000 GMT

Sie sehen dort nicht den 'Year'-Wert ( '2014'), oder? Tatsächlich gibt es einiges an komplizierter Mathematik, die man hin und her übersetzen kann. Wenn Sie also eine der Extraktions- / Datumsteilfunktionen in der gesuchten Spalte aufrufen, muss der Server all diese Berechnungen durchführen, um herauszufinden, ob Sie sie in die Ergebnisse aufnehmen können. Bei kleinen Tabellen ist dies kein Problem, aber wenn der Prozentsatz der ausgewählten Zeilen abnimmt, wird dies zu einem immer größeren Abfluss. Dann machen Sie es in diesem Fall ein zweites Mal, um nach MONTH... zu fragen. Nun , Sie bekommen das Bild.

2. Unbeabsichtigte Daten:

Abhängig von der jeweiligen Version von SQL Server und Datentypen von Spalten, mit BETWEEN(oder ähnlich inklusive oberen gebundenen Bereichen: <=) kann in den falschen Daten führen ausgewählt werden . Im Wesentlichen können Sie Daten ab Mitternacht des "nächsten" Tages einschließen oder einen Teil der Aufzeichnungen des "aktuellen" Tages ausschließen.

Was Sie sollten dabei sein:

Wir brauchen also einen Weg, der für unsere Daten sicher ist und Indizes verwendet (falls möglich). Der richtige Weg ist dann von der Form:

WHERE date_created >= @startOfPreviousMonth AND date_created < @startOfCurrentMonth

Da es nur einen Monat gibt, @startOfPreviousMonthkann es leicht ersetzt werden durch:

DATEADD(month, -1, @startOCurrentfMonth)

Wenn Sie den Beginn des aktuellen Monats auf dem Server ableiten müssen, können Sie dies folgendermaßen tun:

DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)

Ein kurzes Wort zur Erklärung hier. Die Initiale DATEDIFF(...)wird den Unterschied zwischen dem Beginn der aktuellen Ära ( 0001-01-01- AD, CE, was auch immer) erkennen und im Wesentlichen eine große ganze Zahl zurückgeben. Dies ist die Anzahl der Monate bis zum Beginn des aktuellen Monats. Wir addieren diese Zahl dann zum Beginn der Ära, die zu Beginn des jeweiligen Monats liegt.

Ihr vollständiges Skript könnte / sollte also wie folgt aussehen:

DECLARE @startOfCurrentMonth DATETIME
SET @startOfCurrentMonth = DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)

SELECT *
FROM Member
WHERE date_created >= DATEADD(month, -1, @startOfCurrentMonth) -- this was originally    misspelled
      AND date_created < @startOfCurrentMonth

Alle Datumsoperationen werden daher nur einmal mit einem Wert ausgeführt. Dem Optimierer steht es frei, Indizes zu verwenden, und es werden keine falschen Daten aufgenommen.


8
Ich wünschte wirklich, selbst wenn es mich den Ruf kosten würde, könnte ich dies mehr als einmal abstimmen. Gut gemacht.
Knox

2
Du bist ein Genie! Ich freue mich über eine gut geschriebene Antwort, die nicht herabsetzt, sondern nur informiert. Großartige Arbeit! Ich stimme auch mit @knox
bird2920

Dies sollte die beste Antwort sein. Zusätzlicher Dank für die Information, dass "ZWISCHEN" in diesem Fall nicht funktionieren würde, weil es einen zusätzlichen Tag fangen würde.
Cosan

11

Wenn Sie die bisher bereitgestellten Optionen hinzufügen, werden Ihre Indizes überhaupt nicht verwendet.

So etwas reicht aus und verwendet einen Index für die Tabelle (falls vorhanden).

DECLARE @StartDate DATETIME, @EndDate DATETIME
SET @StartDate = dateadd(mm, -1, getdate())
SET @StartDate = dateadd(dd, datepart(dd, getdate())*-1, @StartDate)
SET @EndDate = dateadd(mm, 1, @StartDate)

SELECT *
FROM Member
WHERE date_created BETWEEN @StartDate AND @EndDate

Es tut uns leid, die Abstimmung herabzustimmen, aber es funktioniert nicht: Versuchen Sie '12 / 31/2013 11:59 'als Gegenbeispiel (gibt Zeilen zwischen' 2013-10-30 11: 59: 00.000 'und' 2013-11-30 11: 59: 00.000 'auf SQL Server).
Daniel Cotter

1
getdate () gibt Ihnen die aktuelle Zeit an. Ich denke, Sie sollten sich ab 12:00 Uhr (Beginn des Tages) Zeit nehmen. @Rokas Antwort ist richtig. Drucken Sie die Start- und Endzeit aus, wenn Sie sehen möchten.
madhu_karnati

10
DECLARE @StartDate DATETIME, @EndDate DATETIME
SET @StartDate = DATEADD(mm, DATEDIFF(mm,0,getdate())-1, 0)
SET @EndDate = DATEADD(mm, 1, @StartDate)

SELECT *
FROM Member
WHERE date_created BETWEEN @StartDate AND @EndDate

Ein Upgrade auf die Lösung von mrdenny, auf diese Weise erhalten Sie genau den letzten Monat von JJJJ-MM-01


3

Letzter Monat gilt als bis zum letzten Tag des Monats. Der letzte Tag des Monats ist der 31. Januar, was nicht den letzten 30 Tagen entspricht.

SELECT CONVERT(DATE, DATEADD(DAY,-DAY(GETDATE()),GETDATE()))

1

Eine Möglichkeit hierfür ist die Verwendung der DATEPART- Funktion:

select field1, field2, fieldN from TABLE where DATEPART(month, date_created) = 4 
and DATEPART(year, date_created) = 2009

wird alle Daten im April zurückgeben. Für den letzten Monat (dh vor dem aktuellen Monat) können Sie auch GETDATE und DATEADD verwenden :

select field1, field2, fieldN from TABLE where DATEPART(month, date_created) 
= (DATEPART(month, GETDATE()) - 1) and 
DATEPART(year, date_created) = DATEPART(year, DATEADD(m, -1, GETDATE()))

3
Dieser Ansatz ignoriert alle Indizes in der Tabelle und führt bei jeder Ausführung einen Tabellen- (oder Clustered-Index-) Scan durch. Je größer die Tabelle wird, desto länger dauert die Abfrage.
Mrdenny

1
declare @PrevMonth as nvarchar(256)

SELECT @PrevMonth = DateName( month,DATEADD(mm, DATEDIFF(mm, 0, getdate()) - 1, 0)) + 
   '-' + substring(DateName( Year, getDate() ) ,3,4)

1

SQL-Abfrage, um nur den aktuellen Monat aufzuzeichnen

SELECT * FROM CUSTOMER
WHERE MONTH(DATE) = MONTH(CURRENT_TIMESTAMP) AND YEAR(DATE) = YEAR(CURRENT_TIMESTAMP);

0
select * from [member] where DatePart("m", date_created) = DatePart("m", DateAdd("m", -1, getdate())) AND DatePart("yyyy", date_created) = DatePart("yyyy", DateAdd("m", -1, getdate()))

2
Während dieser Code die Frage möglicherweise beantwortet, verbessert die Bereitstellung eines zusätzlichen Kontexts darüber, warum und / oder wie dieser Code die Frage beantwortet, ihren langfristigen Wert.
β.εηοιτ.βε

0
DECLARE @StartDate DATETIME, @EndDate DATETIME    
SET @StartDate = DATEADD(mm, DATEDIFF(mm, 0, getdate()) - 1, 0)    
SET @EndDate = dateadd(dd, -1, DATEADD(mm, 1, @StartDate))

SELECT * FROM Member WHERE date_created BETWEEN @StartDate AND @EndDate 

und ein weiteres Upgrade auf die Lösung von mrdenny.
Es gibt auch den genauen letzten Tag des Vormonats an.


0
WHERE 
    date_created >= DATEADD(MONTH, DATEDIFF(MONTH, 31, CURRENT_TIMESTAMP), 0)
    AND date_created < DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP), 0)

Ein bisschen Erklärung?
Cheesemacfly

0

Ich bin von Oracle env und würde es in Oracle so machen:

select * from table
where trunc(somedatefield, 'MONTH') =
trunc(sysdate -INTERVAL '0-1' YEAR TO MONTH, 'MONTH')

Idee: Ich führe einen geplanten Bericht des Vormonats aus (vom ersten Tag bis zum letzten Tag des Monats, ohne Fenster). Dies könnte indexunfreundlich sein, aber Oracle hat sowieso eine schnelle Datumsabwicklung. Gibt es einen ähnlichen einfachen und kurzen Weg in MS SQL? Die Antwort, bei der Jahr und Monat getrennt verglichen werden, erscheint Oracle-Leuten albern.


0

Mit dieser Abfrage können Sie die Datensätze des letzten Monats abrufen

SELECT * FROM dbo.member d 
WHERE  CONVERT(DATE, date_created,101)>=CONVERT(DATE,DATEADD(m, datediff(m, 0, current_timestamp)-1, 0)) 
and CONVERT(DATE, date_created,101) < CONVERT(DATE, DATEADD(m, datediff(m, 0, current_timestamp)-1, 0),101) 

0

Ich denke nicht, dass die akzeptierte Lösung sehr indexfreundlich ist. Ich verwende stattdessen die folgenden Zeilen

select * from dbtable where the_date >= convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120) and the_date <= dateadd(ms, -3, convert(varchar(10),DATEADD(m, 0, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120));

Oder einfach (das ist das Beste).

select * from dbtable where the_date >= convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120) and the_date < SELECT convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120);

Etwas Hilfe

-- Get the first of last month
SELECT convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120);
-- Get the first of current month
SELECT convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120);
--Get the last of last month except the last 3milli seconds. (3miliseconds being used as SQL express otherwise round it up to the full second (SERIUSLY MS)
SELECT dateadd(ms, -3, convert(varchar(10),DATEADD(m, 0, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120));

-1

Auf dem SQL Server für den letzten Monat:

select * from tablename 
where order_date > DateAdd(WEEK, -1, GETDATE()+1) and order_date<=GETDATE()

-1
DECLARE @curDate INT = datepart( Month,GETDATE())
IF (@curDate = 1)
    BEGIN
        select * from Featured_Deal
        where datepart( Month,Created_Date)=12 AND datepart(Year,Created_Date) = (datepart(Year,GETDATE())-1)

    END
ELSE
    BEGIN
        select * from Featured_Deal
        where datepart( Month,Created_Date)=(datepart( Month,GETDATE())-1) AND datepart(Year,Created_Date) = datepart(Year,GETDATE())

    END 

-1
DECLARE @StartDate DATETIME, @EndDate DATETIME
SET @StartDate = dateadd(mm, -1, getdate())
SET @StartDate = dateadd(dd, datepart(dd, getdate())*-1, @StartDate)
SET @EndDate = dateadd(mm, 1, @StartDate)
set @StartDate = DATEADD(dd, 1 , @StartDate)

-1

Ich habe ein ähnliches Problem behoben, indem ich meinem SELECT- Teil Month hinzugefügt habe

Month DATEADD(day,Created_Date,'1971/12/31') As Month

und als ich WHERE Anweisung hinzugefügt habe

Month DATEADD(day,Created_Date,'1971/12/31') = month(getdate())-1

-1

Wenn Sie nach dem letzten Monat suchen, versuchen Sie dies,

SELECT
FROM  #emp 
WHERE DATEDIFF(MONTH,CREATEDDATE,GETDATE()) = 1

Wenn Sie nach dem letzten Monat suchen, versuchen Sie dies,

SELECT
FROM #emp
WHERE DATEDIFF(day,CREATEDDATE,GETDATE()) between 1 and 30

1
Bitte lesen Sie die vorherigen Antworten, um zu sehen, warum dies nicht funktioniert und \ oder nicht die richtige Vorgehensweise, bevor die Leute es ablehnen. Und vielleicht möchten Sie Ihre Antwort entfernen.
Cetin Basoz

Hallo, willkommen bei Stack Overflow. Wenn Sie eine Frage beantworten, die bereits viele Antworten enthält (17!), Geben Sie bitte einen zusätzlichen Einblick, warum die von Ihnen bereitgestellte, hastig verfasste Antwort inhaltlich ist und nicht nur das wiedergibt, was bereits vom Originalplakat überprüft wurde. Dies ist besonders wichtig bei "Nur-Code" -Antworten wie Ihrer.
chb

-1

Eine einfache Abfrage, die für mich funktioniert, ist:

Wählen Sie * aus der Tabelle aus, in der DATEADD (Monat, 1, DATEFIELD)> = getdate ()


-1

Wenn Sie nach Daten des Vormonats suchen:

date(date_created)>=date_sub(date_format(curdate(),"%Y-%m-01"),interval 1 month) and 
date(date_created)<=date_sub(date_format(curdate(),'%Y-%m-01'),interval 1 day)

Dies funktioniert auch, wenn sich das Jahr ändert. Es wird auch auf MySQL funktionieren.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.