SQL FROM satırında birden fazla tablo vs katılmak yaptı?


256

Çoğu SQL lehçesi aşağıdaki sorguların ikisini de kabul eder:

SELECT a.foo, b.foo
FROM a, b
WHERE a.x = b.x

SELECT a.foo, b.foo
FROM a
LEFT JOIN b ON a.x = b.x

Şimdi açıkça bir dış birleşim gerektiğinde, ikinci sözdizimi gereklidir. Ama bir iç birleşim yaparken neden ikinci sözdizimini ilkine tercih etmeliyim (ya da tam tersi)?


1
Guffa: Bunu nasıl buldun? Her ne kadar benim sorum "nasıl yaparım" daha iyi uygulama olmasına rağmen
jmucchiello

En iyi uygulama olduğu için lütfen bunu bir Wiki yapın.
Binoj Antony

1
Kimsenin bu ikisinin performansı hakkında yorum yapmadığını sanmıyorum. Herhangi biri önemli farklılıklar konusunda makul bir şeyi onaylayabilir veya anlatabilir mi?
ahnbizcad

@ahnbizcad Verilen iki sorgu aynı şeyi yapmaz. Birincisi, INNER JOIN ON ile aynı şekilde döner. Uygulama DBMS sürümüne özgüdür ve o zaman bile çok az garantisi vardır. Ancak virgül vs INNER JOIN ON / WHERE ve CROSS JOIN NEREDE gibi virgül vakalarına denk gelen DBMS dönüşümleri önemsizdir. İlişkisel veritabanı sorgu optimizasyonu / uygulaması hakkında bilgi edinin.
philipxy

kaynak tavsiyeniz var mı? buradan öğrenmeye çalıştığım devasa, yoğun kılavuzlar.
ahnbizcad

Yanıtlar:


319

Yalnızca tabloları listeleyen WHEREve birleştirme ölçütlerini belirtmek için yan tümcesi kullanan eski sözdizimi çoğu modern veritabanında kullanımdan kaldırılmıştır.

Sadece şov için değil, aynı sorguda hem INNER hem de OUTER birleşimlerini kullandığınızda eski sözdiziminin belirsiz olma olasılığı vardır.

Sana bir örnek vereyim.

Sisteminizde 3 tablonuz olduğunu varsayalım:

Company
Department
Employee

Her tablo birbirine bağlı çok sayıda satır içerir. Birden fazla şirketiniz var ve her şirketin birden çok departmanı olabilir ve her departmanın birden fazla çalışanı olabilir.

Tamam, şimdi aşağıdakileri yapmak istiyorsunuz:

Tüm şirketleri listeleyin ve tüm departmanlarını ve tüm çalışanlarını ekleyin. Bazı şirketlerin henüz departmanları olmadığını, ancak bunları da dahil ettiğinizden emin olun. Yalnızca çalışanları olan departmanları aldığınızdan emin olun, ancak her zaman tüm şirketleri listeleyin.

Yani bunu yaparsınız:

SELECT * -- for simplicity
FROM Company, Department, Employee
WHERE Company.ID *= Department.CompanyID
  AND Department.ID = Employee.DepartmentID

Sonuncunun sadece insanlarla departmanlar olmasını istediğiniz kriterleri yerine getirmek için bir iç birleşim olduğunu unutmayın.

Tamam, şimdi ne olacak. Sorun, veritabanı motoruna, sorgu iyileştiriciye, dizinlere ve tablo istatistiklerine bağlı olmasıdır. Açıklamama izin ver.

Sorgu iyileştirici, bunu yapmanın yolunun önce bir şirket almak, sonra departmanları bulmak ve daha sonra çalışanlarla içsel bir katılım yapmak olduğunu belirlerse, departmanı olmayan herhangi bir şirket elde edemezsiniz.

Bunun nedeni, WHEREcümlenin satırların tek tek bölümlerini değil, hangi satırın nihai sonuçla sonuçlandığını belirlemesidir .

Ve bu durumda, sol katılma nedeniyle, Department.ID sütunu NULL olur ve bu nedenle INNER, Employee JOIN söz konusu olduğunda, Employee satırı için bu kısıtlamayı yerine getirmenin bir yolu yoktur ve bu nedenle görünür.

Öte yandan, sorgu optimize edici önce departman-çalışan katılımı ile başa çıkmaya karar verirse ve daha sonra şirketlerle sol katılım gerçekleştirirse, bunları göreceksiniz.

Yani eski sözdizimi belirsiz. Sorgu ipuçlarıyla uğraşmadan ne istediğinizi belirtmenin bir yolu yoktur ve bazı veritabanlarının hiçbir yolu yoktur.

Yeni sözdizimini girin, bununla seçim yapabilirsiniz.

Örneğin, tüm şirketlerin olmasını istiyorsanız, sorunun açıklandığı gibi, şunu yazardınız:

SELECT *
FROM Company
     LEFT JOIN (
         Department INNER JOIN Employee ON Department.ID = Employee.DepartmentID
     ) ON Company.ID = Department.CompanyID

Burada departman-çalışan katılımının bir katılım olarak yapılmasını ve ardından bunun sonuçlarına şirketler ile katılmasını istediğinizi belirtirsiniz.

Ayrıca, yalnızca adlarında X harfini içeren departmanları istediğinizi varsayalım. Yine, eski stil birleşmeleriyle, adını da X olan herhangi bir departman yoksa, ancak yeni sözdizimi ile, şirketi de kaybetme riskiyle karşı karşıya kalırsınız:

SELECT *
FROM Company
     LEFT JOIN (
         Department INNER JOIN Employee ON Department.ID = Employee.DepartmentID
     ) ON Company.ID = Department.CompanyID AND Department.Name LIKE '%X%'

Bu ek yan tümce, birleştirme için kullanılır, ancak tüm satır için bir filtre değildir. Dolayısıyla satır şirket bilgileriyle görünebilir, ancak o satır için tüm departman ve çalışan sütunlarında NULL olabilir, çünkü o şirket için adında X olan bir departman yoktur. Eski sözdizimi ile bu zor.

Bu nedenle, diğer satıcıların yanı sıra Microsoft, SQL Server 2005 ve sonrasındaki eski dış birleştirme sözdizimini kullanımdan kaldırmıştır, ancak eski iç birleştirme sözdizimini kullanımdan kaldırmıştır. Eski stil dış birleştirme sözdizimini kullanarak Microsoft SQL Server 2005 veya 2008 üzerinde çalışan bir veritabanıyla konuşmanın tek yolu, bu veritabanını 8.0 uyumluluk modunda (SQL Server 2000 olarak da bilinir) ayarlamaktır.

Ayrıca, eski yol, bir grup WHERE yan tümcesi ile sorgu optimize ediciye bir grup tablo atarak, "işte buradasınız, elinizden gelenin en iyisini yapın" demeye benziyordu. Yeni sözdizimiyle, sorgu iyileştiricinin hangi parçaların bir araya geldiğini anlamak için daha az işi vardır.

İşte burada.

SOL ve INNER JOIN geleceğin dalgasıdır.


28
"çoğu modern veritabanında kullanımdan kaldırılıyor." --- sadece merak eden hangileri?
13'te zerkms

10
affet beni, * = operatöre aşina değilim, ne işe yarar? Teşekkürler!
ultrajohn

9
Yıldız = ve = Yıldız sağ ve sol dış birleşimlerdir (solda veya sağdadır)? Çağlar boyunca kullanımdan kaldırıldım, SQL Server 6'dan beri kullanmadım.
Tony Hopkinson

3
Virgül kullanılmıyor. Hiçbir zaman standart OUTER JOINsözdizimi *=/ =*/ *=*kullanımdan kaldırılmıştır.
philipxy

1
Bu cevap dış birleşimlerle ilgili olmayan soruya bile cevap vermiyor. Optimizasyon ve INNER JOIN ON, yeniden optimizasyon hakkında yaptığı bir iddia yanlıştır.
philipxy

17

JOIN sözdizimi koşulları uygulandıkları tabloya yakın tutar. Bu, özellikle çok sayıda tabloya katıldığınızda faydalıdır.

Bu arada, ilk sözdizimiyle de dış birleştirme yapabilirsiniz:

WHERE a.x = b.x(+)

Veya

WHERE a.x *= b.x

Veya

WHERE a.x = b.x or a.x not in (select x from b)

2
* = Sözdizimi MS SQLServer'da ve iyi bir nedenden dolayı kullanımdan kaldırılmıştır: Sadece okumayı zorlaştırmakla kalmaz, aynı zamanda insanların düşündüklerini yapmaz ve benzer görünümlü bir LEFT JOIN ile aynı DEĞİLDİR. (+) Sözdizimi bana yabancı; hangi SQL uygulaması bunu yapar?
Euro Micelli

2
Diğer sözdizimi en azından Oracle tarafından kullanılır.
Lasse V. Karlsen

4
Asla SQL Server sözdizimini kullanmayın * =, bazen sol birleştirme değil çapraz birleştirme olarak yorumlanacağı için tutarlı sonuçlar VERMEZ. Bu, SQL Server 2000'e kadar bile geçerlidir. Bunu kullanan herhangi bir kodunuz varsa, düzeltmeniz gerekir.
HLGEM

12

İlk yol eski standarttır. İkinci yöntem SQL-92'de http://en.wikipedia.org/wiki/SQL olarak tanıtıldı . Standardın tamamı http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt adresinde görülebilir .

Veritabanı şirketlerinin SQL-92 standardını benimsemesi yıllar aldı.

Bu nedenle ikinci yöntemin tercih edilmesinin nedeni, ANSI ve ISO standartları komitesine göre SQL standardıdır.


,hala standarttır. alt seçimler de yapıldıktan sonra onsadece outer jointanıtılması gerekiyordu.
philipxy

12

Temel olarak, FROM yan tümceniz aşağıdaki gibi tabloları listelediğinde:

SELECT * FROM
  tableA, tableB, tableC

sonuç A, B, C tablolarındaki tüm satırların çapraz çarpımıdır. Sonra WHERE tableA.id = tableB.a_idçok sayıda satırı atacak kısıtlamayı uygularsınız , daha sonra ... AND tableB.id = tableC.b_idve sonra sadece gerçekten ilgilendiğiniz satırları almalısınız içinde.

DBMS'ler bu SQL'i nasıl optimize edeceklerini bilirler, böylece JOIN'leri kullanarak bunu yazmadaki performans farkı (varsa) önemsizdir. JOIN gösterimini kullanmak SQL deyimini daha okunabilir hale getirir (IMHO, birleşimleri kullanmamak deyimi karmaşaya dönüştürür). Çapraz ürünü kullanarak, WHERE yan tümcesinde birleştirme ölçütleri sağlamanız gerekir ve gösterimdeki sorun budur. WHERE yan tümcenizi aşağıdaki gibi şeylerle dolduruyorsunuz

    tableA.id = tableB.a_id 
AND tableB.id = tableC.b_id 

Bu sadece çapraz ürünü kısıtlamak için kullanılır. WHERE deyimi, sonuç kümesine yalnızca RESTRICTIONS içermelidir. Tablo birleştirme ölçütlerini sonuç kümesi kısıtlamaları ile karıştırırsanız, siz (ve diğerleri) sorgunuzu okumakta zorlanırsınız. Kesinlikle JOIN'leri kullanmalı ve FROM yan tümcesini bir FROM yan tümcesi ve WHERE yan tümcesi bir WHERE yan tümcesi tutmalısınız.


10

İkincisi tercih edilir, çünkü maddeye nereye koymayı unutarak kazayla çapraz birleşmeye neden olma olasılığı daha azdır. No yan tümcesi olmayan bir birleşim sözdizimi denetiminde başarısız olur, hiçbir yan tümcesi olmayan eski bir stil birleşimi başarısız olmaz, çapraz bir birleşim yapar.

Ek olarak daha sonra bir sol birleşiminiz olduğunda, hepsinin aynı yapıda olması bakım için yararlıdır. Ve eski sözdizimi 1992'den beri güncel değil, kullanmayı bırakmanın zamanı geçti.

Ayrıca, sadece ilk sözdizimini kullanan birçok insanın birleştirmeleri gerçekten anlamadığını ve birleşimleri anlamanın sorgulama yaparken doğru sonuçları elde etmek için kritik olduğunu gördüm.


6

Bu sayfada, açık JOIN'leri kullanan ikinci yöntemi benimsemenin bazı iyi nedenleri olduğunu düşünüyorum. Kattığı olsa da, JOIN ölçütleri WHERE yan tümcesinden çıkarıldığında, WHERE yan tümcesinde kalan seçim ölçütlerini görmek çok daha kolay hale gelir.

Gerçekten karmaşık SELECT ifadelerinde bir okuyucunun neler olup bittiğini anlaması çok daha kolay hale gelir.


5

SELECT * FROM table1, table2, ...Sözdizimi tabloları bir çift için Tamam, ama (katlanarak olur mutlaka matematiksel doğru bir ifade tabloları sayısı arttıkça okumak için sert ve zor).

JOIN sözdiziminin yazılması daha zordur (başlangıçta), ancak hangi ölçütlerin hangi tabloları etkilediğini açık hale getirir. Bu bir hata yapmayı çok daha zorlaştırır.

Ayrıca, tüm birleşimler INNER ise, her iki sürüm de eşdeğerdir. Ancak, ifadenin herhangi bir yerinde bir OUTER katılımına sahip olduğunuz anda, işler çok daha karmaşık hale gelir ve yazdıklarınızın yazdıklarınızı sorgulamayacağı neredeyse garantidir.


2

Dış birleşmeye ihtiyacınız olduğunda, ikinci sözdizimi her zaman gerekli değildir :

Oracle:

SELECT a.foo, b.foo
  FROM a, b
 WHERE a.x = b.x(+)

MSSQLServer ( 2000 sürümünde kullanımdan kaldırılmasına rağmen ) / Sybase:

SELECT a.foo, b.foo
  FROM a, b
 WHERE a.x *= b.x

Ama sorunuza geri dönüyorum. Cevabı bilmiyorum, ama muhtemelen bir birleşme tam olarak bunu yaparken bir nereye cümleye bir ifade eklemekten daha doğal (sözdizimsel olarak, en azından) ile ilgilidir : katılma .


SQL Server, sol birleştirme sözdizimini kullanımdan kaldırmıştır ve SQL Server 2000'de bile doğru sonuçlar vermeyecektir (bazen sol birleştirme yerine çapraz birleştirme yapar) ve asla SQL Server'da kullanılmamalıdır.
HLGEM

@HLGEM: Bilgi için teşekkürler. Söylediklerinizi yansıtmak için yazımı GÜNCELLEMEZ.
Pablo Santa Cruz

0

Bir çok insanın ilkiyi anlamak çok zor ve belirsiz olduğunu duyduğunu duyuyorum. Bununla ilgili bir sorun görmüyorum, ancak bu tartışmayı yaptıktan sonra, ikincisini INNER JOINS'de bile netlik için kullanıyorum.


1
JOIN sözdizimini kullanmama ve bunu ilk şekilde yapma alışkanlığı kazandım. İtiraf etmeliyim ki, beynim bu mantığa uymak için şartlı olduğu için sık sık alışkanlıklara sıkıştığımı itiraf etmeliyim, zaman zaman bana katılma sözdizimini düşünmek zor görünüyor.
TheTXI

3
Bana da bu şekilde öğretildi. Kodlama tarzımı değiştirdim, çünkü insanlar ona bakacak ve neler olduğunu kolayca tanıyamayacaktı. Mantıksal bir fark olmadığından ve ikincisini seçmek için bir neden bulamadığımdan, başkalarının yazdıklarımı anlamasına yardımcı olmak için kodu daha net hale getirmeye adapte olmam gerektiğini hissettim.
kemiller2002

0

Veritabanına, aynı olduklarını. Bununla birlikte, sizin için, bazı durumlarda bu ikinci sözdizimini kullanmanız gerekecektir. Kullanmak zorunda olan sorguları düzenlemek için (düz bir birleşim yaptığınız bir sol birleşime ihtiyacınız olduğunu bulmak için) ve tutarlılık için, sadece 2. yöntemde desen yapardım. Okuma sorgularını kolaylaştırır.


0

Bir LEFT JOIN, sağ tabloda karşılık gelen kayıtlar olmasa bile, ilk tablodaki tüm kayıtları içerdiğinden, ilk ve ikinci sorgular farklı sonuçlar verebilir.

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.