Konwersja pola datetime serwera SQL, aby porównać tylko data części, z indeksowanych wyszukiwań

głosy
28

Byłem robi convert(varchar,datefield,112)na każdym polu daty, które używam w „między” kwerend w serwerze SQL, aby upewnić się, że mam co stanowi jedynie dla dat i nie brakuje dowolne oparte na część czasu datetime pól.

Teraz słyszę, że konwertyci nie są indeksowane i że są lepsze sposoby, w SQL Server 2005 i porównać datę część datetimes w zapytaniu w celu określenia czy daty spaść w zasięgu.

Jaka jest optymalna, wiertła, sposób robi coś takiego:

select * from appointments
where appointmentDate>='08-01-2008' and appointmentDate<'08-15-2008'
Utwórz 09/12/2008 o 15:59
źródło użytkownik
W innych językach...                            


5 odpowiedzi

głosy
65

Najlepszym sposobem, aby rozebrać część czasową pola datetime korzysta DateDiff i funkcje DateAdd.

   DateAdd(day, datediff(day,0, MydateValue), 0)

Dzieje advantedge fakt, że sklepy SQL Server terminach dwóch liczb całkowitych, jeden reprezentujący liczbę dni od pierwszego dnia „0” - (1 stycznia 1900), a drugi, który reprezentuje liczbę kleszczy (każdy kleszcz jest około 3,33 ms ) od północy (na czas) *.

formuła powyżej prostu musi jedynie przeczytać pierwszy całkowitą. Nie ma konwersji lub przetwarzania, a więc jest bardzo szybki.

Aby dokonać kwerendy użyć indeksu ... skorzystać z tej formuły na wejściu filtrowania parametrów pierwszy, lub na „drugiej” stronie znaku równości z pola data godzina stoły tak, że optymalizator kwerendy nie trzeba uruchamiać obliczenia na każdym polu datetime w tabeli, aby określić, które wiersze spełniają predykat filtru. To sprawia, że ​​wyszukiwanie argument "SARG-stanie" (Search argument)

Where MyDateTimeColumn > DateAdd(day, 
      datediff(day,0, @MydateParameter), 0)    -- SARG-able

zamiast

Where DateAdd(day, datediff(day,0, 
      MyDateTimeColumn ), 0) > @MydateParameter -- Not SARG-able

* UWAGA. Wewnątrz, drugie całkowitą (część czasu) przechowuje kleszczy. W ciągu dnia są 24 x 60 x 60 x 300 = 25,920,000 kleszcze (nieoczekiwanie poniżej wartości maksymalnej 32 bitowy może posiadać). Jednak nie trzeba się martwić o to, gdy arytmetycznie modyfikacji datetime ... Dodając lub odejmując wartości od datetimes można traktować jako ułamek wartości, jak gdyby to była dokładnie równa ułamkowej części dnia, jak gdyby pełna wartość datetime była liczba rzeczywista, składający się z części całkowitej reprezentujący datę i części ułamkowej reprezentujący czas). to znaczy,

`Declare @Dt DateTime  Set @Dt = getdate()  
 Set @Dt = @Dt + 1.0/24  -- Adds one hour  
 Select @Dt  
 Set @Dt = @Dt - .25 -- Moves back 6 hours  
 Select @Dt`
Odpowiedział 09/12/2008 o 16:07
źródło użytkownik

głosy
5

Konwersja typów numerycznych do wartości ciągów (typ Boxing) nie jest najlepszym sposobem wykonywania robi to, czego szukasz. Jej naprawdę nie o indeks-stanie, ponieważ rzeczywisty typ kolumna jest czas, data.

Jeśli szukasz najlepszego zapytania drogę do dat, to Twój przykład jest w porządku, ale może warto wziąć pod uwagę różnicę precyzję 3 ms w MSSQL. To może oznaczać, że zapisy z jednego dnia można pokazać się w innym dniu rezultatu.

To

select * from appointments where appointmentDate>='08-01-2008' and appointmentDate<'08-15-2008'

Powinno być to

select * from appointments where appointmentDate>='08-01-2008' and appointmentDate<='08-14-2008 23:59:59.996'
Odpowiedział 09/12/2008 o 16:11
źródło użytkownik

głosy
2

Jest to poprawne - robi konwersję wykona konwersję każdego wiersza odpytywany. Lepiej zostawić kolumny dat jak daty i przekazać w swoich WHERE jak terminach:

select * from appointments where appointmentdate between 
'08/01/2008' AND '08/16/2008'

Uwaga: Pozostawienie off czas oznacza północy (00: 00.000), więc będzie zawierać wszystkie czasy dla 08/01 i wszystkie razy z 08/15, a wszystko to jest dokładnie 16.08.2008 00:00:00

Odpowiedział 09/12/2008 o 16:06
źródło użytkownik

głosy
1

Mają obliczane utrzymywały kolumna obliczyć wyrażenie potrzeba. Jeśli kolumny są obliczane i utrzymywały, mogą być również indeksowane.

Odpowiedział 09/12/2008 o 16:10
źródło użytkownik

głosy
0

Istnieje również sposób opisany w http://www.stillnetstudios.com/comparing-dates-without-times-in-sql-server/

SELECT CAST(FLOOR(CAST( getdate() AS float )) AS datetime)
Odpowiedział 28/09/2011 o 13:31
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more