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.

johnklee
sumber
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)
Pangeran Jea
sumber
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
John Woo
sumber
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/

L. Holanda
sumber
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;
polvoazul.dll
sumber
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
)
CaseyR
sumber
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
JoshYates1980
sumber