2010-10-14 37 views
9

Vì vậy, tôi có một câu hỏi đơn giản mà trả về một danh sách các sản phẩmSQL Và NULL Giá trị trong mệnh đề where

SELECT  Model, CategoryID 
FROM   Products 
WHERE  (Model = '010-00749-01') 

này trả

010-00749-01 00000000-0000-0000-0000-000000000000 
010-00749-01 NULL 

nào là chính xác, vì vậy tôi muốn chỉ các sản phẩm có CategoryID không phải là '00000000-0000-0000-0000-000000000000' vì vậy tôi có

SELECT  Model, CategoryID 
FROM   Products 
WHERE  (Model = '010-00749-01') 
AND (CategoryID <> '00000000-0000-0000-0000-000000000000') 

Nhưng điều này không trả về kết quả. Vì vậy, tôi đã thay đổi truy vấn để

SELECT  Model, CategoryID 
FROM   Products 
WHERE  (Model = '010-00749-01') 
AND ((CategoryID <> '00000000-0000-0000-0000-000000000000') OR (CategoryID IS NULL)) 

trả về kết quả dự kiến ​​

010-00749-01 NULL 

Ai đó có thể giải thích hành vi này đối với tôi? MS SQL Server 2008

+3

bài viết trên wiki khá tốt khi giải thích NULL - http://en.wikipedia.org/wiki/Null_%28SQL%29 –

+0

@Russ Cam - bạn nên đăng câu trả lời này ... – veljkoz

+1

Tôi cảm thấy nó đã được nhiều hơn một câu trả lời lmgtfy :) –

Trả lời

9

Kiểm tra tham chiếu đầy đủ trên Books Online - theo mặc định ANSI_NULLS có nghĩa là bạn cần sử dụng phương pháp bạn đã thực hiện. Nếu không, bạn có thể chuyển cài đặt đó TẮT ở đầu truy vấn để chuyển đổi vòng hành vi.

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 là BẬT, tất cả so sánh với giá trị rỗng được đánh giá là 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.

Dưới đây là một ví dụ đơn giản để chứng minh hành vi liên quan đến so sánh với NULL với:

-- This will print TRUE 
SET ANSI_NULLS OFF; 
IF NULL <> 'A' 
    PRINT 'TRUE' 
ELSE 
    PRINT 'FALSE' 

-- This will print FALSE 
SET ANSI_NULLS ON; 
IF NULL <> 'A' 
    PRINT 'TRUE' 
ELSE 
    PRINT 'FALSE' 
+0

Hãy cẩn thận, thiết lập ANSI_NULLS để 'off' sẽ làm giảm hiệu suất và tăng đọc hợp lý. Việc bật tính năng này ảnh hưởng đến gói truy vấn. – vol7ron

+0

@ Vol7ron Thực sự xứng đáng với một downvote ?! Đó là v khắc nghiệt cho một câu trả lời đúng là gì. Nếu bạn thành thật cảm thấy nó đảm bảo một sự bình luận, đủ công bằng nhưng imho có vẻ kỳ quặc và không phải là một lá phiếu trung thực – AdaTheDev

+0

Điều gì xứng đáng là một sự bỏ rơi? Tôi không nghĩ rằng nó xứng đáng một xuống hoặc lên. Đó là một câu trả lời. Tôi sẽ không đi xa như vậy để nói nó là "đúng". Việc triển khai thực hiện điều này sẽ có hiệu suất cao, nhưng quan trọng hơn về mặt kỹ thuật không phải là tiêu chuẩn SQL, thời điểm bạn thực hiện điều đó, bạn đang đi lạc khỏi ISO. Một trong những điều tốt nhất về SQL là khả năng chuyển từ nền tảng này sang nền tảng khác, bạn đang đưa ra điều đó ở đây. 'Coalesce' là một giải pháp tốt hơn. Như tôi đã nói, nếu bạn lo lắng về tác động hiệu suất thì hãy lập chỉ mục trường đó với chức năng, nếu không làm sạch dữ liệu cơ bản. – vol7ron

1

nhìn lúc này:

1=1  --true 
1=0  --false 
null=null --false 
null=1  --false 

1<>1  --false 
1<>0  --true 
null<>null --false 
null<>1 --false <<<--why you don't get the row with: AND (CategoryID <> '00000000-0000-0000-0000-000000000000') 
+3

SQL về mặt kỹ thuật sử dụng hệ thống logic ba giá trị, vì vậy tất cả các so sánh của bạn với năng suất NULL UNKNOWN thay vì FALSE. Xem: [SQL và Snare of Three-Valued Logic] (http://www.simple-talk.com/sql/learn-sql-server/sql-and-the-snare-of-three-valued-logic/). –

+0

gọi nó là 'sai' hoặc 'không xác định', nó không thực sự quan trọng, bởi vì hàng không được bao gồm trong tập kết quả, đó là những gì câu hỏi là tất cả về. –

1

Về cơ bản, một NULL là sự vắng mặt của bất kỳ giá trị. Vì vậy, cố gắng so sánh NULL trong CategoryId với một giá trị varchar trong truy vấn sẽ luôn dẫn đến một đánh giá sai.

Bạn có thể muốn thử sử dụng các chức năng liên hiệp, một cái gì đó như:

SELECT  ModelId, CategoryID 
FROM  Products 
WHERE  (ModelId = '010-00749-01') 
AND  (COALESCE(CategoryID, '') <> '00000000-0000-0000-0000-000000000000') 

EDIT

Theo ghi nhận của AdaTheDev chức năng liên hiệp sẽ phủ nhận bất kỳ chỉ số có thể tồn tại trên cột CategoryID, có thể ảnh hưởng đến kế hoạch truy vấn và hiệu suất.

+1

Hãy cẩn thận với phương pháp này, vì COALESCE có thể dẫn đến một kế hoạch thực hiện ít tối ưu hơn bằng cách ngăn chặn chỉ mục tìm kiếm trên cột đó – AdaTheDev

+0

Ada là chính xác, COALESCE không có ảnh hưởng đến kế hoạch thực hiện. Sẽ chỉnh sửa câu trả lời của tôi để bao gồm. –

0

Bạn có thể thử bằng cách sử dụng Coalesce chức năng để thiết lập một giá trị mặc định cho các lĩnh vực mà có null:

SELECT Model , CategoryID 
    FROM  Products 
    WHERE  Model = '010-00749-01' 
    AND  Coalesce(CategoryID,'') <> '00000000-0000-0000-0000-000000000000' 

Tôi nghĩ vấn đề nằm ở chỗ hiểu biết của bạn NULL mà về cơ bản có nghĩa là "không có gì." Bạn không thể so sánh bất cứ điều gì với không có gì, giống như bạn không thể chia một số bằng 0. Nó chỉ là quy tắc của toán học/khoa học.

Chỉnh sửa: Như Ada đã chỉ ra, điều này có thể khiến trường được lập chỉ mục không còn sử dụng chỉ mục nữa.

Giải pháp:

  • Bạn có thể tạo một chỉ số sử dụng chức năng liên hiệp: ví dụ create index ... coalesce(field)
  • Bạn có thể thêm một hạn chế not null để ngăn chặn NULLs từ bao giờ xuất hiện
  • Một tiêu chuẩn de facto của tôi là luôn chỉ định các giá trị mặc định và không bao giờ cho phép các giá trị rỗng
+2

Hãy cẩn thận với phương pháp này, vì COALESCE có thể dẫn đến một kế hoạch thực hiện ít tối ưu hơn bằng cách ngăn chặn chỉ mục tìm kiếm trên cột đó – AdaTheDev

+0

Điều này có thể đúng, tuy nhiên, bạn có thể tạo chỉ mục dưới dạng 'coalesce (field)' hoặc thêm không null ràng buộc để ngăn chặn NULL từ bao giờ xuất hiện.Một tiêu chuẩn thực tế của tôi là luôn luôn gán giá trị mặc định và không bao giờ cho phép null. – vol7ron

2

Nói chung, bạn phải nhớ rằng NULL thường có nghĩa là không xác định. Điều đó có nghĩa là nếu bạn nói CategoryID <> '00000000-0000-0000-0000-000000000000' bạn phải giả định rằng truy vấn sẽ chỉ trả về giá trị mà nó BIẾT sẽ đáp ứng tiêu chí của bạn. Vì có một kết quả NULL (UNKNOWN), nó không thực sự biết nếu bản ghi đó đáp ứng các tiêu chí của bạn và do đó sẽ không được trả về trong tập dữ liệu.

+0

Trong khi các câu trả lời khác chứa chi tiết hơn, tôi thích cái này vì sự đơn giản. Nó thậm chí có thể hiểu được ngay cả đối với một người không phải là công nghệ cao, và do đó có giá trị đối với các nhà phát triển mới hơn. +1. – David

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