Kueri SQL untuk menemukan rekaman dengan ID bukan di tabel lain


123

Saya memiliki dua tabel dengan kunci primer yang mengikat dalam database dan saya ingin menemukan satu set terputus di antara mereka. Sebagai contoh,

  • Table1memiliki kolom ( ID, Name) dan contoh data:(1 ,John), (2, Peter), (3, Mary)
  • Table2memiliki kolom ( ID, Address) dan contoh data:(1, address2), (2, address2)

Jadi bagaimana cara membuat kueri SQL sehingga saya bisa mengambil baris dengan ID table1yang tidak ada di dalamnya table2. Dalam hal ini, (3, Mary)harus dikembalikan?

Ps. ID adalah kunci utama untuk dua tabel tersebut.

Terima kasih sebelumnya.


3
Sebagai tip untuk pertanyaan mendatang: selalu tentukan sistem database apa (dan versi database mana) yang Anda gunakan. SQL hanyalah Bahasa Kueri Terstruktur yang digunakan oleh sebagian besar sistem database - yang tidak terlalu banyak membantu ... sering kali, database memiliki ekstensi dan fitur yang jauh melampaui ANSI / ISO SQL Standard yang memudahkan pemecahan masalah - tetapi untuk itu, Anda perlu memberi tahu kami database apa yang Anda gunakan
marc_s

5
@marc_s: Bagaimana jika mereka mencari solusi tanpa bahasa, karena mereka perlu mendukung beberapa sistem database yang mendasarinya, atau implementasi database disarikan?
dwanderson

Hai @marc_s, saya menggunakan PostgreSQL dalam kasus ini. Terima kasih sudah mengingatkan.
johnklee

Jawaban:


213

Coba ini

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

8
@PrinceJea sebenarnya itu tergantung. Lihat di sini untuk klarifikasi
John Woo

Ketika saya memiliki 20 data, itu berfungsi, tetapi ketika saya memiliki 20000 data, itu tidak berfungsi, saya bingung sekarang.
Frank

1
Tidak tahu mengapa tapi tidak berhasil. Saya memiliki sekitar 10.000 baris dalam tabel. Dalam kasus saya, solusi @JohnWoo bekerja dengan baik.
Munam Yousuf

4
Ini tidak akan berhasil. Kita terlalu banyak nilai dalam "Not In" karena metode ini memiliki jumlah nilai yang terbatas cf: dba-oracle.com/t_maximum_number_of_sql_in_list_values.htm
G.Busato

2
Saya harus melakukannya seperti ini: pilih i dari Table1 WHERE I NOT IN (PILIH i FROM Table2 di mana saya bukan null ) dan saya bukan null
jaksco

93

Menggunakan LEFT JOIN

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

Saya pikir ini adalah pendekatan yang lebih cepat untuk database yang sangat besar
Alex Jolig

12

Pada dasarnya ada 3 pendekatan untuk itu: not exists, not indan left join / is null.

LEFT JOIN dengan IS NULL

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

TIDAK MASUK

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

TIDAK ADA

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

Mana yang lebih baik? Jawaban atas pertanyaan ini mungkin lebih baik dipecah menjadi vendor RDBMS khusus utama. Secara umum, seseorang harus menghindari penggunaan select ... where ... in (select...)ketika besarnya jumlah record dalam sub-query tidak diketahui. Beberapa vendor mungkin membatasi ukurannya. Oracle, misalnya, memiliki batas 1.000 . Hal terbaik untuk dilakukan adalah mencoba ketiganya dan menunjukkan rencana eksekusi.

Secara khusus membentuk PostgreSQL, rencana pelaksanaan NOT EXISTSdan LEFT JOIN / IS NULLadalah sama. Saya pribadi lebih suka NOT EXISTSopsi karena menunjukkan maksud yang lebih baik. Setelah semua semantik adalah bahwa Anda ingin menemukan catatan A yang pk yang tidak ada di B .

Tua tapi masih emas, khusus untuk PostgreSQL: https://explainextended.com/2009/09/16/not-in-vs-not-exists-vs-left-join-is-null-postgresql/


10

Alternatif Cepat

Saya menjalankan beberapa tes (pada postgres 9.5) menggunakan dua tabel dengan masing-masing ~ 2 juta baris. Kueri di bawah ini berkinerja setidaknya 5 * lebih baik daripada kueri lain yang diusulkan:

-- 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
Ini tidak lebih cepat dari solusi @Jhon Woo. Saya menggunakan Postgres 9.6 dan dengan runtime solusi Jhon adalah sekitar 60ms. Sementara saya cukup solusi ini setelah 120 detik dan tidak ada hasil.
froy001

5

Mengingat poin-poin yang dibuat dalam komentar / tautan @John Woo di atas, inilah cara saya biasanya menanganinya:

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.