2012-05-01 6 views
14
declare @str_datetime varchar(50) 
set @str_datetime='30-04-2012 19:01:45' -- 30th April 2012 
declare @dt_datetime datetime 
select @[email protected]_datetime 

To daje następujący błąd:W jaki sposób SQL Server decyduje o formacie niejawnej konwersji datetime?

Msg 242, Level 16, State 3, Line 4
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.

Moje pytanie brzmi: w jaki sposób SQL Server zdecyduje, który format do wykorzystania na niejawna konwersja datetime?

Odpowiedz

23

Może to zależeć od wielu czynników - ustawień regionalnych systemu operacyjnego, języka bieżącego użytkownika i ustawień formatu daty. Domyślnie system Windows używa US English, a ustawienia użytkownika to US English i MDY.

Ale oto kilka przykładów pokazujących, jak to się może zmienić.

użytkownik korzysta brytyjskich ustawień językowych:

-- works: 
SET LANGUAGE BRITISH; 
SELECT CONVERT(DATETIME, '30-04-2012 19:01:45'); 

-- fails: 
SELECT CONVERT(DATETIME, '04/13/2012'); 
GO 

(Błąd)

Msg 242, Level 16, State 3, Line 5
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.

użytkownik korzysta Francais:

-- works: 
SET LANGUAGE FRENCH; 
SELECT CONVERT(DATETIME, '30-04-2012 19:01:45'); 

-- fails: 
SELECT CONVERT(DATETIME, '04/13/2012'); 
GO 

(Błąd)

Msg 242, Level 16, State 3, Line 1
La conversion d'un type de données varchar en type de données datetime a créé une valeur hors limites.

użytkownika jest ponownie przy użyciu Francais:

SET LANGUAGE FRENCH; 

-- fails (proving that, contrary to popular belief, YYYY-MM-DD is not always safe): 
SELECT CONVERT(DATETIME, '2012-04-30'); 
GO 

(błąd)

Msg 242, Level 16, State 3, Line 1
La conversion d'un type de données varchar en type de données datetime a créé une valeur hors limites.

użytkownik stosuje DMY zamiast MDY:

SET LANGUAGE ENGLISH; 
SET DATEFORMAT DMY; 

-- works: 
SELECT CONVERT(DATETIME, '30-04-2012 19:01:45'); 

-- fails: 
SELECT CONVERT(DATETIME, '04-30-2012'); 
GO 

(błąd)

Msg 242, Level 16, State 3, Line 2
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.

Zawsze najlepiej jest używać standardowych, nieregionalnych, bezpiecznych i jednoznacznych formatów daty ISO. Obaj ja zwykle zalecane są:

YYYYMMDD     - for date only. 
YYYY-MM-DDTHH:MM:SS[.mmm] - for date + time, and yes that T is important. 

Żaden z nich nie:

SET DATEFORMAT MDY; 
SET LANGUAGE ENGLISH; 
SELECT CONVERT(DATETIME, '20120430'); 
SELECT CONVERT(DATETIME, '2012-04-30T19:01:45'); 
SET LANGUAGE FRENCH; 
SELECT CONVERT(DATETIME, '20120430'); 
SELECT CONVERT(DATETIME, '2012-04-30T19:01:45'); 
SET LANGUAGE BRITISH; 
SELECT CONVERT(DATETIME, '20120430'); 
SELECT CONVERT(DATETIME, '2012-04-30T19:01:45'); 
SET DATEFORMAT DMY; 
SELECT CONVERT(DATETIME, '20120430'); 
SELECT CONVERT(DATETIME, '2012-04-30T19:01:45'); 

Dlatego zalecamy zamiast pozwolić użytkownikom wpisać w wolnych formatów daty tekst (lub użyć zawodne formatów siebie), kontroluj swoje ciągi wejściowe i upewnij się, że są zgodne z jednym z tych bezpiecznych formatów. Wtedy nie będzie miało znaczenia, jakie ustawienia ma użytkownik lub jakie są ustawienia regionalne, twoje daty będą zawsze interpretowane jako daty, w których miały być.Jeśli obecnie pozwalasz użytkownikom wprowadzać daty w polu tekstowym formularza, przestań to robić i zaimplementuj kontrolkę kalendarza lub przynajmniej listę wyboru, aby ostatecznie kontrolować format ciągu, który jest przekazywany do SQL Server.

jakiegoś tle, proszę przeczytać Tibor Karaszi na "The ultimate guide to the datetime datatypes" i mój post "Bad Habits to Kick : Mis-handling date/range queries."

+0

Zobacz moją odpowiedź [tutaj] (http://stackoverflow.com/a/23369706/2108149), jak to zrobić w ramach funkcji zdefiniowanej przez użytkownika. –

+2

@ Eli Myślę, że brakuje ci punktu, który próbowałem stworzyć. Jeśli jedna osoba przebywa w Anglii i ma napis "09/04/2014", a inna osoba przebywa w USA i mija rok "09/04/2014", w jaki sposób twoja funkcja w magiczny sposób wie, który z nich oznaczał 9 kwietnia, a który oznaczało 4 września? –

+0

Muszę przyznać, że nie przeczytałem całej twojej nitki, szukałem miesięcznego rozwiązania tłumaczeniowego i gdy go szukałem natknąłem się na twoją odpowiedź, więc pomyślałem, że niektórym ludziom może się to przydać ... –

1

By default, the date format for SQL server is in U.S. date format MM/DD/YY, unless a localized version of SQL Server has been installed. This setting is fine for cases when an application that requires this functionality is deployed in a manner guaranteeing that dates are used and inserted in the same format across all platforms and locations where the application is used.

However, in some cases the date must be in a DD/MM/YY format because many countries/regions use this format rather than the U.S. default of MM/DD/YY. This is especially an issue for international applications that are distributed all over the world.

Source

Więc co trzeba zrobić, to ustawić format daty przed strony jako tak:

SET DATEFORMAT dmy 
GO 

A potem zapytanie będzie działać.

+0

... dopóki ktoś nie użyje innego formatu. –

+1

@AaronBertrand Prawidłowo. Czy istnieje nieomylne podejście do radzenia sobie z tym w SQL? Mam na myśli, otrzymując ciąg reprezentujący datę w dowolnym formacie i dokonujący konwersji bezpiecznie, bez żadnej nieprzyjemnej logiki? – Icarus

+1

Nie, nie ma. Musisz kontrolować ciąg wejściowy. Jeśli użytkownik przekaże hasło "05/06/2012", ponieważ może je wpisać w dowolnym formacie, w jaki sposób SQL Server w sposób niezawodny określi, czy użytkownik miał na myśli 6 maja, czy 5 czerwca? –

1

Można również zmienić de domyślnego formatu daty dla każdego logowania i/lub dla siebie przyszłość dodanych loginy (bez potrzeby robić „SET dateformat” w każdej sesji.

iść w SQL Management Studio/Bezpieczeństwo/logowania. prawym clic logowania, a następnie Właściwości. Zobaczysz „Domyślny język” u dołu.

Jeśli chcesz się upewnić, dowolny loginy dodane w przyszłości uzyskują "dobry" język. Kliknij prawym przyciskiem myszy na głównym serwerze, a następnie na stronie Właściwości i Zaawansowane. Istnieje również opcja "Default Language", która jest używana do nowo utworzonych loginów.

+0

ty nie powinien tylko komentować "dziękuję" tutaj ... ale muszę, więc: dzięki. – Steen