sql >> Databasteknik >  >> RDS >> Sqlserver

Hämta uppgifterna från förra månaden i SQL-servern

Alla befintliga (fungerande) svar har ett av två problem:

  1. De kommer att ignorera index i kolumnen som söks igenom
  2. Kommer (potentiellt) att välja data som inte är avsedd, vilket i tysthet korrumperar dina resultat.

1. Ignorerade index:

För det mesta, när en kolumn som söks igenom har en funktion anropad (inklusive implicit, som för CAST ), måste optimeraren ignorera index i kolumnen och söka igenom varje post. Här är ett snabbt exempel:

Vi har att göra med tidsstämplar, och de flesta RDBMS:er tenderar att lagra denna information som ett ökande värde av något slag, vanligtvis en long eller BIGINTEGER antal milli-/nanosekunder. Den aktuella tiden ser alltså ut/lagras så här:

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

Du ser inte värdet 'År' ('2014'). ) där inne, gör du? Det finns faktiskt en hel del komplicerad matematik att översätta fram och tillbaka. Så om du anropar någon av funktionerna för extraktion/datumdel i den sökta kolumnen måste servern utföra all den matematiken bara för att ta reda på om du kan inkludera den i resultaten. På små tabeller är detta inte ett problem, men när andelen rader som valts minskar blir detta ett större och större avlopp. I det här fallet gör du det en andra gång för att fråga om MONTH ... ja, ni förstår bilden.

2. Oavsiktlig data:

Beroende på den specifika versionen av SQL Server och kolumndatatyper, med BETWEEN (eller liknande inklusive övre gränsintervall:<= ) kan resultera i att fel data väljs. I grund och botten kan det sluta med att du inkluderar data från midnatt "nästa" dag, eller exkluderar någon del av den "aktuella" dagens register.

Vad du bör gör:

Så vi behöver ett sätt som är säkert för vår data och kommer att använda index (om det är genomförbart). Det korrekta sättet är då av formen:

WHERE date_created >= @startOfPreviousMonth AND date_created < @startOfCurrentMonth

Med tanke på att det bara är en månad, @startOfPreviousMonth kan enkelt ersättas med/härledas av:

DATEADD(month, -1, @startOCurrentfMonth)

Om du behöver härleda start-of-current-month i servern kan du göra det via följande:

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

Ett snabbt ord av förklaring här. Den initiala DATEDIFF(...) kommer att få skillnaden mellan början av den nuvarande eran (0001-01-01 - AD, CE, vad som helst), returnerar i huvudsak ett stort heltal. Detta är antalet månader till början av aktuellt månad. Vi lägger sedan till detta nummer till början av eran, som är i början av den givna månaden.

Så ditt fullständiga skript kan/bör se ut som följande:

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

Alla datumoperationer utförs alltså bara en gång, på ett värde; Optimizern är gratis att använda index, och inga felaktiga data kommer att inkluderas.



  1. JSON_TYPE() – Få en JSON-värdestyp i MySQL

  2. ORACLE SQL*Plus handledning

  3. Flerradsskär med pg-löfte

  4. Hur man uppgraderar MySQL 5.5 till 5.6 på Ubuntu 14.04