Truy vấn MySQL KHÔNG CÓ trong truy vấn


181

Tôi muốn chạy một truy vấn đơn giản để đưa ra tất cả các hàng trong Table1đó giá trị cột chính không có trong một cột trong bảng khác ( Table2).

Tôi đã thử sử dụng:

SELECT * FROM Table1 WHERE Table1.principal NOT IN Table2.principal

Điều này thay vì ném một lỗi cú pháp. Tìm kiếm của Google dẫn tôi đến các diễn đàn nơi mọi người nói rằng MySQL không hỗ trợ NOT INvà cần phải sử dụng thứ gì đó cực kỳ phức tạp. Điều này có đúng không? Hay tôi đang phạm một sai lầm khủng khiếp?


1
Và nếu tôi muốn dữ liệu tương tự từ ba bảng. Ý tôi là một bảng1 có 2000 mục, hai bảng 2 & 3 còn lại có 500 mục, tất cả chúng đều có trường chung 'tên'. Làm thế nào chúng ta có thể nhận được tất cả các chi tiết từ bảng 1 không có trong bảng2 & 3 dựa trên 'tên'. Chúng ta có thể sử dụng KHÔNG VÀO hai lần không, nếu vậy thì thế nào ..?

Câu trả lời:


310

Để sử dụng IN, bạn phải có một bộ, thay vào đó hãy sử dụng cú pháp này:

SELECT * FROM Table1 WHERE Table1.principal NOT IN (SELECT principal FROM table2)

85
Cẩn thận khi table2.principalcó thể NULL. Trong trường hợp đó NOT INsẽ luôn trả về FALSENOT INđược coi là <> ALL, so sánh tất cả các hàng từ truy vấn con như thế Table1.principal <> table2.principal, thất bại khi so sánh với NULL: Table1.principal <> NULLsẽ không dẫn đến TRUE. Để khắc phục : NOT IN (SELECT principal FROM table2 WHERE principal IS NOT NULL).
Basti

4
Cảm ơn vì bình luận @Basti! Đã dành rất nhiều thời gian để cố gắng hiểu tại sao truy vấn không hoạt động như mong đợi.
gvas

3
Đừng quên tránh sử dụng 'CHỌN *' trong danh sách 'KHÔNG VÀO. Bạn phải chọn một cột cụ thể. Nếu không, bạn sẽ gặp phải lỗi này: stackoverflow.com/questions/14046838/ từ
Lorien Brunei

165

Tùy chọn truy vấn con đã được trả lời, nhưng lưu ý rằng trong nhiều trường hợp, LEFT JOINcó thể là một cách nhanh hơn để làm điều này:

SELECT table1.*
FROM table1 LEFT JOIN table2 ON table2.principal=table1.principal
WHERE table2.principal IS NULL

Nếu bạn muốn kiểm tra nhiều bảng để đảm bảo rằng nó không có trong bất kỳ bảng nào (như trong nhận xét của SRKR), bạn có thể sử dụng bảng này:

SELECT table1.*
FROM table1
LEFT JOIN table2 ON table2.name=table1.name
LEFT JOIN table3 ON table3.name=table1.name
WHERE table2.name IS NULL AND table3.name IS NULL

2
Trong các thử nghiệm của riêng tôi, có cùng hiệu suất cho cả hai NOT IN& LEFT JOIN. +1 cả hai
BufferStack

một khi truy vấn chạy một lần, bạn sẽ nhận được kết quả tương tự bất kể điều gì do bộ nhớ đệm DB bên trong
Toote

Đối với tôi hiệu suất là cách tốt hơn. Tôi chạy qua các bảng khác nhau, trong khi chúng có bộ khóa ngoại.
Keenora Fluffball

36

KHÔNG IN so với KHÔNG EXISTS so với LEFT THAM GIA / LÀ NULL trong MySQL

MySQL, cũng như tất cả các hệ thống khác trừ SQL Server, có thể tối ưu hóa LEFT JOIN/IS NULL trả về FALSEngay khi tìm thấy giá trị phù hợp và đó là hệ thống duy nhất quan tâm đến việc ghi lại hành vi này. [Vách] Vì MySQL không có khả năng sử dụng HASHMERGEtham gia các thuật toán, nên chỉ ANTI JOINcó khả năng làNESTED LOOPS ANTI JOIN

[Càng]

Về cơ bản, [ NOT IN] chính xác là cùng một kế hoạch mà LEFT JOIN/ IS NULLsử dụng, mặc dù thực tế các kế hoạch này được thực thi bởi các nhánh mã khác nhau và chúng trông khác nhau trong kết quả của EXPLAIN. Các thuật toán trên thực tế giống nhau trên thực tế và các truy vấn hoàn thành cùng một lúc.

[Càng]

Thật khó để nói lý do chính xác cho [giảm hiệu suất khi sử dụng NOT EXISTS] , vì mức giảm này là tuyến tính và dường như không phụ thuộc vào phân phối dữ liệu, số lượng giá trị trong cả hai bảng, v.v, miễn là cả hai trường được lập chỉ mục. Vì có ba đoạn mã trong MySQL cần thiết thực hiện một công việc, nên có thể mã chịu trách nhiệm EXISTSthực hiện một số loại kiểm tra bổ sung cần thêm thời gian.

[Càng]

MySQL có thể tối ưu hóa cả ba phương pháp để thực hiện một loại NESTED LOOPS ANTI JOIN. [V]] Tuy nhiên, ba phương thức này tạo ra ba kế hoạch khác nhau được thực thi bởi ba đoạn mã khác nhau. Các mã thực thi EXISTSpredicate là khoảng 30% kém hiệu quả [...]

Đó là lý do tại sao cách tốt nhất để tìm kiếm các giá trị bị thiếu trong MySQL là sử dụng LEFT JOIN/ IS NULLhoặc NOT INhơn là NOT EXISTS.

(nhấn mạnh thêm)


7

Thật không may, nó dường như là một vấn đề với việc sử dụng mệnh đề "KHÔNG IN" của MySql, ảnh chụp màn hình bên dưới hiển thị tùy chọn truy vấn phụ trả về kết quả sai:

mysql> show variables like '%version%';
+-------------------------+------------------------------+
| Variable_name           | Value                        |
+-------------------------+------------------------------+
| innodb_version          | 1.1.8                        |
| protocol_version        | 10                           |
| slave_type_conversions  |                              |
| version                 | 5.5.21                       |
| version_comment         | MySQL Community Server (GPL) |
| version_compile_machine | x86_64                       |
| version_compile_os      | Linux                        |
+-------------------------+------------------------------+
7 rows in set (0.07 sec)

mysql> select count(*) from TABLE_A where TABLE_A.Pkey not in (select distinct TABLE_B.Fkey from TABLE_B );
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.07 sec)

mysql> select count(*) from TABLE_A left join TABLE_B on TABLE_A.Pkey = TABLE_B.Fkey where TABLE_B.Pkey is null;
+----------+
| count(*) |
+----------+
|      139 |
+----------+
1 row in set (0.06 sec)

mysql> select count(*) from TABLE_A where NOT EXISTS (select * FROM TABLE_B WHERE TABLE_B.Fkey = TABLE_A.Pkey );
+----------+
| count(*) |
+----------+
|      139 |
+----------+
1 row in set (0.06 sec)

mysql> 

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.