2008-11-17 37 views
30

Tôi chắc chắn làm cho một sai lầm ngớ ngẩn nhưng tôi không thể hình dung những gì:SQL truy vấn câu hỏi: SELECT ... NOT IN

Trong SQL Server 2005, tôi đang cố gắng chọn tất cả các khách hàng trừ những người đã thực hiện đặt phòng trước 2 giờ sáng

Khi tôi chạy truy vấn này:

SELECT idCustomer FROM reservations 
WHERE idCustomer NOT IN 
    (SELECT distinct idCustomer FROM reservations 
    WHERE DATEPART (hour, insertDate) < 2) 

tôi nhận được 0 kết quả.

Nhưng

SELECT idCustomer FROM reservations 

lợi nhuận 152.000 kết quả và "NOT IN" phần:

SELECT distinct idCustomer FROM reservations 
WHERE DATEPART (hour, insertDate) < 2 

lợi nhuận chỉ 284 hàng

+0

Tại sao bạn sẽ đặt một biệt trong bạn KHÔNG TRONG? Là 5 trong (1, 1, 2, 2, 3, 4, 4, 4, 4, 4)? Trong không quan tâm nếu có bản sao. –

+1

Chắc chắn, tôi đã nhận được một chút tuyệt vọng và cố gắng tất cả mọi thứ :) –

Trả lời

53
SELECT distinct idCustomer FROM reservations 
WHERE DATEPART (hour, insertDate) < 2 
    and idCustomer is not null 

Hãy chắc chắn rằng tham số danh sách của bạn không chứa rỗng giá trị.

Dưới đây là một lời giải thích:

WHERE field1 NOT IN (1, 2, 3, null) 

là giống như:

WHERE NOT (field1 = 1 OR field1 = 2 OR field1 = 3 OR field1 = null) 
  • Đó so sánh cuối cùng interval là Null.
  • NẾU đó là HOẶC với phần còn lại của biểu thức boolean, sinh ra null. (*)
  • null bị từ chối, yielding null.
  • null không đúng - mệnh đề where chỉ giữ đúng hàng, vì vậy tất cả các hàng đều được lọc.

(*) Chỉnh sửa: giải thích này khá tốt, nhưng tôi muốn giải quyết một điều để ngăn chặn việc chọn nit trong tương lai. (TRUE OR NULL) sẽ đánh giá TRUE. Điều này có liên quan nếu field1 = 3, ví dụ. Giá trị TRUE đó sẽ được phủ nhận thành FALSE và hàng sẽ được lọc.

+0

Đó là nó, cảm ơn! Tôi vẫn không hiểu tại sao. Không phải các giá trị null không được lọc bởi các giá trị rỗng, đúng không? –

+0

Giải thích tuyệt vời David, cảm ơn rất nhiều! –

2

Với nó SQL 2005, bạn cũng có thể thử này Nó tương tự như lệnh TRỪ của Oracle (đối diện của UNION)

Nhưng tôi cũng sẽ đề nghị bổ sung thêm cột DATEPART (giờ, insertDate) cho debug

SELECT idCustomer FROM reservations 
EXCEPT 
SELECT idCustomer FROM reservations WHERE DATEPART (hour, insertDate) < 2 
0
SELECT Reservations.idCustomer FROM Reservations (nolock) 
LEFT OUTER JOIN @reservations ExcludedReservations (nolock) ON Reservations.idCustomer=ExcludedReservations.idCustomer AND DATEPART(hour, ExcludedReservations.insertDate) < 2 
WHERE ExcludedReservations.idCustomer IS NULL AND Reservations.idCustomer IS NOT NULL 
GROUP BY Reservations.idCustomer 

[cập nhật: thêm tiêu chí bổ sung để xử lý idCustomer là NULL, mà là rõ ràng vấn đề chính các poster ban đầu có]

+0

Xin chào Kevin, vấn đề là customerId đã bị vô hiệu hóa và vì @David đã chỉ ra nhưng rất cảm ơn! –

+0

Ok. Thêm vào các tiêu chí bổ sung chỉ để hoàn thành :-P Tôi không có dữ liệu để dùng thử, nhưng tôi tò mò muốn thấy sự khác biệt trong các kế hoạch EXECUTION của NOT IN so với OUTER JOIN. Nhưng dù sao, vui lòng giải quyết vấn đề của bạn. –

0

Xin lỗi nếu tôi đã bỏ lỡ điểm, nhưng sẽ không làm theo những gì bạn muốn trên chính nó?

SELECT distinct idCustomer FROM reservations 
WHERE DATEPART(hour, insertDate) >= 2 
+0

Tôi đã suy nghĩ cùng một điều ... Tuy nhiên, nếu một khách hàng có hai đặt phòng, một trước khi 2Am và một sau, bạn sẽ bao gồm anh ta, và anh ta sẽ không. –

+0

Ah, điều đó có ý nghĩa, bộ não của tôi không bắn vào tất cả các xi-lanh ngay hôm nay! –

6

Nó luôn luôn nguy hiểm để có NULL trong danh sách IN - nó thường cư xử như mong đợi cho IN nhưng không cho NOT IN:

IF 1 NOT IN (1, 2, 3, NULL) PRINT '1 NOT IN (1, 2, 3, NULL)' 
IF 1 NOT IN (2, 3, NULL) PRINT '1 NOT IN (2, 3, NULL)' 
IF 1 NOT IN (2, 3) PRINT '1 NOT IN (2, 3)' -- Prints 
IF 1 IN (1, 2, 3, NULL) PRINT '1 IN (1, 2, 3, NULL)' -- Prints 
IF 1 IN (2, 3, NULL) PRINT '1 IN (2, 3, NULL)' 
IF 1 IN (2, 3) PRINT '1 IN (2, 3)' 
+0

Điểm tốt. Tuy nhiên, tôi chưa bao giờ chạy vào một trường hợp khi sử dụng null trong danh sách đã đưa ra một câu trả lời đúng hơn. –

+0

Chính xác - vấn đề là khi danh sách là động và bạn không biết NULL là ở đó và bạn lấy một IN và thay đổi nó thành NOT IN. –

-1
SELECT MIN(A.maxsal) secondhigh 
FROM (
     SELECT TOP 2 MAX(EmployeeBasic) maxsal 
     FROM M_Salary 
     GROUP BY EmployeeBasic 
     ORDER BY EmployeeBasic DESC 
    ) A 
+3

Chào mừng bạn đến với SO. Bạn có thể muốn đọc http://stackoverflow.com/help/how-to-answer về cách soạn câu trả lời hay. Mã chỉ câu trả lời không phải là rất hữu ích, bạn có thể thêm một mô tả ngắn gọn về cách nó đã giải quyết vấn đề. – thebenman

-1
select * from table_name where id=5 and column_name not in ('sandy,'pandy'); 
+1

Chào mừng bạn đến với SO. Bạn có thể muốn đọc stackoverflow.com/help/how-to-answer về cách soạn câu trả lời hay. Câu trả lời chỉ có mã không phải là rất hữu ích, bạn có thể thêm một mô tả ngắn gọn về cách nó giải quyết vấn đề – GhostCat