SQL JOIN - WHERE yan tümcesi ile ON yan tümcesi


689

Okuduktan sonra, bu, Explicit ile Implicit SQL Joins'in kopyası değil . Cevap ilişkili olabilir (hatta aynı olabilir) ancak soru farklıdır.


Fark nedir ve her birinde ne yapılması gerekir?

Teoriyi doğru anlarsam, sorgu optimize edici her ikisini de birbirinin yerine kullanabilmelidir.


2
Sadece gelecekteki okuyucular ve bilgileriniz için sql yürütme sırasını okumalısınız. Bu, altta yatan farkı daha iyi anlamanıza yardımcı olacaktır.
Rahul Neekhra

Yanıtlar:


870

Aynı şey değiller.

Şu sorguları düşünün:

SELECT *
FROM Orders
LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID
WHERE Orders.ID = 12345

ve

SELECT *
FROM Orders
LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID 
    AND Orders.ID = 12345

Birincisi, sipariş numarası için bir siparişi ve varsa satırlarını iade edecektir 12345. İkincisi tüm siparişleri iade edecektir, ancak sadece siparişin 12345kendisiyle ilişkili herhangi bir satır olacaktır.

An ile INNER JOIN, maddeler etkili bir şekilde eşdeğerdir. Bununla birlikte, işlevsel olarak aynı olmaları, aynı sonuçları üretmeleri açısından, iki tür cümlenin aynı anlam anlamına sahip olduğu anlamına gelmez.


83
bir iç birleşim için "açık" yan tümcesine nerede koşulunu ekleyerek daha iyi performans elde edecek misiniz?
FistOfFury

96
@FistOfFury Sql Server, mümkün olan en iyi yürütme planını üretmek için kodunuzu derleyen ve değerlendiren bir sorgu iyileştirici yordamı kullanır. Mükemmel değil, ama çoğu zaman önemli olmayacak ve her iki durumda da aynı yürütme planını alacaksınız.
Joel Coehoorn

18
Postgres'de bunların eşdeğer OLMADIĞINI ve farklı sorgu planlarıyla sonuçlandığını belirttim. ON (AÇIK) kullanırsanız, materyalize kullanımıyla sonuçlanır. WHERE kullandıysanız, bir karma kullandı. Materyalize hash'tan 10 kat daha pahalı olan daha kötü bir vakaya sahipti. Bu, tek bir kimlik yerine bir dizi kimlik kullanıyordu.
JamesHutchison

13
@JamesHutchison Böyle gözlemlenen davranışlara dayalı güvenilir performans genellemeleri yapmak zor. Bir gün doğru olan bir sonraki gün yanlış olma eğilimindedir, çünkü bu belgelenmiş davranıştan ziyade bir uygulama detayıdır. Veritabanı ekipleri her zaman iyileştirici performansını artıracak yerler arar. ON davranışı NEREDE eşleşecek şekilde gelişmezse şaşıracağım.
Sürümden

4
@FiHoran Sql Server bu şekilde çalışmaz. İstatistikler yardımcı olabileceğini gösterdiğinde, WHERE yan tümcesindeki öğelere göre agresif bir şekilde ön filtreleme yapar.
Joel Coehoorn

363
  • İç birleşimler için önemli değil
  • Dış birleşimler için konular

    a. WHEREfıkra: Katıldıktan sonra . Birleştirme gerçekleştikten sonra kayıtlar filtrelenecektir.

    b. ONfıkra - Katılmadan önce . Kayıtlar (sağdaki tablodan) katılmadan önce filtrelenecektir. Bu sonuçta null olarak sonuçlanabilir (OUTER birleşiminden beri).



Örnek : Aşağıdaki tabloları göz önünde bulundurun:

    1. documents:
     | id    | name        |
     --------|-------------|
     | 1     | Document1   |
     | 2     | Document2   |
     | 3     | Document3   |
     | 4     | Document4   |
     | 5     | Document5   |


    2. downloads:
     | id   | document_id   | username |
     |------|---------------|----------|
     | 1    | 1             | sandeep  |
     | 2    | 1             | simi     |
     | 3    | 2             | sandeep  |
     | 4    | 2             | reya     |
     | 5    | 3             | simi     |

a) İç WHEREmadde:

  SELECT documents.name, downloads.id
    FROM documents
    LEFT OUTER JOIN downloads
      ON documents.id = downloads.document_id
    WHERE username = 'sandeep'

 For above query the intermediate join table will look like this.

    | id(from documents) | name         | id (from downloads) | document_id | username |
    |--------------------|--------------|---------------------|-------------|----------|
    | 1                  | Document1    | 1                   | 1           | sandeep  |
    | 1                  | Document1    | 2                   | 1           | simi     |
    | 2                  | Document2    | 3                   | 2           | sandeep  |
    | 2                  | Document2    | 4                   | 2           | reya     |
    | 3                  | Document3    | 5                   | 3           | simi     |
    | 4                  | Document4    | NULL                | NULL        | NULL     |
    | 5                  | Document5    | NULL                | NULL        | NULL     |

  After applying the `WHERE` clause and selecting the listed attributes, the result will be: 

   | name         | id |
   |--------------|----|
   | Document1    | 1  |
   | Document2    | 3  | 

b) İç JOINmadde

  SELECT documents.name, downloads.id
  FROM documents
    LEFT OUTER JOIN downloads
      ON documents.id = downloads.document_id
        AND username = 'sandeep'

For above query the intermediate join table will look like this.

    | id(from documents) | name         | id (from downloads) | document_id | username |
    |--------------------|--------------|---------------------|-------------|----------|
    | 1                  | Document1    | 1                   | 1           | sandeep  |
    | 2                  | Document2    | 3                   | 2           | sandeep  |
    | 3                  | Document3    | NULL                | NULL        | NULL     |
    | 4                  | Document4    | NULL                | NULL        | NULL     |
    | 5                  | Document5    | NULL                | NULL        | NULL     |

Notice how the rows in `documents` that did not match both the conditions are populated with `NULL` values.

After Selecting the listed attributes, the result will be: 

   | name       | id   |
   |------------|------|
   |  Document1 | 1    |
   |  Document2 | 3    | 
   |  Document3 | NULL |
   |  Document4 | NULL | 
   |  Document5 | NULL | 

40
IMO bu en iyi cevaptır, çünkü diğer popüler cevapların 'başlığı altında' neler olduğunu açıkça gösterir.
psrpsrpsr

1
Mükemmel açıklama .... aferin! - Sadece merak etmek için ne yaptın intermediate join table? Bazı 'açıkla' komutu?
Manuel Ürdün

1
@ManuelJordan Hayır, bu sadece açıklama içindir. Bir veritabanı, bir ara tablo oluşturmaktan daha performanslı bir şey yapabilir.
Sandeep Jindal

Anlaşılan, belki de üçüncü bir aracın kullanıldığını varsaydım.
Manuel Ürdün

145

On INNER JOINs onlar değiştirilebilir ve iyileştirici irade onları yeniden düzenlemek olacaktır.

Açık OUTER JOINs, bunlar bağlı birleştirme bağlı yan, zorunlu olarak değiştirilemez.

Okunabilirliğe bağlı olarak her iki yere de koydum.



Muhtemelen Where cümlesinde, özellikle Linq-To-Entities lambda ifadelerinde çok daha açıkOrders.Join( OrderLines, x => x.ID, x => OrderID, (o,l) => new {Orders = o, Lines = l}).Where( ol => ol.Orders.ID = 12345)
Triynko

49

Bunu yapmamın yolu:

  • Yapıyorsanız, birleştirme koşullarını her zaman ONmaddeye koyun INNER JOIN. Bu nedenle, ON yan tümcesine WHERE koşulu eklemeyin, yan tümcesine koyun WHERE.

  • Bir yapıyorsanız , birleştirme işleminin sağ tarafındaki tablo için LEFT JOINherhangi bir WHERE koşulunu ekleyin . Bu bir zorunluluktur, çünkü birleştirmenin sağ tarafına başvuran bir WHERE deyimi eklemek birleşmeyi bir INNER JOIN öğesine dönüştürecektir.ON

    İstisna, belirli bir tabloda olmayan kayıtları aradığınız zamandır. Sen NEREDE hükmü bu şekilde tablo JOIN SAĞ (yani hiç GEÇERSİZ değilse) benzersiz bir tanımlayıcı başvurusunu eklersiniz: WHERE t2.idfield IS NULL. Bu nedenle, birleştirmenin sağ tarafındaki bir tabloya başvurmanız gereken tek zaman tabloda bulunmayan kayıtları bulmaktır.


8
Bu şimdiye kadar okuduğum en iyi cevap. Beynin sol edilir katılmak anlar kez Tamamen mantıklı olacak sol tablodaki tüm satırları dönmek ve daha sonra filtre gerekiyor.
Nick Larsen

nullable sütunu olan bir tabloyu dışa birleştirirseniz, o sütunu iç birleşim yapmadan yine de "nerede" yapabilirsiniz? Bu sadece belirli bir tabloda olmayan kayıtları tam olarak aramıyor. Sen var olabilir 1. yok 2. hiç değeri yok.
Yakın

Yani her ikisini de arayabilirsiniz: "1. mevcut değil 2. hiç değeri yok". Bu, o alanın idfield olmadığı durumlar için de geçerlidir.
yakınlarında

Bu durumda karşılaştığım gibi: acil durum kontağı olmadan birinci sınıf öğrencisi (henüz girilmemiş veriler) dahil katılımcıları aramak.
Yakın

30

İçsel bir birleşimde, aynı şey demek. Ancak birleştirme koşulunu WHERE'ye karşı ON yan tümcesine koyarsanız, dış birleşmede farklı sonuçlar elde edersiniz. Bu ilgili soruya ve bu cevaba bir göz atın (benim tarafımdan).

Sorgunuzu okuyan herkes için daha net hale getirdiği için, birleştirme koşulunu her zaman ON yan tümcesine koyma alışkanlığı içinde olmanın en mantıklı olduğunu düşünüyorum (bir dış birleşim olmadığı ve aslında nerede yan tümcesinde olmasını istemiyorsanız) tabloların hangi koşullara katıldığını ve ayrıca WHERE yan tümcesinin düzinelerce satır uzunluğunu önlemesine yardımcı olur.


26

Bu çok yaygın bir soru, bu yüzden bu cevap yazdığım makaleye dayanıyor .

Tablo ilişkisi

Aşağıdaki tablolara postve post_commenttablolara sahip olduğumuzu düşünürsek :

<code> post </code> ve <code> post_comment </code> tabloları

postAşağıdaki kayıtları vardır:

| id | title     |
|----|-----------|
| 1  | Java      |
| 2  | Hibernate |
| 3  | JPA       |

ve post_commentaşağıdaki üç satıra sahiptir:

| id | review    | post_id |
|----|-----------|---------|
| 1  | Good      | 1       |
| 2  | Excellent | 1       |
| 3  | Awesome   | 2       |

SQL İÇ KATILIM

SQL JOIN deyimi, farklı tablolara ait satırları ilişkilendirmenizi sağlar. Örneğin, bir CROSS JOIN , iki birleştirme tablosu arasındaki tüm olası satır kombinasyonlarını içeren bir Kartezyen Ürün oluşturacaktır.

CROSS JOIN belirli senaryolarda yararlı olsa da, çoğu zaman belirli bir koşula bağlı olarak tablolara katılmak istersiniz. İşte bu noktada INNER JOIN devreye giriyor.

SQL INNER JOIN, ON yan tümcesi ile belirtilen bir koşula göre iki tabloyu birleştirerek Kartezyen Ürünü filtrelememizi sağlar.

SQL INNER JOIN - "her zaman doğru" koşulda

"Her zaman doğru" koşulu sağlarsanız, INNER JOIN birleştirilen kayıtları filtrelemez ve sonuç kümesi iki birleştirme tablosunun Kartezyen Ürününü içerecektir.

Örneğin, aşağıdaki SQL INNER JOIN sorgusunu çalıştırırsak:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 1

Tüm kombinasyonları postve post_commentkayıtları alacağız :

| p.id    | pc.id      |
|---------|------------|
| 1       | 1          |
| 1       | 2          |
| 1       | 3          |
| 2       | 1          |
| 2       | 2          |
| 2       | 3          |
| 3       | 1          |
| 3       | 2          |
| 3       | 3          |

Dolayısıyla, ON yan tümcesi koşulu "her zaman doğru" ise, INNER JOIN bir CROSS JOIN sorgusuna eşdeğerdir:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 1
ORDER BY p.id, pc.id

SQL INNER JOIN - AÇIK "her zaman yanlış" koşulu

Öte yandan, ON yan tümcesi koşulu "her zaman yanlış" ise, birleştirilen tüm kayıtlar filtrelenir ve sonuç kümesi boş olur.

Bu nedenle, aşağıdaki SQL INNER JOIN sorgusunu çalıştırırsak:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 0
ORDER BY p.id, pc.id

Herhangi bir sonuç alamayacağız:

| p.id    | pc.id      |
|---------|------------|

Bunun nedeni yukarıdaki sorgunun aşağıdaki CROSS JOIN sorgusuna eşdeğer olmasıdır:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 0
ORDER BY p.id, pc.id

Yabancı Anahtar ve Birincil Anahtar sütunlarını kullanarak SQL INNER JOIN - ON yan tümcesi

En yaygın ON yan tümcesi koşulu, aşağıdaki sorguda gösterildiği gibi, alt tablodaki Yabancı Anahtar sütununu üst tablodaki Birincil Anahtar sütunuyla eşleştiren koşuldur:

SELECT
   p.id AS "p.id",
   pc.post_id AS "pc.post_id",
   pc.id AS "pc.id",
   p.title AS "p.title",
   pc.review  AS "pc.review"
FROM post p
INNER JOIN post_comment pc ON pc.post_id = p.id
ORDER BY p.id, pc.id

Yukarıdaki SQL INNER JOIN sorgusu yürütülürken, aşağıdaki sonuç kümesi elde ediyoruz:

| p.id    | pc.post_id | pc.id      | p.title    | pc.review |
|---------|------------|------------|------------|-----------|
| 1       | 1          | 1          | Java       | Good      |
| 1       | 1          | 2          | Java       | Excellent |
| 2       | 2          | 3          | Hibernate  | Awesome   |

Bu nedenle, yalnızca ON yan tümcesi koşulu ile eşleşen kayıtlar sorgu sonuç kümesine dahil edilir. Bizim durumumuzda, sonuç kümesi kayıtlarıyla postbirlikte tüm bunları içerir post_comment. postHiçbir ilişkilendirmiş satırlar post_commentbunlar AÇIK Madde koşulunu tatmin edemez çünkü dışlanır.

Yine, yukarıdaki SQL INNER JOIN sorgusu aşağıdaki CROSS JOIN sorgusuna eşdeğerdir:

SELECT
   p.id AS "p.id",
   pc.post_id AS "pc.post_id",
   pc.id AS "pc.id",
   p.title AS "p.title",
   pc.review  AS "pc.review"
FROM post p, post_comment pc
WHERE pc.post_id = p.id

Vurulmamış satırlar, WHERE yan tümcesini karşılayan satırlardır ve yalnızca bu kayıtlar sonuç kümesine dahil edilecektir. INNER JOIN deyiminin nasıl çalıştığını görselleştirmenin en iyi yolu budur.

| p.id | pc.post_id | pc.id | p.title | pc.review |
| ------ | ------------ | ------- | ----------- | --------- - |
| 1 | 1 | 1 | Java | İyi |
| 1 | 1 | 2 | Java | Mükemmel |
| 1 | 2 | 3 | Java | Müthiş | 
| 2 | 1 | 1 | Hazırda Beklet | İyi | 
| 2 | 1 | 2 | Hazırda Beklet | Mükemmel |
| 2 | 2 | 3 | Hazırda Beklet | Müthiş |
| 3 | 1 | 1 | JPA | İyi | 
| 3 | 1 | 2 | JPA | Mükemmel | 
| 3 | 2 | 3 | JPA | Müthiş |

Sonuç

Bir INNER JOIN deyimi, bir INNER JOIN sorgusunun ON yan tümcesinde kullandığınız koşulla eşleşen bir WHERE yan tümcesi ile CROSS JOIN olarak yeniden yazılabilir.

Bu sadece INNER JOIN için geçerli değildir, OUTER JOIN için geçerli değildir.


11

Arasındaki büyük fark var nerede fıkra vs. Maddesine sol katılmak için geldiğinde,.

İşte örnek:

mysql> desc t1; 
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   |     | NULL    |       |
| fid   | int(11)     | NO   |     | NULL    |       |
| v     | varchar(20) | NO   |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+

Fid t2 tablosunun kimliği var.

mysql> desc t2;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   |     | NULL    |       |
| v     | varchar(10) | NO   |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

"On cümle" sorgusu:

mysql> SELECT * FROM `t1` left join t2 on fid = t2.id AND t1.v = 'K' 
    -> ;
+----+-----+---+------+------+
| id | fid | v | id   | v    |
+----+-----+---+------+------+
|  1 |   1 | H | NULL | NULL |
|  2 |   1 | B | NULL | NULL |
|  3 |   2 | H | NULL | NULL |
|  4 |   7 | K | NULL | NULL |
|  5 |   5 | L | NULL | NULL |
+----+-----+---+------+------+
5 rows in set (0.00 sec)

"Where yan tümcesi" sorgusu:

mysql> SELECT * FROM `t1` left join t2 on fid = t2.id where t1.v = 'K';
+----+-----+---+------+------+
| id | fid | v | id   | v    |
+----+-----+---+------+------+
|  4 |   7 | K | NULL | NULL |
+----+-----+---+------+------+
1 row in set (0.00 sec)

İlk sorgu, t1.v = 'K' satırı için t1'den ve varsa bağımlı satırını t2'den bir kayıt döndürdüğü açıktır.

İkinci sorgu t1'den satır döndürür, ancak yalnızca t1.v = 'K' için herhangi bir ilişkili satır bulunur.


9

Optimize edici açısından, birleştirme cümlelerinizi ON veya WHERE ile tanımlamanız bir fark yaratmamalıdır.

Ancak, IMHO, bence birleştirme yaparken ON yan tümcesini kullanmak çok daha net. Bu şekilde, sorgunun WHERE cümlelerinin geri kalanıyla karışmasına karşı birleştirmenin nasıl işlendiğini belirten belirli bir bölümüne sahip olursunuz.


7

Şu tabloları ele alalım:

bir

id | SomeData

B

id | id_A | SomeOtherData

id_A masanın yabancı anahtarı olmak A

Bu sorgu yazılıyor:

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A;

Bu sonucu sağlayacaktır:

/ : part of the result
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////+-------+-------------------------+
|/////////////////////////////|
+-----------------------------+

A'da olan, ancak B'de olmayan, B için boş değerlerin olduğu anlamına gelir.


Şimdi, içindeki belirli bir parçayı ele alalım B.id_Ave önceki sonuçtan vurgulayalım:

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////+---+///|                         |
|/////////////////////|***|///|                         |
|/////////////////////+---+---+-------------------------+
|/////////////////////////////|
+-----------------------------+

Bu sorgu yazılıyor:

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A
AND B.id_A = SpecificPart;

Bu sonucu sağlayacaktır:

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|       |                         |
|/////////////////////|       |                         |
|/////////////////////+---+   |                         |
|/////////////////////|***|   |                         |
|/////////////////////+---+---+-------------------------+
|/////////////////////////////|
+-----------------------------+

Çünkü bu, iç birleşimde bulunmayan değerleri kaldırır B.id_A = SpecificPart


Şimdi sorguyu şu şekilde değiştirelim:

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A
WHERE B.id_A = SpecificPart;

Sonuç şimdi:

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|                     |       |                         |
|                     |       |                         |
|                     +---+   |                         |
|                     |***|   |                         |
|                     +---+---+-------------------------+
|                             |
+-----------------------------+

Tüm sonuç, A'da B'de olmayanB.id_A = SpecificPart parçaların çıkarılmasına karşı filtrelendiğinden B.id_A = NULL,


4

Verilere katılmaya mı yoksa verileri filtrelemeye mi çalışıyorsunuz?

Okunabilirlik için bu kullanım durumlarını sırasıyla ON ve WHERE olarak izole etmek en mantıklıdır.

  • verilere ON olarak katıl
  • WHERE içindeki verileri filtrele

WHERE yan tümcesinde JOIN koşulu ve bir filtreleme koşulunun bulunduğu bir sorguyu okumak çok zor olabilir.

Bir fark görmemelisiniz, ancak farklı SQL türleri bazen sorgu planlamasını farklı şekilde ele alır, böylece denemeye değer olabilir ¯\_(ツ)_/¯(Sorgu hızını etkileyen önbelleklemenin farkında olun)

Diğerlerinin de belirttiği gibi, bir dış birleşim kullanırsanız, filtre koşulunu ON deyimine yerleştirirseniz, tablolardan yalnızca birini etkilediği için farklı sonuçlar elde edersiniz.

Bu konuda daha ayrıntılı bir yazı yazdım: https://dataschool.com/learn/difference-between-where-and-on-in-sql


2

SQL'de, 'WHERE' ve 'ON' yan tümcesi bir tür Koşullu Statemanttır, ancak bunlar arasındaki en büyük fark, Koşulları belirtmek için Seçim / Güncelleştirme Bildirimlerinde 'Where' Yanıtı kullanılırken 'ON' Yan tümcesi Tablolar birleştirilmeden önce Kayıtların hedef ve kaynak tablolarda Eşleştirilip eşleşmediğini doğruladığı veya kontrol ettiği Joins'de kullanılır.

Örneğin: - 'NEREDE'

SELECT * FROM employee WHERE employee_id=101

Örneğin: - 'AÇIK'

İki tablo çalışan ve çalışan_detayları vardır, eşleşen sütunlar çalışan_kodur.

SELECT * FROM employee 
INNER JOIN employee_details 
ON employee.employee_id = employee_details.employee_id

Umarım sorunuzu cevapladım. Herhangi bir açıklama için geri dönün.


Ama WHEREyerine anahtar kelime kullanabilirsiniz ON, değil mi? sqlfiddle.com/#!2/ae5b0/14/0
Qwerty

1

Sanırım birleştirme sırası efekti. Sol üst birleşim durumunda, SQL önce Sol birleşim yapar ve sonra nerede filtre yapar. Aşağı durumda, önce Orders.ID = 12345 öğesini bulun ve ardından birleştirme yapın.


1

Bir iç birleşim için WHEREve ONbirbirinin yerine kullanılabilir. Aslında, ONilişkili bir alt sorguda kullanmak mümkündür . Örneğin:

update mytable
set myscore=100
where exists (
select 1 from table1
inner join table2
on (table2.key = mytable.key)
inner join table3
on (table3.key = table2.key and table3.key = table1.key)
...
)

Bu (IMHO) bir insan için tamamen kafa karıştırıcıdır ve table1herhangi bir şeye bağlantı vermeyi unutmak çok kolaydır (çünkü "sürücü" tablosunda "açık" cümlesi yoktur), ancak yasaldır.


1

daha iyi performans için tablolar JOINS kullanmak için özel bir dizinli sütun olmalıdır.

koşullandırdığınız sütun bu dizinli sütunlardan biri değilse, o zaman onu NEREDE tutmak daha iyi olduğundan şüpheleniyorum.

böylece dizinli sütunları kullanarak KATILIR, sonra JOIN sonra koşulu hiçbir dizinli sütun üzerinde çalıştırın.


1

Normalde, filtreleme iki tablo zaten birleştirildikten sonra WHERE yan tümcesinde işlenir. Tablolara katılmadan önce bir veya her ikisine filtre uygulamak isteyebilirsiniz. yani, nerede cümlesi sonuç kümesinin tamamı için geçerli iken, on cümlesi yalnızca söz konusu birleştirme için geçerlidir.


DBMS'ler "normalde" optimize ettikleri için bu böyle değildir.
philipxy

1

Bu ayrım en iyi basitleştirilmiş, SQL işlemlerin mantıksal sırası ile açıklanabilir düşünüyorum :

  • FROM (birleşimler dahil)
  • WHERE
  • GROUP BY
  • toplamaları
  • HAVING
  • WINDOW
  • SELECT
  • DISTINCT
  • UNION, INTERSECT,EXCEPT
  • ORDER BY
  • OFFSET
  • FETCH

Birleşimler select deyiminin bir yan tümcesi değil, içindeki bir işleçtir FROM. Bu nedenle, ONkarşılık gelen JOINoperatöre ait tüm yan tümceler , mantıksal işlem yan tümceye ulaştığında mantıksal olarak "zaten gerçekleşmiştir" WHERE. Bu LEFT JOIN, örneğin a örneğinde, dış birleşimin anlambiliminin, WHEREcümlenin uygulandığı tarihte zaten gerçekleştiği anlamına gelir .

Aşağıdaki örneği bu blog yazısında daha ayrıntılı olarak açıkladım . Bu sorguyu çalıştırırken:

SELECT a.actor_id, a.first_name, a.last_name, count(fa.film_id)
FROM actor a
LEFT JOIN film_actor fa ON a.actor_id = fa.actor_id
WHERE film_id < 10
GROUP BY a.actor_id, a.first_name, a.last_name
ORDER BY count(fa.film_id) ASC;

LEFT JOINBir aktör bir filmde oynamadı bile, aktör filtre edilecektir çünkü onun gerçekten, herhangi bir yararlı etkisi yoktur FILM_IDolacak NULLve WHEREhüküm böyle bir satır filtreler. Sonuç şuna benzer:

ACTOR_ID  FIRST_NAME  LAST_NAME  COUNT
--------------------------------------
194       MERYL       ALLEN      1
198       MARY        KEITEL     1
30        SANDRA      PECK       1
85        MINNIE      ZELLWEGER  1
123       JULIANNE    DENCH      1

Yani sanki içteki iki masaya katılmışız gibi. Filtre yüklemini ONmaddede taşırsak, şimdi dış birleşim için bir kriter haline gelir:

SELECT a.actor_id, a.first_name, a.last_name, count(fa.film_id)
FROM actor a
LEFT JOIN film_actor fa ON a.actor_id = fa.actor_id
  AND film_id < 10
GROUP BY a.actor_id, a.first_name, a.last_name
ORDER BY count(fa.film_id) ASC;

Yani sonuç filmsiz veya filmsiz aktörler içerecektir FILM_ID < 10

ACTOR_ID  FIRST_NAME  LAST_NAME     COUNT
-----------------------------------------
3         ED          CHASE         0
4         JENNIFER    DAVIS         0
5         JOHNNY      LOLLOBRIGIDA  0
6         BETTE       NICHOLSON     0
...
1         PENELOPE    GUINESS       1
200       THORA       TEMPLE        1
2         NICK        WAHLBERG      1
198       MARY        KEITEL        1

Kısacası

Yükleminizi her zaman mantıklı olarak en mantıklı olduğu yere koyun.


0

Sorunuzla ilgili olarak,

Sunucunuz alabildiği sürece, iç birleşimdeki hem "açık" veya "nerede" ile aynıdır:

select * from a inner join b on a.c = b.c

ve

select * from a inner join b where a.c = b.c

'Tercüme' seçeneği tüm tercümanların bilmediği için kaçınılmalıdır. Ve elbette 'on' maddesi daha açıktır.


-5

bu benim çözümüm.

SELECT song_ID,songs.fullname, singers.fullname
FROM music JOIN songs ON songs.ID = music.song_ID  
JOIN singers ON singers.ID = music.singer_ID
GROUP BY songs.fullname

Sen olmalıdırGROUP BY işe almak için.

Umarım bu yardım.


10
Song_id ve singers.fullname öğelerini de seçerken yalnızca songs.fullname üzerinde gruplama çoğu veritabanında sorun olacaktır.
btilly
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.