Najlepsze podejście do usuwania części czasowej datetime w SQL Server

Która metoda zapewnia najlepszą wydajność przy usuwaniu porcji czasu z pola datetime w SQL Server?

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

Lub

b) select cast(convert(char(11), getdate(), 113) as datetime)

Druga metoda wysyła kilka bajtów w obie strony, ale może to nie być tak ważne jak szybkość konwersji.

Oba wydają się być bardzo szybkie, ale może być różnica w prędkości, gdy mamy do czynienia z setkami tysięcy lub więcej wierszy?

Również, czy jest możliwe, że istnieją jeszcze lepsze metody, aby uzyskać pozbycie się części czasowej datetime w SQL?

Author: gbn, 2009-07-24

23 answers

Ściśle, Metoda a jest najmniej zasobochłonna:

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

Udowodniono mniej intensywne CPU dla tego samego całkowitego czasu trwania miliona wierszy przez kogoś, kto ma zbyt dużo czasu na ręce: najbardziej efektywny sposób w SQL Server, aby uzyskać datę Z daty+czasu?

Widziałem podobny test gdzie indziej z podobnymi wynikami.

Wolę DATEADD / DATEDIFF ponieważ:

    Varchar jest przedmiotem problemów językowych / dateformatowych
    Przykład: Why is my CASE wyrażenie niedeterministyczne?
  • float opiera się na pamięci wewnętrznej
  • rozszerza się do pracy pierwszego dnia miesiąca, jutro itp zmieniając bazę " 0 "

Edit, Październik 2011

Dla SQL Server 2008+, można wrzucić do date. Lub po prostu użyj date, aby nie mieć czasu na usunięcie.

Edit, Styczeń 2012

Przykład jak elastyczny to jest: trzeba obliczyć za pomocą zaokrąglonej liczby czasu lub daty w sql server

Edytuj, Maj 2012

Nie używaj tego w przypadku, gdy klauzule i tym podobne bez myślenia: dodanie funkcji lub CAST do kolumny unieważnia użycie indeksu. Zobacz numer 2 tutaj: http://www.simple-talk.com/sql/t-sql-programming/ten-common-sql-programming-mistakes/

Teraz, to ma przykład późniejszych wersji SQL Server Optimizer zarządzanie CAST do tej pory poprawnie, ale ogólnie to będzie zły pomysł ...

Edit, wrz 2018, dla datetime2

DECLARE @datetime2value datetime2 = '02180912 11:45' --this is deliberately within datetime2, year 0218
DECLARE @datetime2epoch datetime2 = '19000101'

select DATEADD(dd, DATEDIFF(dd, @datetime2epoch, @datetime2value), @datetime2epoch)
 486
Author: gbn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-19 19:26:52

W SQL Server 2008 możesz użyć:

CONVERT(DATE, getdate(), 101)
 52
Author: Anto Raja Prakash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-09 06:49:53

Oczywiście, że jest to stary wątek, ale żeby go uzupełnić.

Z SQL 2008 można użyć datatype więc można po prostu zrobić:

SELECT CONVERT(DATE,GETDATE())
 33
Author: Arjan Fraaij,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-06 13:05:14
SELECT CAST(FLOOR(CAST(getdate() AS FLOAT)) AS DATETIME)
 19
Author: Gary McGill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-24 12:57:54

W SQL Server 2008 istnieje Typ daty (również Typ daty czasu).

CAST(GetDate() as DATE)

Lub

declare @Dt as DATE = GetDate()
 12
Author: Metaphor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-03 22:54:13

Oto kolejna odpowiedź, z innego duplicate question:

SELECT CAST(CAST(getutcdate() - 0.50000004 AS int) AS datetime) 

Ta metoda liczb magicznych działa nieco szybciej niż metoda DATEADD. (Wygląda na ~10%)

Czas procesora na kilku rundach miliona rekordów:

DATEADD   MAGIC FLOAT
500       453
453       360
375       375
406       360

Ale zauważ, że te liczby są prawdopodobnie nieistotne, ponieważ są już bardzo szybkie. Chyba że miałem zestawy rekordów 100,000 lub więcej, nie mogłem nawet uzyskać czasu procesora do odczytu powyżej zera.

Biorąc pod uwagę fakt, że DateAdd jest przeznaczony do tego celu i jest bardziej wytrzymały, powiedziałbym użyć DateAdd.
 8
Author: Jeff Meatball Yang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:50
SELECT CAST(CAST(GETDATE() AS DATE) AS DATETIME)
 5
Author: Byju,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-03 13:55:00

Czas na wstawki/aktualizacje w pierwszej kolejności. Jeśli chodzi o konwersję on-the-fly, nic nie jest w stanie pokonać funkcji zdefiniowanej przez użytkownika]}

select date_only(dd)

Implementacja date_only może być dowolna - teraz jest abstrakcyjna, a kod wywołujący jest dużo czystszy.

 2
Author: Anton Gogolev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-24 12:55:14

Zobacz to pytanie:
Jak mogę obciąć datetime w SQL Server?

Cokolwiek robisz, nie używaj metody string . To najgorszy sposób, w jaki mogłeś to zrobić.

 2
Author: Joel Coehoorn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:32

Już odebrałem, ale to też wyrzucę... to również preformuje się dobrze, ale działa poprzez wyrzucenie dziesiętnego (który przechowuje czas) z float i zwrócenie tylko całej części (która jest datą)

 CAST(
FLOOR( CAST( GETDATE() AS FLOAT ) )
AS DATETIME
)

Po raz drugi znalazłem to rozwiązanie... zdjąłem ten kod

 2
Author: Carter Cole,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-09 16:06:45
CAST(round(cast(getdate()as real),0,1) AS datetime)

Ta metoda nie używa funkcji string. Date jest w zasadzie rzeczywistym typem danych z cyframi przed dziesiętnym ułamkiem dnia.

To chyba będzie szybsze niż wiele.
 2
Author: shantanu singh chauhan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-18 14:10:25

Dla mnie poniższy kod jest zawsze zwycięzcą:

SELECT CONVERT(DATETIME, FLOOR(CONVERT(FLOAT,GETDATE())));
 2
Author: user1920017,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-20 21:20:31

Uważaj!

Metoda a) i b) nie zawsze ma taki sam wynik!

select DATEADD(dd, DATEDIFF(dd, 0, '2013-12-31 23:59:59.999'), 0)

Wyjście: 2014-01-01 00:00:00.000

select cast(convert(char(11), '2013-12-31 23:59:59.999', 113) as datetime)

Wyjście: 2013-12-31 00:00:00.000

(testowane na MS SQL Server 2005 i 2008 R2)

EDIT: zgodnie z komentarzem Adama, nie może się to zdarzyć, jeśli odczytasz wartość daty z tabeli, ale może się zdarzyć, jeśli podasz wartość daty jako literalną (przykład: jako parametr procedury składowanej wywołanej przez ADO.NET).

 2
Author: broslav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-22 14:01:46

Select CONVERT(char (10), GetDate (), 126)

 2
Author: Diego,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-10 14:11:33

Bardzo mi się podoba:

[date] = CONVERT(VARCHAR(10), GETDATE(), 120)

Kod formatu 120 wprowadzi datę do normy ISO 8601:

'YYYY-MM-DD' or '2017-01-09'

Super łatwy w użyciu w dplyr (R) i pandy (Python)!

 2
Author: emehex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-10 17:58:09

Myślę, że masz na myśli cast(floor(cast(getdate()as float))as datetime)

Real jest tylko 32-bitowy i może stracić pewne informacje

To jest najszybsze cast(cast(getdate()+x-0.5 as int)as datetime)

...choć tylko o 10% szybciej (about 0.49 microseconds CPU vs. 0.58)

To było zalecane, i zajmuje ten sam czas w moim teście właśnie teraz: DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

[[5]} w SQL 2008, funkcja SQL CLR jest około 5 razy szybciej niż przy użyciu funkcji SQL byłoby, na 1.35 mikrosekundy w porównaniu do 6.5 mikrosekundy, co wskazuje znacznie niższy narzut wywołania funkcji SQL CLR w porównaniu do prostego SQL UDF.

W SQL 2005, funkcja SQL CLR jest 16 razy szybsza, na moje testy, w porównaniu z tą powolną funkcją:

create function dateonly (  @dt datetime )
returns datetime
as
begin
return cast(floor(cast(@dt as float))as int)
end
 1
Author: Aaron West,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-26 04:37:36

A może select cast(cast my_datetime_field as date) as datetime)? Skutkuje to tą samą datą, z czasem ustawionym na 00: 00, ale unika konwersji na tekst, a także unika jawnego zaokrąglania liczb.

 1
Author: Dr. Drew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-24 08:52:41

Myślę, że jeśli trzymać się ściśle TSQL, to jest to najszybszy sposób na skrócenie czasu:

 select convert(datetime,convert(int,convert(float,[Modified])))

Okazało się, że ta metoda okrojenia jest o 5% szybsza niż metoda DateAdd. A to można łatwo zmodyfikować do rundy do najbliższego dnia w ten sposób:

select convert(datetime,ROUND(convert(float,[Modified]),0))
 1
Author: Jamie G,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-26 16:53:03

Tutaj zrobiłem funkcję do usuwania niektórych części datetime dla SQL Server. Sposób użycia:

  • Pierwszy param jest datetime do usunięcia.
  • Second param is a char:
    • s: zaokrągla do sekund; usuwa milisekundy
    • m: zaokrągla do minut; usuwa sekundy i milisekundy
    • h: rund do godzin; usuwa minuty, sekundy i milisekundy.
    • d: rund do dni; usuwa godziny, minuty, sekundy i milisekundy.
  • zwraca nowy datetime

create function dbo.uf_RoundDateTime(@dt as datetime, @part as char) returns datetime as begin if CHARINDEX( @part, 'smhd',0) = 0 return @dt; return cast( Case @part when 's' then convert(varchar(19), @dt, 126) when 'm' then convert(varchar(17), @dt, 126) + '00' when 'h' then convert(varchar(14), @dt, 126) + '00:00' when 'd' then convert(varchar(14), @dt, 112) end as datetime ) end

 1
Author: Max Vargas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-26 17:07:58

Na wypadek, gdyby ktoś szukał tutaj wersji Sybase, ponieważ kilka powyższych wersji nie działało

CAST(CONVERT(DATE,GETDATE(),103) AS DATETIME)
  • testowany w I SQL v11 uruchomiony na Adaptive Server 15.7
 1
Author: Alan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-31 01:32:38

Jeśli to możliwe, do specjalnych rzeczy takich jak ta, lubię używać funkcji CLR.

W tym przypadku:

[Microsoft.SqlServer.Server.SqlFunction]
    public static SqlDateTime DateOnly(SqlDateTime input)
    {
        if (!input.IsNull)
        {
            SqlDateTime dt = new SqlDateTime(input.Value.Year, input.Value.Month, input.Value.Day, 0, 0, 0);

            return dt;
        }
        else
            return SqlDateTime.Null;
    }
 0
Author: tjeuten,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-13 14:40:19

Ja osobiście prawie zawsze używam funkcji zdefiniowanych przez użytkownika do tego, jeśli chodzi o SQL Server 2005 (lub niższą wersję), należy jednak zauważyć, że istnieją pewne wady korzystania z UDF, zwłaszcza jeśli stosuje się je do klauzul WHERE(patrz poniżej i komentarze na tej odpowiedzi dla dalszych szczegółów). Jeśli używasz SQL Server 2008 ( lub nowszego) - patrz poniżej.

W rzeczywistości, dla większości baz danych, które tworzę, dodaję te UDF tuż przy starcie, ponieważ Wiem, że jest 99% szansa, że prędzej czy później będę ich potrzebował.

Tworzę jeden dla "tylko Data" & " tylko czas "(chociaż" tylko Data " jeden jest zdecydowanie najczęściej używany z dwóch).

Oto kilka linków do różnych UDF związanych z datą:

Podstawowe funkcje daty, czasu i DateTime serwera SQL
Get date Only Function

Ten ostatni link pokazuje nie mniej niż 3 różne sposoby uzyskania daty tylko część pola datetime i wymienia kilka zalet i wad każde podejście.

Jeśli używasz UDF, należy zauważyć, że powinieneś unikać używania UDF jako części klauzuli WHERE w zapytaniu, ponieważ znacznie utrudni to wykonanie zapytania. Głównym powodem tego jest to, że użycie UDF w klauzuli WHERE renderuje tę klauzulę jako non-sargable, co oznacza, że SQL Server nie może już używać indeksu z tą klauzulą w celu zwiększenia szybkości wykonywania zapytań. W odniesieniu do mojego własnego wykorzystania UDF, będę często używać kolumna daty "surowa" w klauzuli WHERE, ale zastosuj UDF do wybranej kolumny. W ten sposób UDF jest stosowany tylko do przefiltrowanego zestawu wyników, a nie do każdego wiersza tabeli jako część filtra.

Oczywiście, absolutnym najlepszym podejściem jest użycie SQL Server 2008 (lub wyższej) i oddzielenie dat i czasów, ponieważ silnik bazy danych SQL Server natywnie dostarcza poszczególne składniki daty i czasu i może skutecznie odpytywać te dane. niezależnie, bez potrzeby stosowania UDF lub innego mechanizmu do wyodrębniania części daty lub czasu z kompozytowego typu datetime.

 0
Author: CraigTP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-30 14:48:29

Użyłbym:

CAST
(
CAST(YEAR(DATEFIELD) as varchar(4)) + '/' CAST(MM(DATEFIELD) as varchar(2)) + '/' CAST(DD(DATEFIELD) as varchar(2)) as datetime
) 

W ten sposób skutecznie tworzysz nowe pole z pola daty, które już posiadasz.

 -3
Author: Jabu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-19 12:33:49