Làm cách nào để chọn tất cả các bản ghi từ một bảng không tồn tại trong một bảng khác?


469

bảng1 (id, tên)
bảng2 (id, tên)

Truy vấn:

SELECT name   
FROM table2  
-- that are not in table1 already

Câu trả lời:


843
SELECT t1.name
FROM table1 t1
LEFT JOIN table2 t2 ON t2.name = t1.name
WHERE t2.name IS NULL

Q : Chuyện gì đang xảy ra ở đây?

Trả lời : Về mặt khái niệm, chúng tôi chọn tất cả các hàng từ table1và cho mỗi hàng chúng tôi cố gắng tìm một hàng table2có cùng giá trị cho namecột. Nếu không có hàng như vậy, chúng tôi chỉ để trống table2phần kết quả của chúng tôi cho hàng đó. Sau đó, chúng tôi hạn chế lựa chọn của mình bằng cách chỉ chọn những hàng đó trong kết quả mà hàng phù hợp không tồn tại. Cuối cùng, chúng tôi bỏ qua tất cả các trường từ kết quả của chúng tôi ngoại trừ namecột (trường mà chúng tôi chắc chắn tồn tại, từ table1).

Mặc dù nó có thể không phải là phương thức hiệu quả nhất có thể trong mọi trường hợp, nhưng về cơ bản, nó nên hoạt động trong mọi công cụ cơ sở dữ liệu cố gắng thực hiện ANSI 92 SQL


16
@ z-boss: Đây cũng là công cụ ít hoạt động nhất trên SQL Server: giải
thích.com / 2009/09/15/2007

7
@BunkerBoy: Tham gia bên trái cho phép các hàng bên phải không tồn tại mà không ảnh hưởng đến việc bao gồm các hàng bên trái. Một phép nối bên trong yêu cầu các hàng ở bên trái và bên phải để có mặt. Những gì tôi đang làm ở đây là áp dụng một số logic để cơ bản có được sự lựa chọn ngược của một phép nối bên trong.
Kris

2
omg điều này đã giúp hình dung rất dễ dàng, những người khác đã đặt nó như 5 cách khác nhau nhưng điều này đã giúp. đơn giản: đầu tiên bạn được tham gia trái, mọi thứ trong A và mọi thứ trong B khớp với A. Nhưng như trong các trường tham gia bên trái không tham gia thì chỉ là null. Sau đó, bạn nói, ok tôi chỉ muốn đó là null. Bằng cách này, bây giờ bạn có tất cả các hàng trong A không có trận đấu Trong B
Muhammad Umer

7
Cần lưu ý rằng các giải pháp này (được chấp nhận và bỏ phiếu) là giải pháp duy nhất, tôi nghĩ, có thể được chỉnh sửa cho một kịch bản có nhiều hơn một lĩnh vực đi vào hoạt động. Cụ thể, tôi đang trả về trường, trường 2, trường 3 từ bảng một trong đó sự kết hợp của trường quảng cáo trường2 không có trong bảng thứ hai. Ngoài việc sửa đổi tham gia trong câu trả lời này, tôi không thấy cách nào để thực hiện điều đó với một số "câu trả lời hiệu quả" khác được tranh luận dưới đây
TMWP

1
Chỉ cần đảm bảo rằng bạn sử dụng "WHERE t2.name IS NULL" chứ không phải "VÀ t2.name IS NULL" bởi vì "và" sẽ không cho kết quả chính xác. Tôi thực sự không hiểu tại sao nhưng đó là sự thật, tôi đã thử nó.
dùng89032

236

Bạn có thể làm

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

hoặc là

SELECT name 
FROM table2 
WHERE NOT EXISTS 
    (SELECT * 
     FROM table1 
     WHERE table1.name = table2.name)

Xem câu hỏi này cho 3 kỹ thuật để thực hiện điều này


38
Điều này là vô cùng chậm với số lượng lớn dữ liệu.
Lightbulb1

Vâng, thực sự nó rất chậm
sirus 2/215

Không nên là "từ bảng1" trong truy vấn con của truy vấn không tồn tại.
Chó săn

Rất bối rối tại sao điều này có rất nhiều upvote. Tôi thấy rất khó để nghĩ ra một lý do để sử dụng điều này, khi có một cách tiếp cận vấn đề này nhanh hơn nhiều với số lần nhấn phím tương đương.
searchengine27

Cái này hiệu quả với tôi .. Cảm ơn bạn
Thameem

81

Tôi không có đủ điểm đại diện để bỏ phiếu cho câu trả lời thứ 2. Nhưng tôi phải không đồng ý với các ý kiến ​​về câu trả lời hàng đầu. Câu trả lời thứ hai:

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

Là FAR hiệu quả hơn trong thực tế. Tôi không biết tại sao, nhưng tôi đang chạy nó với 800 nghìn + hồ sơ và sự khác biệt là rất lớn với lợi thế được đưa ra cho câu trả lời thứ 2 được đăng ở trên. Chỉ 0,02 đô la của tôi


30
Trong truy vấn KHÔNG IN, truy vấn con chỉ được thực hiện một lần, trong truy vấn EXISTS, truy vấn phụ được thực hiện cho mỗi hàng
Carrick

1
bạn thật tuyệt vời :) theo cách này tôi chuyển đổi truy vấn 25 giây của mình bằng cách sử dụng kết nối trái thành chỉ 0,1 giây
Bassem Shahin

3
câu trả lời không theo thứ tự cụ thể, vì vậy câu trả lời thứ hai không có nghĩa là bạn nghĩ nó có nghĩa gì.

38

Đây là lý thuyết tập hợp thuần túy mà bạn có thể đạt được với minusthao tác.

select id, name from table1
minus
select id, name from table2

Bạn có nghĩ rằng điều này là hiệu quả hơn nhiều so với tham gia trái?
uhs

Nó nên Lệnh trừ được thiết kế cho tình huống chính xác này. Tất nhiên cách duy nhất để đánh giá cho bất kỳ tập dữ liệu cụ thể nào là thử cả hai cách và xem cái nào chạy nhanh hơn.
Mùa đông

9
Trong T-SQL, toán tử tập hợp là "ngoại trừ". Điều này rất thuận tiện cho tôi và không gây ra bất kỳ sự chậm lại nào.

2
Trong SQLite, toán tử "trừ" cũng là "ngoại trừ".
lifjoy

MySQL không hỗ trợ toán tử MINUS.
Muhammad Azeem


16

Coi chừng cạm bẫy. Nếu trường Nametrong Table1chứa Nulls, bạn sẽ gặp bất ngờ. Tốt hơn là:

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT ISNULL(name ,'')
     FROM table1)

1
COALESCE> ISNULL (ISNULL là một bổ sung T-SQL vô dụng cho ngôn ngữ không có gì mới hoặc tốt hơn COALESCE)
Kris

14

Đây là những gì làm việc tốt nhất cho tôi.

SELECT *
FROM @T1
EXCEPT
SELECT a.*
FROM @T1 a
JOIN @T2 b ON a.ID = b.ID

Tốc độ này nhanh hơn gấp đôi so với bất kỳ phương pháp nào khác mà tôi đã thử.


Cảm ơn, Điều này cũng hoạt động tốt với số lượng lớn Dữ liệu! Nhưng tôi chỉ tự hỏi về thuật ngữ 'Ngoại trừ'.
PatsonLeaner


7

Đó là công việc sắc nét đối với tôi

SELECT * 
FROM [dbo].[table1] t1
LEFT JOIN [dbo].[table2] t2 ON t1.[t1_ID] = t2.[t2_ID]
WHERE t2.[t2_ID] IS NULL

1

Xem truy vấn:

SELECT * FROM Table1 WHERE
id NOT IN (SELECT 
        e.id
    FROM
        Table1 e
            INNER JOIN
        Table2 s ON e.id = s.id);

Về mặt khái niệm sẽ là: Tìm nạp các bản ghi khớp trong truy vấn phụ và sau đó trong truy vấn chính tìm nạp các bản ghi không thuộc truy vấn phụ.


0

Tôi sẽ đăng lại (vì tôi chưa đủ bình luận để trả lời) trong câu trả lời đúng .... trong trường hợp bất kỳ ai khác nghĩ rằng nó cần giải thích tốt hơn.

SELECT temp_table_1.name
FROM original_table_1 temp_table_1
LEFT JOIN original_table_2 temp_table_2 ON temp_table_2.name = temp_table_1.name
WHERE temp_table_2.name IS NULL

Và tôi đã thấy cú pháp TỪ cần dấu phẩy giữa các tên bảng trong myQuery nhưng trong sqlLite dường như thích khoảng trắng hơn.

Điểm mấu chốt là khi bạn sử dụng tên biến xấu, nó để lại câu hỏi. Các biến của tôi sẽ có ý nghĩa hơn. Và ai đó nên giải thích tại sao chúng ta cần một dấu phẩy hoặc không có dấu phẩy.


0

Nếu bạn muốn chọn trong người dùng cụ thể

SELECT tent_nmr FROM Statio_Tentative_Mstr
WHERE tent_npk = '90009'
AND
tent_nmr NOT IN (SELECT permintaan_tent FROM Statio_Permintaan_Mstr)

Đây tent_npklà khóa chính của người dùng

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.