PostgreSQL 'KHÔNG VÀO' và truy vấn con


89

Tôi đang cố thực hiện truy vấn này:

SELECT mac, creation_date 
FROM logs 
WHERE logs_type_id=11
AND mac NOT IN (select consols.mac from consols)

Nhưng tôi không nhận được kết quả. Tôi đã kiểm tra nó và tôi biết rằng có gì đó sai với cú pháp. Trong MySQL, một truy vấn như vậy hoạt động hoàn hảo. Tôi đã thêm một hàng để chắc chắn rằng có một hàng mackhông tồn tại trong consolsbảng, nhưng nó vẫn không đưa ra bất kỳ kết quả nào.


4
consols.maccột NULLhoặc NOT NULL?
Đánh dấu Byers

Câu trả lời:


166

Khi sử dụng NOT IN, bạn nên đảm bảo rằng không có giá trị nào là NULL:

SELECT mac, creation_date 
FROM logs 
WHERE logs_type_id=11
AND mac NOT IN (
    SELECT mac
    FROM consols
    WHERE mac IS NOT NULL -- add this
)

4
Lưu ý: WHERE mac IS NOT NULLmệnh đề trong truy vấn con là không cần thiết, vì In(...)luôn loại bỏ các NULL (và các bản sao). Bởi vì một bộ không thể chứa NULLs
wildplasser

7
@wildplasser Tôi không biết về điều đó. Nó không hoạt động với tôi, cho đến khi tôi thêm IS NOT NULL. Các lồng nhau SELECTđã trở lại một vài NULLS, và điều đó đang vấp phải IN(SELECT...).
robins35

2
Tôi sẽ đánh giá rất cao lời giải thích tại sao IS NOT NULLnguyên nhân của việc này.
mbarkhau

7
Có vẻ như việc sử dụng NULLtrong NOT INmệnh đề không hoạt động vì so sánh với NULLkhông đúng cũng không sai. sqlbadpractices.com/using-not-in-operator-with-null-values
mbarkhau 19/04/17

2
Truy vấn sẽ trả về không có hàng nào is not nullnếu truy vấn con không tạo ra giá trị phù hợp và ít nhất một nullgiá trị. Từ phần 9.22 của hướng dẫn sử dụng PostgreSQL hiện tại (phiên bản 10): "[…] nếu không có giá trị bên phải bằng nhau và ít nhất một hàng bên phải cho ra giá trị rỗng, kết quả của cấu trúc NOT IN sẽ là giá trị rỗng, không đúng . "
Christopher Lewis,

29

Khi sử dụng NOT IN, bạn cũng nên xem xét NOT EXISTS, xử lý âm thầm các trường hợp rỗng. Xem thêm Wiki PostgreSQL

SELECT mac, creation_date 
FROM logs lo
WHERE logs_type_id=11
AND NOT EXISTS (
  SELECT *
  FROM consols nx
  WHERE nx.mac = lo.mac
  );

3
Cũng lưu ý rằng một mất mát hiệu suất lớn khi sử dụng NOT EXISTSvs... NOT IN
IcanDivideBy0

1
@ IcanDivideBy0 Trong hầu hết các trường hợp, chúng tạo ra cùng một kế hoạch truy vấn. Bạn đã thử nghiệm nó chưa?
wildplasser

1
Cũng có hiệu suất tăng khi sử dụng NOT IN thay vì NOT EXISTS, trong trường hợp truy vấn con. Xem wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use_NOT_IN
Gerbrand

8

Bạn cũng có thể sử dụng điều kiện LEFT JOIN và IS NULL:

SELECT 
  mac, 
  creation_date 
FROM 
  logs
    LEFT JOIN consols ON logs.mac = consols.mac
WHERE 
  logs_type_id=11
AND
  consols.mac IS NULL;

Chỉ mục trên cột "mac" có thể cải thiện hiệu suất.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.