Truy vấn SQL để tìm bản ghi có ID không có trong bảng khác


123

Tôi có hai bảng với khóa chính ràng buộc trong cơ sở dữ liệu và tôi muốn tìm một tập hợp riêng biệt giữa chúng. Ví dụ,

  • Table1có các cột ( ID, Name) và dữ liệu mẫu:(1 ,John), (2, Peter), (3, Mary)
  • Table2có các cột ( ID, Address) và dữ liệu mẫu:(1, address2), (2, address2)

Vậy làm cách nào để tạo truy vấn SQL để tôi có thể tìm nạp hàng có ID từ table1 đó không có trong đó table2. Trong trường hợp này, (3, Mary)có nên trả lại?

Ps. ID là khóa chính cho hai bảng đó.

Cảm ơn trước.


3
Như một mẹo cho các câu hỏi trong tương lai: hãy luôn xác định hệ thống cơ sở dữ liệu (và phiên bản cơ sở dữ liệu đó) bạn đang sử dụng. SQL chỉ là Ngôn ngữ truy vấn có cấu trúc được sử dụng bởi hầu hết các hệ thống cơ sở dữ liệu - điều đó không thực sự giúp ích nhiều ... thường thì cơ sở dữ liệu có các phần mở rộng và tính năng vượt ra ngoài Tiêu chuẩn ANSI / ISO SQL giúp giải quyết vấn đề dễ dàng - nhưng đối với điều đó, bạn cần phải cho chúng tôi biết những gì bạn đang sử dụng cơ sở dữ liệu
marc_s

5
@marc_s: Điều gì sẽ xảy ra nếu họ đang tìm kiếm một giải pháp bất khả tri về ngôn ngữ, vì chúng cần hỗ trợ nhiều hệ thống cơ sở dữ liệu cơ bản hoặc việc triển khai cơ sở dữ liệu bị trừu tượng hóa?
dwanderson

Xin chào @marc_s, tôi đang sử dụng PostgreSQL trong trường hợp này. Cảm ơn vì đã nhắc nhở.
johnklee

Câu trả lời:


213

Thử cái này

SELECT ID, Name 
FROM   Table1 
WHERE  ID NOT IN (SELECT ID FROM Table2)

8
@PrinceJea thực sự nó phụ thuộc. Xem ở đây để làm rõ
John Woo

Khi tôi có 20 dữ liệu, nó hoạt động, nhưng khi tôi có 20000 dữ liệu, nó không hoạt động, tôi nhầm lẫn bây giờ.
Frank

1
Không có ý tưởng tại sao nhưng nó không hoạt động. Tôi có khoảng 10000 hàng trong bảng. Trong trường hợp của tôi, giải pháp của @JohnWoo hoạt động tốt.
Munam Yousuf

4
Nó sẽ không hoạt động vì chúng tôi có quá nhiều giá trị trong "Not In" vì phương thức này có một số giá trị hạn chế cf: dba-oracle.com/t_maximum_number_of_sql_in_list_values.htm
G.Busato 19/02/18

2
Tôi phải làm điều đó như thế này: chọn tôi từ Table1 nơi tôi NOT IN (SELECT i TỪ Table2 nơi mà tôi không phải là null ) và tôi không phải là null
jaksco

93

Sử dụng LEFT JOIN

SELECT  a.*
FROM    table1 a
            LEFT JOIN table2 b
                on a.ID = b.ID
WHERE   b.id IS NULL

Tôi nghĩ đây là cách tiếp cận nhanh hơn cho một cơ sở dữ liệu rất lớn
Alex Jolig

12

Về cơ bản có 3 cách tiếp cận đó: not exists, not inleft join / is null.

THAM GIA TRÁI với IS NULL

SELECT  l.*
FROM    t_left l
LEFT JOIN
        t_right r
ON      r.value = l.value
WHERE   r.value IS NULL

KHÔNG VÀO

SELECT  l.*
FROM    t_left l
WHERE   l.value NOT IN
        (
        SELECT  value
        FROM    t_right r
        )

KHÔNG TỒN TẠI

SELECT  l.*
FROM    t_left l
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    t_right r
        WHERE   r.value = l.value
        )

Cái nào tốt hơn? Câu trả lời cho câu hỏi này có thể tốt hơn nếu được chia nhỏ cho các nhà cung cấp RDBMS cụ thể. Nói chung, người ta nên tránh sử dụng select ... where ... in (select...)khi độ lớn của số lượng bản ghi trong truy vấn con là không xác định. Một số nhà cung cấp có thể giới hạn kích thước. Ví dụ, Oracle có giới hạn 1.000 . Điều tốt nhất cần làm là thử cả ba và hiển thị kế hoạch thực hiện.

Cụ thể hình thức PostgreSQL, kế hoạch thực thi của NOT EXISTSLEFT JOIN / IS NULLgiống nhau. Cá nhân tôi thích NOT EXISTStùy chọn hơn vì nó cho thấy ý định tốt hơn. Sau tất cả các ngữ nghĩa là bạn muốn tìm các bản ghi trong A mà pk của nó không tồn tại trong B .

Tuy cũ nhưng vẫn còn vàng, dành riêng cho PostgreSQL: https://explainextended.com/2009/09/16/not-in-vs-not-exists-vs-left-join-is-null-postgresql/


10

Thay thế nhanh

Tôi đã chạy một số thử nghiệm (trên postgres 9.5) bằng cách sử dụng hai bảng với ~ 2 triệu hàng mỗi bảng. Truy vấn dưới đây hoạt động tốt hơn ít nhất 5 * so với các truy vấn khác được đề xuất:

-- Count
SELECT count(*) FROM (
    (SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2;

-- Get full row
SELECT table1.* FROM (
    (SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2 JOIN table1 ON t1_not_in_t2.id=table1.id;

1
Cách này không nhanh hơn giải pháp của @Jhon Woo. Tôi đang sử dụng Postgres 9.6 và với thời gian chạy giải pháp của Jhon là khoảng 60ms. Trong khi tôi khá giải pháp này sau 120 giây và không có kết quả.
froy001

5

Hãy ghi nhớ những điểm được đưa ra trong nhận xét / liên kết của @John Woo ở trên, đây là cách tôi thường xử lý:

SELECT t1.ID, t1.Name 
FROM   Table1 t1
WHERE  NOT EXISTS (
    SELECT TOP 1 NULL
    FROM Table2 t2
    WHERE t1.ID = t2.ID
)

2
SELECT COUNT(ID) FROM tblA a
WHERE a.ID NOT IN (SELECT b.ID FROM tblB b)    --For count


SELECT ID FROM tblA a
WHERE a.ID NOT IN (SELECT b.ID FROM tblB b)    --For results
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.