2013-04-16 41 views
7

Tôi đang sửa đổi một truy vấn, đây là kịch bản của tôi:SQL Server so sánh ngày với chuỗi bằng chữ như thế nào?

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

Kịch bản này chỉ đơn giản là so sánh ngày, nếu nó là '1900/01/01' sau đó trả về null ngược lại trả về ngày tháng.

tôi có thể nhìn thấy trong ngày cơ sở dữ liệu của tôi được lưu trữ trong các định dạng sau:

1900-01-01 00:00:00.000 

Câu hỏi là cách SQL Server được ngày như thế này phù hợp khi mô hình của tôi là khác biệt so với lưu trữ một. Ngoài ra ở định dạng ngày tôi không vượt qua yếu tố thời gian.

+0

Nhìn vào 'chức năng DATEPART'. Xem http://msdn.microsoft.com/en-us/library/aa258265(v=sql.80).aspx –

+2

@ PM77-1 bạn đã đọc câu hỏi chưa? –

+0

Vâng ... tôi đã làm. Mắc lỗi. Có nghĩa là 'CONVERT'. –

Trả lời

17

Máy chủ SQL chuyển đổi chuỗi ký tự bạn đang chuyển ('1/1/1900') thành giá trị ngày giờ do data type precedence (since datetime has higher precedence than string types). Nếu bạn vượt qua ngày không hợp lệ làm chuỗi của mình, ví dụ: '2/31/1900', bạn sẽ nhận được một lỗi chuyển đổi (Msg 242) bởi vì SQL Server không biết những gì có nghĩa là 31 tháng hai. Nó không cố gắng để phù hợp với một chuỗi giống như những gì bạn đang truyền, nó chuyển đổi cả hai để đại diện nội bộ của nó cho ngày (thêm vào đó trong bình luận của tôi).

Khi giao dịch với số ngày cụ thể, ngừng suy nghĩ về một định dạng ngoại trừ việc khi bạn vượt qua xâu, m/d/y (hoặc là d/m/y?) Là một định dạng khủng khiếp để sử dụng. Nhiều an toàn hơn để sử dụng:

YYYYMMDD 

truy vấn của bạn nên đọc:

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

Bằng cách này, khi bạn vượt qua một ngày như ngày 8 tháng 9, nó không phải là hiểu sai bởi SQL Server, độc giả khác, vv là 09/08/2013 ngày 8 tháng 9 hoặc ngày 9 tháng 8? Phụ thuộc vào phần nào của thế giới bạn đang ở, phải không? Trong trường hợp của bạn thì không sao cả vì ngày và tháng là như nhau, nhưng điều này không phải lúc nào cũng đúng. Xin vui lòng xem bài viết sau:

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

(. Xin vui lòng, xin vui lòng, xin vui lòng đọc liên kết trong toàn bộ)

Cuối cùng, nếu bạn đang sử dụng DATETIME/SMALLDATETIME và đang tìm kiếm các giá trị từ một ngày cụ thể, bạn không nên sử dụng bình đẳng ở tất cả, mà đúng hơn là một truy vấn phạm vi. Ví dụ, để tìm tất cả các hàng nơi EndDate rơi vào ngày 15 Tháng Tư năm 2013, bất kể thời gian, bạn sẽ nói: (. Read this link to understand why you don't want to use BETWEEN here)

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

Nếu bạn đang ở trên SQL Server 2008 hoặc tốt hơn, bạn vẫn có thể đạt được sargability trên cột này với CONVERT, nhưng đây là một ngoại lệ hiếm - thường bạn không muốn sử dụng một hàm chống lại một cột.

WHERE CONVERT(DATE, EndDate) = '20130415' 

Một vài ý kiến ​​khác - không liên quan trực tiếp đến câu hỏi của bạn, nhưng ngoại vi quan sát về mã của bạn:

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

cảm ơn vì đã tham dự câu hỏi của tôi. Bạn có ý gì khi "ngừng suy nghĩ về một định dạng"? Bạn có nghĩa là cho một ngày lưu trữ cho máy chủ sql nó là như nhau nếu tôi nhập ngày cho phù hợp với 1/2/1900 hoặc 2/1/1900 hoặc 1900/2/1 và thậm chí 1900/1/2? Bạn có thể làm rõ điều đó không. – user576510

+4

Tôi có nghĩa là SQL Server không * lưu trữ * ngày của bạn ở định dạng có thể đọc được con người mà bạn nghĩ là có. Nó lưu trữ ngày nội bộ dưới dạng hai số nguyên đại diện cho ngày và giờ tương ứng. Khi bạn chuyển một chuỗi tới SQL Server, việc giải thích phụ thuộc vào cài đặt vùng, cài đặt ngôn ngữ, cài đặt định dạng ngày, v.v. Vì vậy, nếu bạn lưu trữ ngày 2 tháng 1 trong cơ sở dữ liệu, sử dụng '1/2/1900' có thể tìm thấy hàng của bạn . Sử dụng '2/1/1900' có thể tìm thấy hàng của bạn, nó có thể không. Những điều này phụ thuộc vào các cài đặt khác nhau (để biết thêm thông tin, hãy đọc liên kết). Nếu bạn sử dụng '19000102' sẽ không bao giờ có bất kỳ sự nhầm lẫn nào ... –

+0

1. Trong 19000102, 01 là tháng và 02 là ngày phải không? 2. Liệu nó vẫn xem xét thời gian trong ngày hay không phù hợp? 3. Bạn có nghĩa là 19000102 luôn an toàn để làm bất kể cài đặt vùng nào có trên máy chủ không? Cảm ơn rất nhiều vì đã làm rõ tất cả các số – user576510

Các vấn đề liên quan