sql >> Database teknologi >  >> RDS >> Sqlserver

Få optegnelser fra sidste måned i SQL server

Alle de eksisterende (fungerende) svar har et af to problemer:

  1. De vil ignorere indekser i den kolonne, der søges i
  2. Det vil (potentielt) vælge data, der ikke er tilsigtet, hvilket i det stille ødelægger dine resultater.

1. Ignorerede indekser:

For det meste, når en kolonne, der søges i, har en funktion kaldet på sig (inklusive implicit, som for CAST ), skal optimeringsværktøjet ignorere indekser i kolonnen og søge gennem hver post. Her er et hurtigt eksempel:

Vi har at gøre med tidsstempler, og de fleste RDBMS'er har en tendens til at gemme denne information som en stigende værdi af en eller anden art, normalt en long eller BIGINTEGER antal milli-/nanosekunder. Det aktuelle klokkeslæt ser således ud/lagres således:

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

Du kan ikke se 'År'-værdien ('2014' ) derinde, gør du? Faktisk er der en del kompliceret matematik at oversætte frem og tilbage. Så hvis du kalder nogen af ​​funktionerne til ekstraktion/dato-delen i den søgte kolonne, skal serveren udføre al den matematik for at finde ud af, om du kan inkludere den i resultaterne. På små borde er dette ikke et problem, men efterhånden som procentdelen af ​​udvalgte rækker falder, bliver dette et større og større dræn. Så i dette tilfælde gør du det en anden gang for at spørge om MONTH ... ja, du forstår billedet.

2. Utilsigtede data:

Afhængigt af den særlige version af SQL Server og kolonnedatatyper, ved hjælp af BETWEEN (eller lignende inklusive øvre grænseområder:<= ) kan resultere i, at de forkerte data bliver valgt. Grundlæggende ender du potentielt med at inkludere data fra midnat den "næste" dag eller ekskludere en del af den "aktuelle" dags registreringer.

Hvad du bør gør:

Så vi har brug for en måde, der er sikker for vores data og vil bruge indekser (hvis det er levedygtigt). Den korrekte måde er så af formen:

WHERE date_created >= @startOfPreviousMonth AND date_created < @startOfCurrentMonth

Da der kun er én måned, @startOfPreviousMonth kan nemt erstattes/afledes af:

DATEADD(month, -1, @startOCurrentfMonth)

Hvis du skal udlede start-of-current-month i serveren, kan du gøre det via følgende:

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

En hurtig forklaring her. Den initiale DATEDIFF(...) vil få forskellen mellem begyndelsen af ​​den nuværende æra (0001-01-01 - AD, CE, hvad som helst), hvilket i det væsentlige returnerer et stort heltal. Dette er antallet af måneder til starten af ​​den aktuelle måned. Vi tilføjer derefter dette nummer til starten af ​​æraen, som er i starten af ​​den givne måned.

Så dit fulde script kunne/bør ligne følgende:

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 datooperationer udføres således kun én gang, på én værdi; optimeringsværktøjet er gratis at bruge indekser, og der vil ikke blive inkluderet forkerte data.



  1. SQLite ER NULL

  2. Fuld forståelse for PDO ATTR_PERSISTENT

  3. PL/SQL, hvordan undslipper man et enkelt citat i en streng?

  4. Virkningen af ​​query_post_execution_showplan Extended Event i SQL Server 2012