Bir JOIN sorgusunda filtre koşulunu yanlış yere yerleştirmek, özellikle dış birleştirmelerde sessizce hatalı sonuçlar üretebilir. Bu konu; her JOIN türünün alt sorgularda, ON yan tümcesinde ve dış WHERE yan tümcesinde bulunan filtre koşullarını nasıl işlediğini açıklar. Böylece tam olarak beklediğiniz sonuçları döndüren sorgular yazabilirsiniz.
Desteklenen JOIN Türleri
MaxCompute SQL aşağıdaki JOIN işlemlerini destekler.
| İşlem | Açıklama |
|---|---|
| INNER JOIN | Her iki tabloda da eşleşen sütun değerlerine sahip satırları döndürür. |
| LEFT JOIN | Sol tablodaki tüm satırları döndürür. Sağ tabloda eşleşme bulunmayan sol tablo satırları için sağ tablo sütunlarında NULL değerler görünür. |
| RIGHT JOIN | Sağ tablodaki tüm satırları döndürür. Sol tabloda eşleşme bulunmayan sağ tablo satırları için sol tablo sütunlarında NULL değerler görünür. |
| FULL JOIN | Her iki tablodaki tüm satırları döndürür. Bir satırın diğer tabloda eşleşmesi yoksa eşleşmeyen sütunlar NULL değerlerle doldurulur. |
| LEFT SEMI JOIN | Sağ tabloda en az bir eşleşmesi olan sol tablo satırlarını döndürür. Sağ tablo satırları sonuca dahil edilmez. |
| LEFT ANTI JOIN | Sağ tabloda eşleşmesi olmayan sol tablo satırlarını döndürür. Sağ tablo satırları sonuca dahil edilmez. Genellikle NOT EXISTS ifadesinin yerine kullanılır. |
Filtre Koşulu Yerleşiminin Sonuçları Nasıl Etkilediği
Tek bir SQL deyimi alt sorgu filtrelerini, bir ON yan tümcesini ve dış WHERE yan tümcesini birleştirebilir:
SELECT *
FROM
(SELECT * FROM A WHERE <subquery_filter_A>) A
JOIN
(SELECT * FROM B WHERE <subquery_filter_B>) B
ON <on_condition>
WHERE <where_condition>
MaxCompute bu koşulları şu sırayla değerlendirir:
<subquery_filter>— Alt sorguların içindeki WHERE koşulları<on_condition>— ON yan tümcesi<where_condition>— JOIN sonrası WHERE yan tümcesi
Bu değerlendirme sırası nedeniyle aynı mantıksal filtre, nereye yerleştirdiğinize bağlı olarak farklı sonuçlar üretebilir.
Dış JOIN'lerde (LEFT JOIN, RIGHT JOIN, FULL JOIN) NULL sağlayan tablonun sütunlarına dış WHERE yan tümcesinde filtre uygulamak; NULL değer taşıyan satırları, yani korunmuş satır tablosunda eşleşme bulunmayan satırları eler. Bu durum dış birleştirmeyi etkin bir şekilde INNER JOIN'e dönüştürür. Dış birleştirme davranışını korumak için bu filtreleri ON yan tümcesine veya bir alt sorguya yerleştirin.
Bu konuda kullanılan dış JOIN terminolojisi:
| Terim | Tanım | Örnekler |
|---|---|---|
| Korunmuş satır tablosu | Satırlarının tamamının sonuçta görünmesi gereken tablo | LEFT JOIN'de sol tablo; RIGHT JOIN'de sağ tablo; FULL JOIN'de her iki tablo |
| NULL sağlayan tablo | Eşleşmeyen satırlar için NULL değerler sağlayan tablo | LEFT JOIN'de sağ tablo; RIGHT JOIN'de sol tablo; FULL JOIN'de her iki tablo |
Test Tabloları
Bu konudaki örnekler A ve B adlı iki tablo kullanır.
A Tablosu
CREATE TABLE A AS SELECT * FROM VALUES (1, 20180101),(2, 20180101),(2, 20180102) t (key, ds);
| key | ds |
|---|---|
| 1 | 20180101 |
| 2 | 20180101 |
| 2 | 20180102 |
B Tablosu
CREATE TABLE B AS SELECT * FROM VALUES (1, 20180101),(3, 20180101),(2, 20180102) t (key, ds);
| key | ds |
|---|---|
| 1 | 20180101 |
| 3 | 20180101 |
| 2 | 20180102 |
A ve B'nin kartezyen çarpımı 9 satır üretir. Kartezyen çarpım sorgularını şu şekilde etkinleştirin:
SET odps.sql.allow.cartesian=true;
SELECT * FROM A, B;
Sonuç:
+------+----------+------+----------+
| key | ds | key2 | ds2 |
+------+----------+------+----------+
| 1 | 20180101 | 1 | 20180101 |
| 2 | 20180101 | 1 | 20180101 |
| 2 | 20180102 | 1 | 20180101 |
| 1 | 20180101 | 3 | 20180101 |
| 2 | 20180101 | 3 | 20180101 |
| 2 | 20180102 | 3 | 20180101 |
| 1 | 20180101 | 2 | 20180102 |
| 2 | 20180101 | 2 | 20180102 |
| 2 | 20180102 | 2 | 20180102 |
+------+----------+------+----------+
INNER JOIN
INNER JOIN kartezyen çarpımından birleştirme koşulunu karşılayan satırları döndürür.
Sonuç: Filtre koşulu yerleşimi sonucu etkilemez.
Durum 1 — filtre alt sorguda:
SELECT A.*, B.*
FROM
(SELECT * FROM A WHERE ds='20180101') A
JOIN
(SELECT * FROM B WHERE ds='20180101') B
ON a.key = b.key;
Durum 2 — filtre ON yan tümcesinde:
SELECT A.*, B.*
FROM A JOIN B
ON a.key = b.key AND A.ds='20180101' AND B.ds='20180101';
Durum 3 — filtre dış WHERE yan tümcesinde:
SELECT A.*, B.*
FROM A JOIN B
ON a.key = b.key
WHERE A.ds='20180101' AND B.ds='20180101';
Her üç durum da şunu döndürür:
+------+----------+------+----------+
| key | ds | key2 | ds2 |
+------+----------+------+----------+
| 1 | 20180101 | 1 | 20180101 |
+------+----------+------+----------+
INNER JOIN için sorgu motoru önce birleştirme koşulunu uygular (9 satırlık kartezyen çarpımından 3 eşleşen satır üretir) ardından dış WHERE filtresini uygular. Her iki adımın da karşılanması gerektiğinden yerleşimden bağımsız olarak nihai sonuç aynıdır.
LEFT JOIN
LEFT JOIN sol tablodaki (korunmuş satır tablosu) tüm satırları döndürür. Sağ tabloda eşleşme bulunmayan sol tablo satırları sağ tablo sütunlarında NULL değerlerle görünür.
Sonuç: Filtre koşulu yerleşimi sonucu etkiler.
Dikkat: Dış WHERE yan tümcesinde sağ tablo (NULL sağlayan) sütununa filtre uygulamak NULL taşıyan tüm satırları yani sol tabloda eşleşme bulunmayan satırları eler. Bu durum LEFT JOIN'i etkin bir şekilde INNER JOIN'e dönüştürür.
Sol tablo filtreleri için alt sorgu filtresi ile dış WHERE filtresi aynı sonucu verir.
Sağ tablo filtreleri için alt sorgu filtresi ile ON yan tümcesi filtresi aynı sonucu verir.
Durum 1 — filtre alt sorguda:
SELECT A.*, B.*
FROM
(SELECT * FROM A WHERE ds='20180101') A
LEFT JOIN
(SELECT * FROM B WHERE ds='20180101') B
ON a.key = b.key;
Sonuç (2 satır — ds='20180101' koşuluna sahip sol tablo satırları, sağ tablo eşleşmesi veya NULL):
+------+----------+------+----------+
| key | ds | key2 | ds2 |
+------+----------+------+----------+
| 1 | 20180101 | 1 | 20180101 |
| 2 | 20180101 | NULL | NULL |
+------+----------+------+----------+
Durum 2 — filtre ON yan tümcesinde:
SELECT A.*, B.*
FROM A LEFT JOIN B
ON a.key = b.key AND A.ds='20180101' AND B.ds='20180101';
ON yan tümcesi B'deki hangi satırların eşleşebileceğini filtreler ancak A'nın tüm satırları yine de korunur. 9 satırlık kartezyen çarpımda 1 eşleşen çift vardır. Eşleşmeyen 2 A satırı B sütunları için NULL döndürür.
Sonuç (3 satır — A'dan tüm satırlar, eşleşme veya NULL):
+------+----------+------+----------+
| key | ds | key2 | ds2 |
+------+----------+------+----------+
| 1 | 20180101 | 1 | 20180101 |
| 2 | 20180101 | NULL | NULL |
| 2 | 20180102 | NULL | NULL |
+------+----------+------+----------+
Durum 3 — filtre dış WHERE yan tümcesinde:
SELECT A.*, B.*
FROM A LEFT JOIN B
ON a.key = b.key
WHERE A.ds='20180101' AND B.ds='20180101';
Birleştirme eşleşmeyen A satırları için B.ds sütununda NULL içeren satırlar üretir. WHERE filtresi B.ds='20180101' NULL ile eşleşemediğinden bu satırlar elenir.
Sonuç (1 satır — INNER JOIN ile aynı):
+------+----------+------+----------+
| key | ds | key2 | ds2 |
+------+----------+------+----------+
| 1 | 20180101 | 1 | 20180101 |
+------+----------+------+----------+
RIGHT JOIN
RIGHT JOIN tablolar ters çevrilmiş olarak LEFT JOIN'in aynısıdır. Sağ tablodaki (korunmuş satır tablosu) tüm satırlar döndürülür ve eşleşme olmayan durumlarda sol tablo sütunları NULL değer taşır.
Sonuç: Filtre koşulu yerleşimi sonucu etkiler.
Sağ tablo filtreleri için alt sorgu filtresi ile dış WHERE filtresi aynı sonucu verir.
Sol tablo filtreleri için alt sorgu filtresi ile ON yan tümcesi filtresi aynı sonucu verir.
Aynı tuzak geçerlidir: dış WHERE yan tümcesinde sol tablo (NULL sağlayan) sütununa filtre uygulamak NULL taşıyan satırları eler ve RIGHT JOIN'i etkin bir şekilde INNER JOIN'e dönüştürür.
FULL JOIN
FULL JOIN her iki tablodaki tüm satırları döndürür. Her iki tablo aynı anda hem korunmuş satır tablosu hem de NULL sağlayan tablo rolündedir. Bir satırın eşleşmesi yoksa eşleşmeyen sütunlar NULL değerlerle doldurulur.
Sonuç: Filtre koşulu yerleşimi sonucu etkiler.
Dikkat: FULL JOIN için ON yan tümcesine veya dış WHERE yan tümcesine yerleştirilen filtreler her tablodan döndürülen satırları kısıtlamaz yalnızca eşleşmelerin bulunup bulunmadığını etkiler. Yalnızca alt sorgu filtreleri birleştirmeden önce girişi güvenilir bir şekilde kısıtlar.
Durum 1 — filtre alt sorguda:
SELECT A.*, B.*
FROM
(SELECT * FROM A WHERE ds='20180101') A
FULL JOIN
(SELECT * FROM B WHERE ds='20180101') B
ON a.key = b.key;
Sonuç (3 satır):
+------+----------+------+----------+
| key | ds | key2 | ds2 |
+------+----------+------+----------+
| 2 | 20180101 | NULL | NULL |
| 1 | 20180101 | 1 | 20180101 |
| NULL | NULL | 3 | 20180101 |
+------+----------+------+----------+
Durum 2 — filtre ON yan tümcesinde:
SELECT A.*, B.*
FROM A FULL JOIN B
ON a.key = b.key AND A.ds='20180101' AND B.ds='20180101';
9 satırlık kartezyen çarpımdan yalnızca 1 satır birleştirme koşulunu karşılar. Eşleşmeyen 2 A satırı B sütunları için NULL alır ve eşleşmeyen 2 B satırı A sütunları için NULL alır.
Sonuç (5 satır):
+------+----------+------+----------+
| key | ds | key2 | ds2 |
+------+----------+------+----------+
| NULL | NULL | 2 | 20180102 |
| 2 | 20180101 | NULL | NULL |
| 2 | 20180102 | NULL | NULL |
| 1 | 20180101 | 1 | 20180101 |
| NULL | NULL | 3 | 20180101 |
+------+----------+------+----------+
Durum 3 — filtre dış WHERE yan tümcesinde:
SELECT A.*, B.*
FROM A FULL JOIN B
ON a.key = b.key
WHERE A.ds='20180101' AND B.ds='20180101';
Birleştirme 4 satır üretir (3 eşleşen + NULL A sütunlarına sahip 1 eşleşmemiş B satırı). WHERE filtresi herhangi bir sütunu NULL olan satırları eler.
Sonuç (1 satır):
+------+----------+------+----------+
| key | ds | key2 | ds2 |
+------+----------+------+----------+
| 1 | 20180101 | 1 | 20180101 |
+------+----------+------+----------+
LEFT SEMI JOIN
LEFT SEMI JOIN sağ tabloda en az bir eşleşmesi olan sol tablo satırlarını döndürür. Sağ tablo satırları sonuca dahil edilmediğinden sağ tablo sütunlarına dış WHERE yan tümcesinde referans verilemez.
Sonuç: Filtre koşulu yerleşimi sonucu etkilemez.
Durum 1 — filtre alt sorguda:
SELECT A.*
FROM
(SELECT * FROM A WHERE ds='20180101') A
LEFT SEMI JOIN
(SELECT * FROM B WHERE ds='20180101') B
ON a.key = b.key;
Durum 2 — filtre ON yan tümcesinde:
SELECT A.*
FROM A LEFT SEMI JOIN B
ON a.key = b.key AND A.ds='20180101' AND B.ds='20180101';
Durum 3 — filtre dış WHERE yan tümcesinde (sağ tablo filtresi alt sorguda olmalıdır):
SELECT A.*
FROM A LEFT SEMI JOIN
(SELECT * FROM B WHERE ds='20180101') B
ON a.key = b.key
WHERE A.ds='20180101';
Her üç durum da şunu döndürür:
+------+----------+
| key | ds |
+------+----------+
| 1 | 20180101 |
+------+----------+
LEFT ANTI JOIN
LEFT ANTI JOIN sağ tabloda eşleşmesi olmayan sol tablo satırlarını döndürür. Sağ tablo satırları sonuca dahil edilmediğinden sağ tablo sütunlarına dış WHERE yan tümcesinde referans verilemez.
Sonuç: Filtre koşulu yerleşimi sonucu etkiler.
Sol tablo filtreleri için alt sorgu filtresi ile dış WHERE filtresi aynı sonucu verir.
Sağ tablo filtreleri için alt sorgu filtresi ile ON yan tümcesi filtresi aynı sonucu verir.
Durum 1 — filtre alt sorguda:
SELECT A.*
FROM
(SELECT * FROM A WHERE ds='20180101') A
LEFT ANTI JOIN
(SELECT * FROM B WHERE ds='20180101') B
ON a.key = b.key;
Sonuç (1 satır):
+------+----------+
| key | ds |
+------+----------+
| 2 | 20180101 |
+------+----------+
Durum 2 — filtre ON yan tümcesinde:
SELECT A.*
FROM A LEFT ANTI JOIN B
ON a.key = b.key AND A.ds='20180101' AND B.ds='20180101';
ON yan tümcesi eşleşme olarak kullanılabilecek B satırlarını kısıtlar. Daha dar bir birleştirme koşuluyla daha fazla A satırında eşleşme olmaz ve bu satırlar döndürülür.
Sonuç (2 satır):
+------+----------+
| key | ds |
+------+----------+
| 2 | 20180101 |
| 2 | 20180102 |
+------+----------+
Durum 3 — filtre dış WHERE yan tümcesinde (sağ tablo filtresi alt sorguda olmalıdır):
SELECT A.*
FROM A LEFT ANTI JOIN
(SELECT * FROM B WHERE ds='20180101') B
ON a.key = b.key
WHERE A.ds='20180101';
Birleştirme 2 satır döndürür ardından dış WHERE filtresi bunu 1 satıra indirir.
Sonuç (1 satır):
+------+----------+
| key | ds |
+------+----------+
| 2 | 20180101 |
+------+----------+
Filtre Yerleşimi Referansı
JOIN Türüne Göre Davranış
| JOIN Türü | Sol Tablo Filtresi | Sağ Tablo Filtresi |
|---|---|---|
| INNER JOIN | Herhangi bir konum aynı sonucu verir | Herhangi bir konum aynı sonucu verir |
| LEFT SEMI JOIN | Herhangi bir konum aynı sonucu verir | Herhangi bir konum aynı sonucu verir |
| LEFT JOIN | Alt sorgu = dış WHERE | Alt sorgu = ON yan tümcesi |
| LEFT ANTI JOIN | Alt sorgu = dış WHERE | Alt sorgu = ON yan tümcesi |
| RIGHT JOIN | Alt sorgu = ON yan tümcesi | Alt sorgu = dış WHERE |
| FULL JOIN | Yalnızca alt sorgu | Yalnızca alt sorgu |
Öneriler
Dış JOIN'ler için alt sorgu filtrelerini kullanın. Alt sorgu filtreleri birleştirme çalışmadan önce giriş verilerini kısıtlar bu nedenle birleştirme semantiği hiçbir zaman etkilenmez. Bu tüm JOIN türleri için en güvenli yaklaşımdır.
LEFT JOIN veya RIGHT JOIN'de NULL sağlayan tablo filtreleri için ON yan tümcesini kullanırsanız dış birleştirme semantiği korunur. Bu filtreleri dış WHERE yan tümcesine yerleştirmek NULL taşıyan satırları eler ve dış birleştirmeyi etkin bir şekilde INNER JOIN'e dönüştürür.
FULL JOIN için girişi güvenilir bir şekilde kısıtlayan tek seçenek alt sorgu filtreleridir. ON yan tümcesindeki veya dış WHERE yan tümcesindeki filtreler hangi satırların eşleştiğini değiştirir ancak eşleşmeyen satırları her iki tablodan da hariç tutmaz.
Sırada Ne Var
JOIN — MaxCompute SQL'de standart JOIN işlemleri için sözdizimi referansı
SEMI JOIN — LEFT SEMI JOIN ve LEFT ANTI JOIN için sözdizimi referansı
MAPJOIN HINT — büyük bir tabloyu küçük bir tabloyla birleştirirken performansı artırma
DISTRIBUTED MAPJOIN — büyük bir tabloyu orta boyutlu bir tabloyla birleştirirken performansı artırma
SKEWJOIN HINT — JOIN işlemlerinde uzun kuyruk sorunlarına neden olan sıcak anahtar değerlerini işleme