Kimliği başka bir tabloda olmayan kaydı bulmak için SQL sorgusu


123

Veritabanında birincil anahtarı bağlayan iki tablom var ve aralarında ayrık bir küme bulmak istiyorum. Örneğin,

  • Table1sütunlara ( ID, Name) ve örnek verilere sahiptir:(1 ,John), (2, Peter), (3, Mary)
  • Table2sütunlara ( ID, Address) ve örnek verilere sahiptir:(1, address2), (2, address2)

I kimliği ile bir satırı çeker böylece Yani bir SQL sorgusu oluşturmak nasıl table1o değil table2. Bu durumda (3, Mary)iade edilmeli mi?

Ps. Kimlik, bu iki tablo için birincil anahtardır.

Şimdiden teşekkürler.


3
Gelecekteki sorular için bir ipucu olarak: her zaman hangi veritabanı sistemini (ve bu veritabanının hangi sürümünü) kullandığınızı tanımlayın. SQL , çoğu veritabanı sistemi tarafından kullanılan yalnızca Yapılandırılmış Sorgu Dilidir - bu pek yardımcı olmaz ... çoğu zaman veritabanlarında, sorunu çözmeyi kolaylaştıran ANSI / ISO SQL Standardının çok ötesinde uzantılar ve özellikler vardır - ancak bunun için siz bize hangi veritabanını kullandığınızı söylemeniz gerekiyor
marc_s

5
@marc_s: Ya dilden bağımsız bir çözüm arıyorlarsa, çünkü birden çok temel veritabanı sistemini desteklemeleri gerekiyorsa ya da veritabanı uygulaması soyutlanmışsa?
dwanderson

Merhaba @marc_s, bu durumda PostgreSQL kullanıyorum. Hatırlattığın için teşekkürler.
johnklee

Yanıtlar:


213

Bunu dene

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

8
@PrinceJea aslında buna bağlıdır. Açıklama için buraya bakın
John Woo

20 veriye sahip olduğumda çalışıyor, ama 20000 veriye sahip olduğumda çalışmıyor, şimdi kafam karıştı.
Frank

1
Neden olduğuna dair bir fikrim yok ama işe yaramıyor. Tabloda yaklaşık 10000 satırım var. Benim durumumda @JohnWoo'nun çözümü gayet iyi çalıştı.
Munam Yousuf

4
Bu yöntemin sınırlı sayıda değeri olduğu için "Değildir" de çok fazla değer çalışmayacaktır cf: dba-oracle.com/t_maximum_number_of_sql_in_list_values.htm
G.Busato

2
Bunu şu şekilde yapmak zorundaydım: Tablo1 NEREDE OLMADIĞIMIZDAN i seçin (i boş olmadığında
Tablo2’den

93

kullanım LEFT JOIN

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

Bunun çok büyük bir veritabanı için daha hızlı bir yaklaşım olduğunu düşünüyorum
Alex Jolig

12

Orada buna 3 yaklaşımlar temelde şunlardır: not exists, not inve left join / is null.

IS NULL ile LEFT JOIN

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

DEĞİL

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

MEVCUT DEĞİL

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

Hangisi daha iyi? Bu sorunun cevabının belli başlı RDBMS satıcılarına ayrılması daha iyi olabilir. Genel olarak konuşursak, select ... where ... in (select...)alt sorgudaki kayıt sayısının büyüklüğü bilinmediğinde kullanmaktan kaçınılmalıdır . Bazı satıcılar boyutu sınırlayabilir. Örneğin Oracle, 1.000 sınırına sahiptir . Yapılacak en iyi şey, üçünü de denemek ve yürütme planını göstermektir.

Özellikle PostgreSQL oluşturur, yürütme planı NOT EXISTSve LEFT JOIN / IS NULLaynıdır. Ben kişisel olarak bu NOT EXISTSseçeneği tercih ediyorum çünkü niyeti daha iyi gösteriyor. Sonuçta anlambilim, A'da pk'sinin B'de bulunmadığı kayıtları bulmak istediğinizdir .

PostgreSQL'e özel eski ama yine de altın: https://explainextended.com/2009/09/16/not-in-vs-not-exists-vs-left-join-is-null-postgresql/


10

Hızlı Alternatif

Her biri ~ 2M satır içeren iki tablo kullanarak bazı testler yaptım (postgres 9.5'te). Aşağıdaki bu sorgu, önerilen diğer sorgulardan en az 5 * daha iyi performans gösterdi:

-- 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
Bu, @Jhon Woo'nun çözümünden daha hızlı değildi. Postgres 9.6 kullanıyorum ve Jhon'un çözüm çalışma süresi yaklaşık 60ms. 120 saniye sonra oldukça bu çözüm ve sonuç yok.
froy001

5

@John Woo'nun yukarıdaki yorumunda / bağlantısında belirtilen noktaları göz önünde bulundurarak, genellikle bunu şu şekilde hallederim:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.