SQL EXISTS deyimleri nasıl çalışır?


89

SQL öğrenmeye çalışıyorum ve EXISTS ifadelerini anlamakta zorlanıyorum. "Var" ile ilgili şu alıntıyla karşılaştım ve bir şey anlamadım:

Var operatörünü kullanarak, alt sorgunuz sıfır, bir veya çok sayıda satır döndürebilir ve koşul, alt sorgunun herhangi bir satır döndürüp döndürmediğini kontrol eder. Alt sorgunun seçme cümlesine bakarsanız, tek bir değişmez değerden (1) oluştuğunu görürsünüz; içeren sorgudaki koşulun yalnızca kaç satır döndürüldüğünü bilmesi gerektiğinden, alt sorgunun döndürdüğü gerçek veriler ilgisizdir.

Anlamadığım şey, dış sorgunun alt sorgunun hangi satırı kontrol ettiğini nasıl bildiği? Örneğin:

SELECT *
  FROM suppliers
 WHERE EXISTS (select *
                 from orders
                where suppliers.supplier_id = orders.supplier_id);

Tedarikçiden ve siparişler tablosundan gelen kimlik eşleşirse, alt sorgunun doğru döneceğini ve tedarikçilerin tablosundaki eşleşen satırdaki tüm sütunların çıkarılacağını anlıyorum. Anlamadığım şey, yalnızca doğru veya yanlış döndürülüyorsa, alt sorgunun hangi belirli satırın (tedarikçi kimliği 25 olan satır diyelim) yazdırılması gerektiğini nasıl ilettiği.

Bana öyle geliyor ki, dış sorgu ile alt sorgu arasında bir ilişki yok.

Yanıtlar:


100

Bu şekilde düşün:

'Her' satır için Suppliers, Ordertabloda koşulu karşılayan bir satırın var olup olmadığını kontrol edin Suppliers.supplier_id(bu, Dış sorgu geçerli 'satırından' gelir) = Orders.supplier_id. İlk eşleşen satırı bulduğunuzda, orada durun - WHERE EXISTStatmin edildi.

Dış sorgu ve alt sorgu arasındaki sihirli bağlantı, Supplier_iddeğerlendirilen her satır için dış sorgudan alt sorguya geçirilmesi gerçeğinde yatmaktadır .

Ya da başka bir deyişle, dış sorgunun her tablo satırı için alt sorgu yürütülür.

Bu, alt sorgunun bütün üzerinde yürütülmesi ve "doğru / yanlış" ı alması ve ardından bu "doğru / yanlış" koşulunu dış sorgu ile eşleştirmeye çalışması gibi DEĞİLDİR.


7
Teşekkürler! "Bir bütün olarak yürütülen alt sorgu gibi DEĞİLDİR ve" doğru / yanlış "ı alır ve ardından bu" doğru / yanlış "koşulunu dış sorgu ile eşleştirmeye çalışır." benim için bunu gerçekten açıklığa kavuşturan şeydi, düşünmeye devam ediyorum, alt sorgular bu şekilde çalışıyor (ve çoğu kez işe yarıyor), ancak söyledikleriniz mantıklı çünkü alt sorgu dış sorguya dayanıyor ve bu nedenle her satırda bir kez yürütülmesi gerekiyor
Clarence Liu

32

Bana öyle geliyor ki, dış sorgu ile alt sorgu arasında bir ilişki yok.

EXISTS örneğindeki WHERE cümlesinin ne işe yaradığını düşünüyorsunuz? TEDARİKÇİLER referansı, EXISTS maddesinin FROM veya JOIN maddelerinde yer almadığında bu sonuca nasıl varırsınız?

EXISTS, DOĞRU / YANLIŞ için değer verir ve kriterlerin ilk eşleşmesinde DOĞRU olarak çıkar - bundan daha hızlı olmasının nedeni budur IN. Ayrıca, bir EXISTS'deki SELECT yan tümcesinin göz ardı edildiğini unutmayın - IE:

SELECT s.*
  FROM SUPPLIERS s
 WHERE EXISTS (SELECT 1/0
                 FROM ORDERS o
                WHERE o.supplier_id = s.supplier_id)

... bir bölümü sıfır hata ile vurmalı, ama olmayacak. WHERE cümlesi, bir EXISTS cümlesinin en önemli parçasıdır.

Ayrıca, bir JOIN'in EXISTS için doğrudan bir ikame olmadığını unutmayın, çünkü üst ile ilişkilendirilmiş birden fazla alt kayıt varsa yinelenen üst kayıtlar olacaktır.


1
Hala bir şey eksik. İlk maçta çıkarsa, çıktı nasıl olur da o.supplierid = s.supplierid? Bunun yerine ilk sonucu çıktı olarak vermez mi?
Dan

3
@Dan: EXISTSÇıkışlar, ilk maçta DOĞRU döndürüyor - çünkü tedarikçi SİPARİŞLER tablosunda en az bir kez var. SİPARİŞLER'de birden fazla çocuk ilişkisi olması nedeniyle TEDARİKÇİ verilerinin kopyasını görmek istiyorsanız, bir BİRLEŞTİRME kullanmanız gerekir. Ancak çoğu kişi bu yinelemeyi istemiyor ve GROUP BY / DISTINCT'i çalıştırmak sorguya ek yük getirebilir. SQL Server'dan EXISTSdaha verimli SELECT DISTINCT ... FROM SUPPLIERS JOIN ORDERS ..., son zamanlarda Oracle veya MySQL üzerinde test edilmedi.
OMG Midilli

Bir sorum vardı, dış sorguda SEÇİLEN her kayıt için eşleştirme yapılır. Tedarikçilerden seçilen 5 satır varsa, siparişlerden 5 kez getiriyoruz.
Rahul Kadukar

24

Ya kullanarak özdeş sonuçlar verebilir JOIN, EXISTS, IN, veya INTERSECT:

SELECT s.supplier_id
FROM suppliers s
INNER JOIN (SELECT DISTINCT o.supplier_id FROM orders o) o
    ON o.supplier_id = s.supplier_id

SELECT s.supplier_id
FROM suppliers s
WHERE EXISTS (SELECT * FROM orders o WHERE o.supplier_id = s.supplier_id)

SELECT s.supplier_id 
FROM suppliers s 
WHERE s.supplier_id IN (SELECT o.supplier_id FROM orders o)

SELECT s.supplier_id
FROM suppliers s
INTERSECT
SELECT o.supplier_id
FROM orders o

1
harika bir cevap, ama korelasyonu önlemek için var kullanmamanın daha iyi olduğunu da unutmayın
Florian Fröhlich

1
Tedarikçilerin 10 milyon satırı ve siparişlerin 100 milyon satırı varsa hangi sorgunun daha hızlı çalışacağını düşünüyorsunuz ve neden?
Teja

7

Bunun gibi görünen bir where cümlesiniz varsa:

WHERE id in (25,26,27) -- and so on

neden bazı satırların döndürüldüğünü ve bazılarının dönmediğini kolayca anlayabilirsiniz.

Where cümlesi böyle olduğunda:

WHERE EXISTS (select * from orders where suppliers.supplier_id = orders.supplier_id);

sadece şu anlama gelir: siparişler tablosunda aynı kimliğe sahip mevcut bir kaydı olan satırları döndür.


2

Bu çok güzel bir soru, bu yüzden bloguma bu konuyla ilgili çok detaylı bir yazı yazmaya karar verdim .

Veritabanı tablo modeli

Veritabanımızda bire çok tablo ilişkisi oluşturan aşağıdaki iki tablonun olduğunu varsayalım.

SQL EXISTS tabloları

studentTablo üst vestudent_grade öğrenci tablosundaki id Birincil Anahtar sütununa başvurmak bir student_id Yabancı anahtar sütunu vardır çünkü çocuk tablodur.

student tableAşağıdaki iki kayıtlarını içerir:

| id | first_name | last_name | admission_score |
|----|------------|-----------|-----------------|
| 1  | Alice      | Smith     | 8.95            |
| 2  | Bob        | Johnson   | 8.75            |

Ve, student_grademasa öğrencilerin almış notları saklar:

| id | class_name | grade | student_id |
|----|------------|-------|------------|
| 1  | Math       | 10    | 1          |
| 2  | Math       | 9.5   | 1          |
| 3  | Math       | 9.75  | 1          |
| 4  | Science    | 9.5   | 1          |
| 5  | Science    | 9     | 1          |
| 6  | Science    | 9.25  | 1          |
| 7  | Math       | 8.5   | 2          |
| 8  | Math       | 9.5   | 2          |
| 9  | Math       | 9     | 2          |
| 10 | Science    | 10    | 2          |
| 11 | Science    | 9.4   | 2          |

SQL VAR

Diyelim ki Matematik dersinde 10 not alan tüm öğrencileri almak istiyoruz.

Yalnızca öğrenci tanımlayıcısıyla ilgileniyorsak, bunun gibi bir sorgu çalıştırabiliriz:

SELECT
    student_grade.student_id
FROM
    student_grade
WHERE
    student_grade.grade = 10 AND
    student_grade.class_name = 'Math'
ORDER BY
    student_grade.student_id

Ancak, uygulama studentyalnızca tanımlayıcıyı değil, a'nın tam adını görüntülemekle ilgileniyor , bu nedenlestudent tablodaki .

studentMath'da notu 10 olan kayıtları filtrelemek için EXISTS SQL operatörünü şu şekilde kullanabiliriz:

SELECT
    id, first_name, last_name
FROM
    student
WHERE EXISTS (
    SELECT 1
    FROM
        student_grade
    WHERE
        student_grade.student_id = student.id AND
        student_grade.grade = 10 AND
        student_grade.class_name = 'Math'
)
ORDER BY id

Yukarıdaki sorguyu çalıştırırken sadece Alice satırının seçildiğini görebiliriz:

| id | first_name | last_name |
|----|------------|-----------|
| 1  | Alice      | Smith     |

Dış sorgu student, istemciye döndürmek istediğimiz satır sütunlarını seçer . Ancak, WHERE yan tümcesi, ilişkili bir iç alt sorgu ile EXISTS işlecini kullanıyor.

EXISTS operatörü, alt sorgu en az bir kayıt döndürürse doğru, satır seçilmezse yanlış döndürür. Veritabanı motorunun alt sorguyu tamamen çalıştırması gerekmez. Tek bir kayıt eşleşirse, EXISTS operatörü true değerini döndürür ve ilişkili diğer sorgu satırı seçilir.

student_gradeTablonun öğrenci_kimliği sütunu dış öğrenci tablosunun kimlik sütunuyla eşleştiği için iç alt sorgu ilişkilidir .


Ne harika bir cevap. Sanırım yanlış bir örnek kullandığım için konsepti anlamadım. Does EXISTsadece ilişkili alt sorgu ile çalışmak? Sadece 1 tablo içeren sorgu ile oynuyordum SELECT id FROM student WHERE EXISTS (SELECT 1 FROM student WHERE student.id > 1). Yazdıklarımın basit bir WHERE sorgusuyla başarılabileceğini biliyorum ama onu sadece VARLIKLARI anlamak için kullanıyordum. Tüm satırları aldım. Gerçekten de ilişkili alt sorgu kullanmamamdan mı kaynaklanıyor? Teşekkürler.
Bowen Liu

Dış sorgunun kayıtlarını filtrelemek istediğinizden, yalnızca ilişkili alt sorgular için anlamlıdır. Sizin durumunuzda, iç sorgu WHERE TRUE ile değiştirilebilir
Vlad Mihalcea

Teşekkürler Vlad. Bende böyle düşünmüştüm. Bu sadece ben onunla uğraşırken ortaya çıkan tuhaf bir fikir. İlişkili alt sorgu kavramını gerçekten bilmiyordum. Ve şimdi dış sorgunun satırlarını iç sorgu ile filtrelemek çok daha mantıklı.
Bowen Liu

0

EXISTS, alt sorgunun en az bir satır döndürdüğü anlamına gelir, gerçekten budur. Bu durumda, bu ilişkili bir alt sorgudur çünkü dış tablonun Supplier_id'sini iç tablonun Supplier_id'ine kadar kontrol eder. Bu sorgu aslında şunu söylüyor:

Tüm tedarikçileri seçin Her tedarikçi kimliği için, bu tedarikçi için bir sipariş olup olmadığına bakın Tedarikçi siparişler tablosunda yoksa, tedarikçiyi sonuçlardan çıkarın, siparişler tablosunda karşılık gelen satırları olan tüm tedarikçileri GERİ DÖN

Bu durumda aynı şeyi INNER JOIN ile de yapabilirsiniz.

SELECT suppliers.* 
  FROM suppliers 
 INNER 
  JOIN orders 
    ON suppliers.supplier_id = orders.supplier_id;

Midilli yorumu doğru. Bu birleştirme ile gruplama yapmanız veya ihtiyacınız olan verilere bağlı olarak farklı seçmeniz gerekir.


4
Bir üst öğe ile birden fazla alt kayıt ilişkilendirilmişse iç birleşim, EXISTS'ten farklı sonuçlar üretecektir - bunlar aynı değildir.
OMG Pony'leri

Sanırım kafa karışıklığım, bir EXISTS ile alt sorgunun doğru veya yanlış döndürdüğünü okumuş olmam olabilir; ama geri döndüğü tek şey bu olamaz, değil mi? Alt sorgu, tüm "siparişler tablosunda karşılık gelen satırları olan tedarikçileri" de döndürüyor mu? Ama öyleyse, EXISTS ifadesi nasıl bir mantıksal sonuç döndürüyor? Ders kitaplarında okuduğum her şey, bunun yalnızca bir boole sonucu döndürdüğünü söylüyor, bu yüzden kodun sonucunu bana döndürdüğü söylenenlerle uzlaştırmakta zorlanıyorum.
Dan

Varolanları bir işlev gibi okuyun ... MEVCUT (sonuç kümesi). EXISTS işlevi, sonuç kümesinde satırlar varsa doğru, boşsa yanlış döndürür. Bu temelde bu.
David Fells

3
@Dan, EXISTS () 'in her kaynak satırı için bağımsız olarak mantıksal olarak değerlendirildiğini düşünün - tüm sorgu için tek bir değer değildir.
Arvo

-1

Tanımladığınız şey, ilişkili bir alt sorguya sahip sözde bir sorgu .

(Genel olarak), bunun yerine bir birleşim kullanarak sorgu yazarak kaçınmanız gereken bir şeydir:

SELECT suppliers.* 
FROM suppliers 
JOIN orders USING supplier_id
GROUP BY suppliers.supplier_id

Aksi takdirde, dış sorgudaki her satır için alt sorgu çalıştırılacaktır.


2
Bu iki çözüm eşdeğer değildir. JOIN orders, birleştirme koşuluyla eşleşen birden fazla satır varsa, EXISTS alt sorgusundan farklı bir sonuç verir .
a_horse_with_no_name

1
alternatif çözüm için teşekkürler. ancak ilişkili alt sorgu ve birleştirme arasında bir seçenek verilirse, daha verimli olduğu için join ile gitmem gerektiğini önerir misiniz?
sunny_dev
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.