2009-03-25 36 views
5

Trong bảng của tôi, tôi có một cột bitable (hệ thống kế thừa ...) và một nhà phát triển khác gần đây đã thực hiện thay đổi đối với một thủ tục được lưu trữ để chỉ hiển thị các giá trị trong đó cột bit không đúng (1). Bởi vì đây là một cột nullable, chúng tôi nhận thấy rằng nếu cột là NULL, hồ sơ đã không được chọn. TẠI SAO?SQL: Tại sao giá trị NULL được lọc ra trong mệnh đề where?

Cả nhà phát triển khác và tôi đồng ý rằng NULL <> 1 ... Đây có phải là lỗi trong SQL hoặc được thiết kế theo cách này không? Có vẻ như một lỗ hổng thiết kế.

Mã hiện tại:

(VoidedIndicator <> 1) 

Đề xuất Fix:

(VoidedIndicator <> 1 OR VoidedIndicator IS NULL) 

Làm rõ (Theo Jon Erickson)

VoidedIndicator là một lĩnh vực chút nullable để nó có thể có các giá trị sau: NULL, 0, o r 1

Khi câu lệnh SQL được tạo với mệnh đề where (VoidedIndicator <> 1), chúng tôi chỉ nhận được các bản ghi trả về có VoidedIndicator == 0, nhưng chúng tôi mong đợi cả VoidedIndicator == 0 và VoidedIndicator IS NULL. Tại sao điều này?

Trả lời

11

Từ Wikipedia entry on NULL:

Ví dụ, một mệnh đề WHERE hoặc tuyên bố có điều kiện có thể so sánh giá trị của một cột với một hằng số. Đó là thường giả định sai rằng giá trị bị thiếu sẽ "nhỏ hơn" hoặc "không bằng" nếu trường chứa Null, nhưng, trên thực tế, biểu thức như vậy sẽ trả về Không xác định. Một ví dụ là dưới đây:

-- Rows where num is NULL will not be returned, 
-- contrary to many users' expectations. 
SELECT * FROM sometable WHERE num <> 1; 

Về cơ bản, bất kỳ so sánh giữa NULL và cái gì khác, cho dù đó là với = hoặc <> sẽ không thể đúng.

Là tài liệu tham khảo khác, MSDN T-SQL page on <> trạng thái:

So sánh hai biểu thức (toán tử so sánh ). Khi bạn so sánh các biểu thức không phải là , kết quả là TRUE nếu toán tử bên trái không bằng với toán hạng đúng; nếu không, kết quả là FALSE.Nếu một hoặc cả hai toán hạng là NULL, hãy xem THIẾT LẬP ANSI_NULLS (Transact-SQL).

Trang SET ANSI_NULLS sau đó khẳng định:

Khi SET ANSI_NULLS là ON, một câu lệnh SELECT có sử dụng ĐÂU column_name = lợi nhuận NULL zero hàng ngay cả khi có giá trị null trong column_name. Câu lệnh SELECT SELECT sử dụng WHERE column_name <> NULL trả về hàng không ngay cả khi có các giá trị không trống trong column_name.

...

Khi SET ANSI_NULLS ON, tất cả so sánh với một giá trị null đánh giá để UNKNOWN. Khi SET ANSI_NULLS TẮT, so sánh tất cả các dữ liệu so với giá trị null đánh giá là TRUE nếu giá trị dữ liệu là NULL.

3

Nó không phải là lỗi.

NULL không bằng bất kỳ thứ gì, thậm chí không NULL (NULL = NULL trả về SAI).

Thông thường giá trị NULL cũng không được lập chỉ mục. Nó thường là một ý tưởng tồi để dựa vào một giá trị cụ thể hoặc NULL. Tùy thuộc vào những gì bạn đang lưu trữ trong cột, bạn có thể được tốt hơn off đặt một giá trị giả hoặc sentinel thay vì sử dụng NULL để chỉ ra một số ý nghĩa.

+0

Vì vậy, nếu NULL không bằng bất kỳ thứ gì bạn nói, thì NULL không được bao gồm trong trường hợp này như thế nào? Cột <> 1 ... NULL không bằng 1? Chính xác? – RSolberg

+0

Bất kỳ so sánh nào liên quan đến trả về NULL sai vì vậy có NULL <> 1 là sai. Đó là những gì IS NULL hoặc IS NOT NULL là cho. – cletus

+0

Cách tốt nhất mà tôi tìm thấy để suy nghĩ về null trong thuật ngữ cơ sở dữ liệu, đúng hay sai, là giá trị null là "không xác định", do đó không thể so sánh với giá trị null khác, cũng không so sánh với giá trị cụ thể –

0

Bạn cũng có thể: ISNULL (VoidedIndicator, 1) <> 1

+0

Ý tưởng tồi về hiệu suất trừ khi bạn có chỉ mục chức năng cho loại điều này. – cletus

+0

Tôi sẽ nói, tôi nghĩ IsNull() có mối quan tâm về hiệu suất ... – RSolberg

+0

@cletus đang xem xét rằng họ có một kịch bản thực sự cần tối ưu hóa đó. Tôi đồng ý sử dụng giá trị mặc định nếu có thể/thích hợp. – eglasius

0

Bởi vì mệnh đề WHERE chỉ chọn hàng khi điều kiện xác định là true.

Khi một trong các toán hạng là NULL, điều kiện thường được đánh giá là UNKNOWN (xấp xỉ tương đương với NULL) và do đó không đúng. Nó áp dụng cho cả 'column = 1' và 'column <> 1'; nếu cột là NULL, điều kiện tìm kiếm thất bại.

Đó là lý do tại sao bạn được yêu cầu tránh cột NULL bất cứ khi nào có thể.

+0

Bạn cũng có tránh giá trị số nguyên không, vì phép chia cho số không gây ra lỗi? –

+0

Nó có thể phụ thuộc vào máy chủ, nhưng cơ hội là phong nha nếu bạn viết 'cột/0' và cột là null, thì mã phân chia sẽ xem liệu toán hạng là null và trả về null trước khi tạo 'chia cho 0' lỗi. Tuy nhiên, nếu bạn biết 'cột' là null, tại sao bạn lại phân chia nó? –

+0

Và tại sao bạn chia cho số không? Tôi nghĩ rằng nó sẽ là không khôn ngoan để dựa vào null ngăn ngừa phân chia bằng không lỗi, nhưng nếu bạn chia một null bằng không 'vô tình', sau đó bạn có thể không nhận được lỗi. –

1

Những người khác là chính xác rằng NULL <> 1 không đánh giá là đúng, do đó, nó không đáp ứng điều khoản WHERE.

Việc sửa chữa đề nghị bạn mô tả là cách tốt nhất để xử lý nó:

(VoidedIndicator <> 1 OR VoidedIndicator IS NULL) 

SQL-99 không có một vị giúp trong trường hợp này, được gọi là IS DISTINCT FROM:

(VoidedIndicator IS DISTINCT FROM 1) 

vị này sẽ hành xử chính xác giống như sửa lỗi được đề xuất của bạn. Thật không may, Microsoft SQL Server không hỗ trợ IS DISTINCT FROM.

+0

Cảm ơn sự thấu hiểu, tôi sẽ không gặp IS TỪ CHỐI TỪ trước đây. Vì vậy, điều này vẫn chưa được thực hiện trong SQL Server 2008? –

+0

Phải. Tôi không thể tìm thấy IS DISTINCT FROM trong tài liệu trực tuyến MS SQL Server 2008, trong khi tôi tìm thấy vị từ IS NULL và hàm ISNULL(). –

+0

Hỗ trợ PostgreSQL, IBM DB2 và Firebird KHÔNG ĐƯỢC TỪ CHỐI. Oracle và Microsoft thì không. MySQL hỗ trợ toán tử "<=>". –

0

NULL <> 1 đánh giá (về mặt lý thuyết) thành "có thể", có nghĩa là bản ghi sẽ không được trả về.

12

Rất nhiều câu trả lời hay, nhưng hãy để tôi cung cấp cho bạn một phiên bản ngắn gọn.

Để SQL, Null không có nghĩa là "Không có giá trị" có nghĩa là "Unknown Value"

Với ý nghĩ đó, hãy xem xét câu trả lời cho câu hỏi mà bạn đang yêu cầu SQL bằng tiếng Anh.

Q: Is this unknown value not equal to 1? 
A: I don't know, there is no way to tell without knowing the value. 

Hence Null<>1 = Null 
Các vấn đề liên quan