Alle vorhandenen (funktionierenden) Antworten haben eines von zwei Problemen:
- Sie ignorieren Indizes in der durchsuchten Spalte
- Der wird (möglicherweise) Daten auswählen, die nicht beabsichtigt sind, und Ihre Ergebnisse stillschweigend verfälschen.
1. Ignorierte Indizes:
Wenn für eine zu durchsuchende Spalte eine Funktion aufgerufen wird (einschließlich implizit, wie für CAST
), muss der Optimierer 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 neigen dazu, diese Informationen als ansteigenden Wert zu speichern, normalerweise als long
oder BIGINTEGER
Anzahl Milli-/Nanosekunden. Die aktuelle Uhrzeit sieht also so aus/wird gespeichert:
1402401635000000 -- 2014-06-10 12:00:35.000000 GMT
Der Wert für das Jahr wird nicht angezeigt ('2014'
). ) da drin, oder? Tatsächlich gibt es einiges an komplizierter Mathematik, die hin und her übersetzt werden muss. Wenn Sie also eine der Extraktions-/Datumsteilfunktionen für die gesuchte Spalte aufrufen, muss der Server all diese Berechnungen durchführen, nur 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 einer immer größeren Belastung. Dann tun Sie es in diesem Fall ein zweites Mal, um nach MONTH
zu fragen ... gut, Sie bekommen das Bild.
2. Unbeabsichtigte Daten:
Abhängig von der jeweiligen Version von SQL Server und den Spaltendatentypen mit BETWEEN
(oder ähnliche einschließliche Obergrenzenbereiche:<=
) kann dazu führen, dass die falschen Daten ausgewählt werden. Im Wesentlichen schließen Sie möglicherweise Daten ab Mitternacht des „nächsten“ Tages ein oder schließen einen Teil der Datensätze des „aktuellen“ Tages aus.
Was Sie sollten tun:
Wir brauchen also einen Weg, der für unsere Daten sicher ist, und verwenden Indizes (falls möglich). Der korrekte Weg hat dann die Form:
WHERE date_created >= @startOfPreviousMonth AND date_created < @startOfCurrentMonth
Da es nur einen Monat gibt, @startOfPreviousMonth
kann einfach ersetzt/abgeleitet werden von:
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)
Hier ein kurzes Wort zur Erklärung. Das anfängliche DATEDIFF(...)
erhält die Differenz zwischen dem Beginn der aktuellen Ära (0001-01-01
- AD, CE, was auch immer), im Wesentlichen eine große Ganzzahl zurückgeben. Dies ist die Anzahl der Monate bis zum Beginn des aktuellen Monat. Wir addieren diese Zahl dann zum Beginn des Zeitalters, das am Beginn des angegebenen Monats liegt.
Ihr vollständiges Skript könnte/sollte also etwa so 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 somit nur einmal auf einem Wert durchgeführt; Der Optimierer kann Indizes frei verwenden, und es werden keine falschen Daten aufgenommen.