2009-05-13 41 views
16

Tôi đã gỡ một thủ tục lưu trữ ngày khác và tìm thấy một số điều gì đó logic như thế này:"<>" vs "NOT IN"

SELECT something 
FROM someTable 
WHERE idcode <> (SELECT ids FROM tmpIdTable) 

này trở gì. Tôi nghĩ rằng nó trông hơi lạ với "<>" vì vậy tôi đã thay đổi nó thành "NOT IN" và sau đó mọi thứ hoạt động tốt. Tôi đã tự hỏi tại sao đây là? Đây là một proc khá cũ và tôi không thực sự chắc chắn bao lâu vấn đề đã được xung quanh, nhưng chúng tôi gần đây đã chuyển từ SQL Server 2005 sang SQL Server 2008 khi điều này đã được phát hiện. Sự khác biệt thực sự giữa "<>" và "KHÔNG IN" và có hành vi thay đổi giữa Server2005 và 2008 là gì?

Trả lời

18
SELECT something 
FROM someTable 
WHERE idcode NOT IN (SELECT ids FROM tmpIdTable) 

kiểm tra mọi giá trị trong danh sách.

Tuy nhiên, NOT IN không chịu NULL. Nếu truy vấn con trả lại một tập hợp các giá trị chứa NULL, sẽ không có bản ghi nào được trả về. (Điều này là do nội bộ KHÔNG IN được tối ưu hóa thành idcode <> 'foo' AND idcode <> 'bar' AND idcode <> NULL, v.v., sẽ luôn thất bại vì bất kỳ so sánh nào với giá trị NULL KHÔNG ĐÚNG, ngăn chặn toàn bộ biểu thức không bao giờ trở thành TRUE.)

Một biến thể đẹp hơn, chịu NULL này:

SELECT something 
FROM someTable 
WHERE NOT EXISTS (SELECT ids FROM tmpIdTable WHERE ids = someTable.idcode) 

EDIT: tôi ban đầu giả định rằng đây:

SELECT something 
FROM someTable 
WHERE idcode <> (SELECT ids FROM tmpIdTable) 

sẽ kiểm tra so với giá trị đầu tiên mà thôi. Nó chỉ ra rằng giả định này là sai ít nhất cho SQL Server, nơi nó thực sự gây ra lỗi của mình:

Msg 512, Level 16, State 1, Line 1 
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression. 
+1

'WHERE idcode NOT IN (...)' tương đương với 'WHERE idcode <> ALL (...)' –

7

<> là hoạt động "số ít" NOT; NOT IN là một hoạt động được thiết lập, do đó, nó có ý nghĩa rằng trước đây sẽ không hoạt động. Tôi không có ý tưởng hay không nó có thể đã làm như vậy theo một phiên bản trước của SQL Server, tuy nhiên.

+0

Nó không bao giờ được thực hiện bất kỳ khác nhau trong SQL Server. – Tomalak

11

thử loại này, có thể chạy nhanh hơn vì sử dụng chỉ mục:

SELECT something 
FROM someTable 
    LEFT OUTER JOIN tmpIdTable ON idcode=ids 
WHERE ids IS NULL 
+0

+1 thay thế tốt –

+0

Đó là một ý tưởng hay! –

+0

SQL Server bình thường (Tôi chưa từng thấy một trường hợp nào khi nó không có) tạo ra QEP giống nhau cho một kết nối hoặc một truy vấn con, và do đó thực hiện giống hệt nhau. – pipTheGeek

2

Tôi không có ý tưởng tại sao bạn sẽ viết một cái gì đó như WHERE idcode <> (SELECT ids FROM tmpIdTable). Một câu lệnh SELECT sẽ trả về một tập hợp các bộ dữ liệu và mã nhận dạng của bạn hoặc sẽ KHÔNG ở trong bộ này. "WHERE idcode NOT IN (SELECT ids FROM tmpIdTable)" là cách để làm điều đó.

+0

Thats lý do tại sao tôi biết để sửa chữa nó, tôi chỉ không thực sự biết chính xác những gì logic đằng sau nó được. –

+0

Câu lệnh <> có thể có ý nghĩa nếu truy vấn phụ được sắp xếp theo một cách nào đó, ví dụ: "<> [điều lớn nhất] trong danh sách". – Tomalak

+0

Bạn nói đúng, trong trường hợp truy vấn phụ được đặt hàng, ký hiệu <> có thể có ý nghĩa gì đó, nhưng tôi sẽ tránh nó bằng cách nào đó, vì nó dễ bị lỗi - dễ bỏ qua ý định của nó.Bất kỳ ai loại bỏ hoặc thay đổi thứ tự của truy vấn phụ sau này có thể bị bối rối bởi vì sao truy vấn không trả về gì cả. –

-1

trong một số phiên bản của SQL ! = nên được sử dụng cho câu lệnh logic "không bằng". Bạn đã thử điều đó chưa?

+2

'<>' và '! =' Tương đương với SQL Server. Không có phiên bản nào nhấn mạnh vào '! ='. Nhưng '<>' là cách làm chuẩn của ANSI SQL, mặc dù cá nhân tôi có xu hướng sử dụng! = Thường xuyên hơn vì một lý do nào đó. – Tomalak

4

Mã này là hợp lệ nếu và chỉ nếu không có hàng hoặc một hàng duy nhất trở về từ tmpIdTable:

SELECT something 
FROM someTable 
WHERE idcode <> (SELECT ids FROM tmpIdTable) 

Nếu nhiều hàng được trả về, bạn sẽ nhận được một lỗi như:

Msg 512 , Cấp 16, Tiểu bang 1, Dòng 1 Truy vấn con được trả về nhiều hơn 1 giá trị. Điều này không được phép khi truy vấn con sau =,! =, <, < =,>,> = hoặc khi truy vấn phụ được sử dụng làm biểu thức.

Đây là lỗi tương tự bạn nhận được với vô hướng lồng nhau bất ngờ tạo ra nhiều hàng như:

SELECT *, (SELECT blah TỪ t1 ĐÂU vv) từ t2

Không có gì đã thay đổi WRT này trong SQL Server trong một thập kỷ, vì vậy tôi mong đợi các giả định về truy vấn lồng nhau trong mã ban đầu đã bị hỏng.

Nếu không có hàng nào được trả về, kết quả sẽ trống vì <> NULL không bao giờ đúng (giả sử ANSI NULL).

Mã này có giá trị đối với bất kỳ số lượng hàng:

SELECT something 
FROM someTable 
WHERE idcode NOT IN (SELECT ids FROM tmpIdTable) 

Tuy nhiên, vẫn có thể có các vấn đề với NULL.

+0

Tôi thực sự đã có cuộc trò chuyện tương tự sáng nay với một đồng nghiệp. Câu trả lời tương tự, nhưng không hoàn toàn. –

+0

Về mặt khái niệm, ít nhất, nó thậm chí còn sai nếu subselect trả về 0 hoặc một hàng. Bởi vì bạn đang hỏi liệu một vô hướng, idcode, có bằng một danh sách không hoặc một phần tử không. Vô hướng không bao giờ thực sự bằng danh sách, ngay cả khi nó bằng với phần tử duy nhất trong danh sách một phần tử. –

+0

Thật vậy, tôi không bao giờ sử dụng cấu trúc và tôi thường nghĩ nó như một mùi mã. –

2

Nếu truy vấn con SELECT trả về 0 hàng, đó là NULL. Khi NULL được so sánh với bất cứ điều gì, kết quả luôn luôn là không xác định, và không bao giờ TRUE. Đủ lộn xộn, KHÔNG PHẢI NỔI BẬT bằng UNKNOWN.

Tôi tránh ba giá trị logic (TRUE, FALSE, UNKNOWN) bất cứ khi nào có thể. Nó không phải là khó để tránh một khi bạn nhận được hang của nó.

Nếu truy vấn con SELECT trả về chính xác một giá trị, so sánh cho bất bình đẳng sẽ trả về kết quả bạn mong đợi.

Nếu truy vấn con SELECT trả về nhiều giá trị, bạn sẽ gặp lỗi.

Nói chung, NOT IN sẽ trả về kết quả bạn mong đợi khi bạn đang thử nghiệm không phải là thành viên trong tập hợp.

Phản hồi này trùng lặp các phản hồi khác, nhưng nó được diễn đạt khác một chút.

Edited để thêm chi tiết về KHÔNG IN:

tôi đã làm một số tìm kiếm về NOT IN trong Oracle, và tôi đã học một cái gì đó tôi không biết một nửa giờ trước. NOT IN là NULL nhạy cảm. Đặc biệt,

X NOT IN (SELECT ...) 

là không giống như

NOT (X IN SELECT ...)) 

tôi có thể phải sửa đổi phản ứng trước đây của tôi!

+0

+1 để chỉ ra phần TRUE/FALSE/UNKNOWN. Cảm ơn. – Tomalak

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