2013-04-16 12 views
7

ja modyfikację zapytania, tu jest mój skrypt:W jaki sposób SQL Server porównuje datę z literałem łańcuchowym?

select 
CASE When EndDate='1/1/1900' 
THEN NULL 
ELSE EndDate END,* 
from Members 

Ten skrypt po prostu porównuje datę, jeśli jest to „01.01.1900”, a następnie powraca null inaczej zwraca datę.

widzę w dacie mojego bazy danych są przechowywane w następującym formacie:

1900-01-01 00:00:00.000 

Pytanie jest jak SQL Server datę takiego dopasowania kiedy mój wzór różni się od zapamiętanej jeden. Również w formacie daty nie przepuszczam elementu czasu.

+0

Spójrz na 'funkcji DATEPART'. Zobacz http://msdn.microsoft.com/en-us/library/aa258265(v=sql.80).aspx –

+2

@ PM77-1 czy przeczytałeś pytanie? –

+0

Cóż ... zrobiłem. Popełniłem błąd. Oznacz to 'CONVERT'. –

Odpowiedz

17

SQL Server konwertuje literał literału, który przechodzisz ('1/1/1900') na wartość datetime z powodu data type precedence (since datetime has higher precedence than string types). Jeśli przekażesz nieprawidłową datę jako ciąg znaków, np. '2/31/1900', otrzymasz błąd konwersji (Msg 242), ponieważ SQL Server nie wie, co oznacza 31 lutego. Nie próbuje dopasować ciąg, który wygląda tak, jak to, co przechodzisz, konwertuje zarówno do wewnętrznej reprezentacji dat (więcej na temat w moim komentarzu).

Gdy mamy do czynienia z datami konkretnie, przestać myśleć o formaciewyjątkiem tego, że kiedy przechodzą literały ciągów, m/d/y (lub jest to, że d/m/y?) Jest straszny Format użyć. Znacznie bezpieczniejsze w użyciu:

YYYYMMDD 

Zapytanie powinno brzmieć:

SELECT CASE When EndDate = '19000101' 
THEN NULL ELSE EndDate END, ...other columns... 
FROM dbo.Members; 

W ten sposób, kiedy przechodzą datę jak 8 września, nie jest źle interpretowane przez SQL Server, innych czytelników, itp Czy 09/08/2013 8 września lub 9 sierpnia? Zależy od tego, w której części świata się znajdujesz, prawda? W twoim przypadku jest to w porządku, ponieważ dzień i miesiąc są takie same, ale nie zawsze tak będzie. Zobacz następujący artykuł:

http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/16/bad-habits-to-kick-mishandling-date-range-queries.aspx

(. Proszę, proszę, proszę przeczytać, że odnośnik w całości)

Wreszcie, jeśli używasz DATETIME/SMALLDATETIME i szukasz wartości z określonego dnia, nie powinieneś używać w ogóle równości, ale raczej zapytania zakresu. Na przykład, aby znaleźć wszystkie wiersze gdzie EndDate przypada na 15 kwietnia 2013 roku, niezależnie od czasu, można by powiedzieć: (. Read this link to understand why you don't want to use BETWEEN here)

WHERE EndDate >= '20130415' 
    AND EndDate < '20130416' 

Jeśli jesteś na SQL Server 2008 lub lepsza, nadal można uzyskać sargability na tej kolumnie z CONVERT, ale jest to rzadki wyjątek - zazwyczaj nie chcesz używać funkcji przeciwko kolumnie.

WHERE CONVERT(DATE, EndDate) = '20130415' 

Kilka innych uwag - nie są bezpośrednio związane z danym pytaniem, ale peryferyjne obserwacje o kodzie:

  1. Always use the schema prefix
  2. Never use SELECT * in production
+0

dzięki za udział w moim pytaniu. Co masz na myśli przez "przestań myśleć o formacie"? Czy masz na myśli zapisaną datę dla serwera sql, to jest to samo, gdy wprowadziłem datę dla dopasowania 1/2/1900 lub 2/1/1900 lub 1900/2/1, a nawet 1900/1/2? Czy możesz to wyjaśnić. – user576510

+4

Mam na myśli to, że SQL Server nie * przechowuje * twojej daty w formacie czytelnym dla ludzi, który twoim zdaniem robi. Przechowuje on datę wewnętrznie jako dwie liczby całkowite reprezentujące odpowiednio dzień i godzinę. Kiedy przekazujesz ciąg znaków do SQL Server, interpretacja zależy od ustawień regionalnych, ustawień językowych, ustawień daty i tak dalej. Więc jeśli przechowujesz 2 stycznia w bazie danych, użycie '1/2/1900' może znaleźć twój wiersz, może nie . Użycie '2/1/1900' może znaleźć twój wiersz, może nie. Te zależą od różnych ustawień (więcej informacji, przeczytaj link). Jeśli użyjesz '19000102', nigdy nie będzie żadnego pomyłki ... –

+0

1. W 19000102, 01 to miesiąc, a 02 to właściwa data? 2. Czy nadal będzie uwzględniać datę w czasie lub nie w dopasowaniu? 3. Czy masz na myśli, że 19000102 jest zawsze bezpieczny, niezależnie od ustawień regionalnych na serwerze? Wielkie dzięki za wyjaśnienie wszystkich tych – user576510