Başka bir tabloda eşleşen girişi olmayan satırlar nasıl seçilir?


323

Bir veritabanı uygulaması üzerinde bazı bakım çalışmaları yapıyorum ve bir tablodaki değerler yabancı anahtarlar tarzında kullanılıyor olsa da, sevinçlerin sevincini keşfettim, tablolarda yabancı anahtar kısıtlamaları yok.

Bu sütunlara FK kısıtlamaları eklemeye çalışıyorum, ama bu, naif olarak düzeltilmiş önceki hatalardan tablolarda zaten bir sürü kötü veri yükü olduğu için, olmayan satırları bulmam gerektiğini buluyorum diğer tabloyla eşleşip silin.

Web üzerinde bu tür bir sorgu bazı örnekler buldum, ama hepsi açıklamalar yerine örnekler veriyor gibi görünüyor ve neden çalıştıklarını anlamıyorum.

Birisi Doğrusu bu her tablo için SO çalışan gelme yerine, bu sorguları kendim yapmak, böylece, o yapıyor bir başka tabloda hiç maçlarla tüm satırları döndüren sorgu ve ne nasıl oluştuğunu açıklayabilir misin karmaşa vardır FK kısıtlaması yok mu?

Yanıtlar:


614

İşte basit bir sorgu:

SELECT t1.ID
FROM Table1 t1
    LEFT JOIN Table2 t2 ON t1.ID = t2.ID
WHERE t2.ID IS NULL

Kilit noktalar:

  1. LEFT JOINkullanıldı; bu, Table1eşleşen bir satır olup olmadığına bakılmaksızın TÜM satırları döndürür Table2.

  2. WHERE t2.ID IS NULLmaddesi; bu, döndürülen sonuçları yalnızca döndürülen kimliğin Table2boş olduğu satırlarla sınırlar; diğer bir deyişle, söz konusu kimlik için hiçbir kayıt YOK olur . kimliğin eşleşmediği tüm kayıtlar için NULL olarak döndürülür .Table2Table1Table2.IDTable1Table2


4
Kimlik NULL olursa başarısız
Michael

169
@Michael - Şemanızda bir NULLkimlik olması geçerliyse, daha büyük sorunlarınız olabilir, kabul etmez misiniz? :)
rinogo

1
table1'den sonra table2'den daha fazla kayıt olsa bile bu işe yarar mı? table1 100 kaydı ve table2 200 kaydı (100 eşleşen / katıl ve 100 eşleşen / katılmıyorsa) 200 kaydın tümünü döndürür müsünüz?
Juan Velez

1
WHERE deyimi ile LEFT JOIN arasında hiçbir etkileşim olmadığından emin olmak için sol birleşimi alt sorgu / satır içi görünüm olarak sarmak isterim.
Andrew Wolfe

1
@Jas Cevabın anahtar noktası 1, ilk tablodan TÜM satırlar, hatta t1.ID = t2.ID sol birleşim koşuluyla eşleşmeyenler. İlk satırı SELECT t1.ID, t2.IDWHERE satırına değiştirir ve kaldırırsanız, bunun nasıl çalıştığı hakkında daha iyi bir fikir edinirsiniz.
Peter Laboš

97

Ben kullanmak EXISTSdaha güçlü olduğu için, sen durumda, katılmak istediğiniz satırları seçmek daha doğrusu yani edebilirsiniz ifadesini LEFT JOINEğer katıldı tabloda ne herşeyi almak zorunda. Verimliliği muhtemelen LEFT JOINsıfır testi ile aynıdır .

SELECT t1.ID
FROM Table1 t1
WHERE NOT EXISTS (SELECT t2.ID FROM Table2 t2 WHERE t1.ID = t2.ID)

Bu basit bir şey, en iyi yürütme için sorgu iyileştirici tarafından kolayca ele alınır.
Andrew Wolfe

2
Evet, ana avantajı EXISTSdeğişkenliğidir.
Ondrej Bozek

1
Basit, zarif ve sorunumu çözdü! Güzel bir!
MikeMighty

2
Aslında bir sorgunun hızını 7 saniyeden 200 ms'ye düşürdüm ... (karşılaştırıldığında WHERE t2.id IS NULL) Teşekkürler.
Moti Korets

4
@MotiKorets demek hızını arttırmak demek :)
Ondrej Bozek

14
SELECT id FROM table1 WHERE foreign_key_id_column NOT IN (SELECT id FROM table2)

Tablo 1'de yabancı anahtar kısıtlamasını eklemek istediğiniz bir sütun vardır, ancak foreign_key_id_columnhepsindeki değerlerin tümü idtablo 2'deki ile eşleşmez .

  1. İlk seçim idtablo1'deki s'yi listeler . Bunlar silmek istediğimiz satırlar olacak.
  2. NOT INNerede açıklamada fıkra değeri sadece satır sorgu sınırlar foreign_key_id_columntablo 2 listesinde değildir ids.
  3. SELECTParantez içindeki ifadesi bütün bir listesini alacak idtablo 2'de olan s.

@ zb226: Bağlantınız, INyan tümcenin sınırlarıyla ilgili değişmez değerler listesiyle ilgilidir. INAlt sorgunun sonucu olan bir cümle kullanmak için geçerli değildir . Bu soruya kabul edilen cevap aslında bir alt sorgu kullanarak sorunu çözer. (Değişken değerlerin büyük bir listesi sorunludur çünkü çok büyük bir SQL ifadesi oluşturur. Bir alt sorgu düzgün çalışır, çünkü sonuç listesi büyük olsa bile SQL ifadesinin kendisi küçüktür.)
Kannan Goundan

@KannanGoundan Mutlak haklısın. Hatalı yorumu geri çekmek.
zb226

8

T2Kısıtlamayı eklediğiniz tablo nerede :

SELECT *
FROM T2
WHERE constrained_field NOT
IN (
    SELECT DISTINCT t.constrained_field
    FROM T2 
    INNER JOIN T1 t
    USING ( constrained_field )
)

Ve sonuçları silin.


4

Aşağıdaki 2 tabloyu alalım (maaş ve çalışan) resim açıklamasını buraya girin

Şimdi maaş olmayan çalışan tablodan bu kayıtları istiyorum. Bunu 3 şekilde yapabiliriz:

  1. İç birleştirmeyi kullanma
select * from employee
where id not in(select e.id from employee e inner join salary s on e.id=s.id)

resim açıklamasını buraya girin

  1. Sol dış birleştirmeyi kullanma
select * from employee e 
left outer join salary s on e.id=s.id  where s.id is null

resim açıklamasını buraya girin

  1. Tam Birleştirmeyi Kullanma
select * from employee e
full outer join salary s on e.id=s.id where e.id not in(select id from salary)

resim açıklamasını buraya girin



0

Sen tercih olabilir Görünümler aşağıda gösterildiği gibi:

CREATE VIEW AuthorizedUserProjectView AS select t1.username as username, t1.email as useremail, p.id as projectid, 
(select m.role from userproject m where m.projectid = p.id and m.userid = t1.id) as role 
FROM authorizeduser as t1, project as p

ve ardından seçim veya güncelleme için görünüm üzerinde çalışın:

select * from AuthorizedUserProjectView where projectid = 49

aşağıdaki resimde gösterildiği gibi sonuç veren, yani eşleşmeyen sütun için null doldurulmuştur.

[Result of select on the view][1]

0

Hangisinin Optimize Edildiğini Bilmiyorum (@AdaTheDev ile karşılaştırıldığında) ama kullandığımda bu daha hızlı görünüyor (benim için en az)

SELECT id  FROM  table_1 EXCEPT SELECT DISTINCT (table1_id) table1_id FROM table_2

Başka bir belirli özellik elde etmek istiyorsanız şunları kullanabilirsiniz:

SELECT COUNT(*) FROM table_1 where id in (SELECT id  FROM  table_1 EXCEPT SELECT DISTINCT (table1_id) table1_id FROM table_2);


-2

Böyle bir şey yapabilirsin

   SELECT IFNULL(`price`.`fPrice`,100) as fPrice,product.ProductId,ProductName 
          FROM `products` left join `price` ON 
          price.ProductId=product.ProductId AND (GeoFancingId=1 OR GeoFancingId 
          IS NULL) WHERE Status="Active" AND Delete="No"

-6

Her iki tabloda da eşleşen girişi olmayan satırlar nasıl seçilir?

    [dbo] 'dan * seçin. [EmpPDetails] e
     e.Gid = d.Gid'deki [Cinsiyet] d.
    e.Gid değeri Null olduğunda

    Birlik 
    [dbo] 'dan * seçin. [EmpPDetails] e
     [Çalışan] olarak ayrıldı. [Cinsiyet] d e.Gid = d.Gid
    Burada d.Gid değeri Null

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.