Yanıtlar:
SQL JOIN
?SQL JOIN
iki veya daha fazla veritabanı tablosundan veri alma yöntemidir.
SQL JOIN
?Toplam beş JOIN
s var. Onlar :
1. JOIN or INNER JOIN
2. OUTER JOIN
2.1 LEFT OUTER JOIN or LEFT JOIN
2.2 RIGHT OUTER JOIN or RIGHT JOIN
2.3 FULL OUTER JOIN or FULL JOIN
3. NATURAL JOIN
4. CROSS JOIN
5. SELF JOIN
Bu tür bir JOIN
a'da, her iki tabloda da koşulla eşleşen tüm kayıtları alırız ve her iki tabloda da eşleşmeyen kayıtlar raporlanmaz.
Başka bir deyişle, INNER JOIN
tek gerçeğe dayanmaktadır: SADECE İKİ eşleşen girişler tablolar listelenmelidir.
Bir o Not JOIN
başka olmaksızın JOIN
anahtar kelimeler (gibi INNER
, OUTER
, LEFT
, vs) bir olduğunu INNER JOIN
. Başka bir deyişle, JOIN
sözdizimsel bir şekerdir INNER JOIN
(bakınız: JOIN ve INNER JOIN arasındaki fark ).
OUTER JOIN
verilerini geri çağırır
Ya bir tablodaki eşleşen satırlar ve diğer tablodaki tüm satırlar Ya da, tüm tablolardaki tüm satırlar (eşleşme olup olmadığı önemli değildir).
Üç çeşit Dış birleşim vardır:
2.1 SOL DIŞ ORTAK veya SOL KATIL
Bu birleştirme, sol tablodaki tüm satırları sağ tablodaki eşleşen satırlarla birlikte döndürür. Sağ tabloda eşleşen sütun yoksa, NULL
değerleri döndürür .
2.2 DOĞRU DIŞ ORTAK veya SAĞ KATIL
Bu JOIN
, sağ tablodaki tüm satırları, sol tablodaki eşleşen satırlarla birlikte döndürür. Sol tabloda eşleşen sütun yoksa, NULL
değerleri döndürür .
2.3 TAM DIŞ ORTAK veya FULL KATILIM
Bu JOIN
birleştirir LEFT OUTER JOIN
ve RIGHT OUTER JOIN
. Koşullar karşılandığında her iki tablodan satır döndürür ve NULL
eşleşme olmadığında değer döndürür .
Başka bir deyişle, OUTER JOIN
SADECE tablolardan BİRİNDE (SAĞ veya SOL) veya tabloların HER İKİ (TAM) eşleşen girişler listelenmelidir.
Note that `OUTER JOIN` is a loosened form of `INNER JOIN`.
İki koşula dayanmaktadır:
JOIN
eşitlik aynı adla tüm sütunlar üzerinde yapılır.Bu, doğası gereği daha teorik görünmektedir ve sonuç olarak (muhtemelen) çoğu DBMS bunu desteklemekten bile rahatsız değildir.
İlgili iki tablonun Kartezyen ürünüdür. Bir CROSS JOIN
durumun sonucu çoğu durumda mantıklı değildir. Dahası, buna hiç ihtiyacımız olmayacak (ya da en azından kesin olmak gerekirse).
Bu farklı bir formu değil JOIN
daha ziyade olduğu, JOIN
( INNER
, OUTER
kendisi için bir tablonun, vb).
Bir JOIN
cümle için kullanılan operatöre bağlı olarak, iki tür JOIN
s olabilir. Onlar
Ne JOIN
tür olursa olsun ( INNER
, OUTER
vb.) SADECE eşitlik operatörünü (=) kullanırsak, JOIN
bunun bir EQUI JOIN
.
Bu aynıdır EQUI JOIN
ancak>, <,> = vb. Gibi diğer tüm işleçlere izin verir.
Birçok ikisini de göz önüne
EQUI JOIN
ve TetaJOIN
benzerINNER
,OUTER
vsJOIN
ler. Ama bunun bir hata olduğuna ve fikirleri belirsizleştirdiğine inanıyorum. ÇünküINNER JOIN
,OUTER JOIN
vb. Tüm tablolar ve onların verileri ile bağlantılıdırEQUI JOIN
veTHETA JOIN
sadece eskisinde kullandığımız operatörlerle bağlantılıdır.Yine, bir
NATURAL JOIN
tür "tuhaf" olarak kabul eden birçok kişi varEQUI JOIN
. Aslında, bahsettiğim ilk koşul nedeniyle doğrudurNATURAL JOIN
. Ancak, bunu sadeceNATURAL JOIN
yalnızlıkla sınırlamak zorunda değiliz .INNER JOIN
s,OUTER JOIN
s vs de olabilirEQUI JOIN
.
Tanım:
JOINS, aynı anda birden çok tablodan birleştirilen verileri sorgulamanın yoludur.
RDBMS ile ilgili olarak 5 tip birleştirme vardır:
Equi-Join: Eşitlik durumuna göre iki tablodaki ortak kayıtları birleştirir. Teknik olarak, Bir tablonun Birincil Anahtarının değerlerini ve başka bir tablonun Yabancı Anahtar değerlerini karşılaştırmak için eşitlik operatörü (=) kullanılarak yapılan Join, dolayısıyla sonuç kümesi her iki tabloda da ortak (eşleşen) kayıtları içerir. Uygulama için INNER-JOIN'e bakınız.
Natural-Join: SELECT işleminin yinelenen sütunu atladığı Equi-Join'ın geliştirilmiş sürümüdür. Uygulama için bkz. INNER-JOIN
Equi-Join olmayan: Birleştirme koşulunun eşit işleç (=) dışında kullanıldığı durumlarda Equi-join tersidir; örneğin,! =, <=,> =,>, <Veya BETWEEN vb. Uygulama için INNER-JOIN'e bakınız.
Kendi Kendine Katılma: Bir tablonun kendisiyle birleştiği özelleştirilmiş birleştirme davranışı; Bu genellikle kendi kendine referans veren tabloları (veya Tekli ilişki varlığını) sorgulamak için gereklidir. Uygulama için INNER-JOIN'lere bakınız.
Kartezyen Ürün: Çapraz, her iki tablonun tüm kayıtlarını herhangi bir koşul olmaksızın birleştirir. Teknik olarak, WHERE-Clause içermeyen bir sorgunun sonuç kümesini döndürür.
SQL endişesine ve ilerlemesine göre, 3 tür bağlantı vardır ve tüm RDBMS birleştirmeleri bu tür birleştirmeler kullanılarak gerçekleştirilebilir.
INNER-JOIN: Eşleşen satırları iki tablodan birleştirir (veya birleştirir). Eşleştirme, tabloların ortak sütunlarına ve karşılaştırma işlemlerine göre yapılır. Eşitlik temelli koşul varsa: EQUI-JOIN gerçekleştirildi, aksi takdirde EQUI-Join değil.
OUTER-JOIN: Eşleşen satırları iki tablodan ve eşleşmeyen satırları NULL değerleriyle birleştirir (veya birleştirir). Bununla birlikte, eşleşmemiş satırların seçimini özelleştirebilir, örneğin, alt tablolara göre ilk tablodan veya ikinci tablodan eşleşmeyen satırı seçme: SOL DIŞ BİRLEŞTİR ve SAĞ DIŞ BİRLEŞTİR.
2.1. LEFT Outer JOIN (diğer adıyla LEFT-JOIN): İki tablodan eşleşen satırları döndürür ve yalnızca LEFT tablosundan (yani ilk tablo) eşleşmez.
2.2. RIGHT Outer JOIN (diğer bir deyişle RIGHT-JOIN): İki tablodan eşleşen satırları döndürür ve yalnızca RIGHT tablosundan eşleşmez.
2.3. FULL OUTER JOIN (diğer adıyla OUTER JOIN): Her iki tabloda da eşleşen ve eşleşmeyen döndürür.
ÇAPRAZ BAĞLANTI: Bu birleştirme Kartezyen ürünü yerine birleştirmez / birleştirmez.
Not: Self-JOIN, gereksinime göre INNER-JOIN, OUTER-JOIN ve CROSS-JOIN ile elde edilebilir, ancak tablo kendisiyle birleşmelidir.
1.1: INNER-JOIN: Eşit katılma uygulaması
SELECT *
FROM Table1 A
INNER JOIN Table2 B ON A.<Primary-Key> =B.<Foreign-Key>;
1.2: INNER-JOIN: Doğal-JOIN uygulaması
Select A.*, B.Col1, B.Col2 --But no B.ForeignKeyColumn in Select
FROM Table1 A
INNER JOIN Table2 B On A.Pk = B.Fk;
1.3: NON-Equi-join uygulamasıyla INNER-JOIN
Select *
FROM Table1 A INNER JOIN Table2 B On A.Pk <= B.Fk;
1.4: KENDİ KENDİNE KATILIN
Select *
FROM Table1 A1 INNER JOIN Table1 A2 On A1.Pk = A2.Fk;
2.1: DIŞ BİRLEŞTİR (tam dış birleşim)
Select *
FROM Table1 A FULL OUTER JOIN Table2 B On A.Pk = B.Fk;
2.2: SOL GİRİŞ
Select *
FROM Table1 A LEFT OUTER JOIN Table2 B On A.Pk = B.Fk;
2.3: DOĞRU KATILIM
Select *
FROM Table1 A RIGHT OUTER JOIN Table2 B On A.Pk = B.Fk;
3.1: ÇAPRAZ KATIL
Select *
FROM TableA CROSS JOIN TableB;
3.2: ÇAPRAZ KATIL - Kendine KATIL
Select *
FROM Table1 A1 CROSS JOIN Table1 A2;
//VEYA//
Select *
FROM Table1 A1,Table1 A2;
intersect
/ except
/ union
; burada daireler , numaralı etiketlerin dediği gibi left
& ile döndürülen satırlardır right
join
. AXB resmi saçmalıktır. cross join
= inner join on 1=1
& ilk diyagramın özel bir halidir.
UNION JOIN
. SQL: 2003 artık kullanılmıyor.
İlginçtir ki diğer cevapların çoğu bu iki problemden muzdariptir:
Son zamanlarda konuyla ilgili bir makale yazdım: Muhtemelen Eksik, Kapsamlı Bir Tablo, SQL'de Tablolara KATILMAK için Birçok Farklı Yolda , burada özetleyeceğim.
Bu yüzden Venn diyagramları onları yanlış bir şekilde açıklıyor, çünkü bir JOIN birleştirilen iki tablo arasında kartezyen bir ürün yaratıyor . Wikipedia bunu güzel bir şekilde gösteriyor:
Kartezyen ürünler için SQL sözdizimi CROSS JOIN
. Örneğin:
SELECT *
-- This just generates all the days in January 2017
FROM generate_series(
'2017-01-01'::TIMESTAMP,
'2017-01-01'::TIMESTAMP + INTERVAL '1 month -1 day',
INTERVAL '1 day'
) AS days(day)
-- Here, we're combining all days with all departments
CROSS JOIN departments
Bu, bir tablodaki tüm satırları diğer tablodaki tüm satırlarla birleştirir:
Kaynak:
+--------+ +------------+
| day | | department |
+--------+ +------------+
| Jan 01 | | Dept 1 |
| Jan 02 | | Dept 2 |
| ... | | Dept 3 |
| Jan 30 | +------------+
| Jan 31 |
+--------+
Sonuç:
+--------+------------+
| day | department |
+--------+------------+
| Jan 01 | Dept 1 |
| Jan 01 | Dept 2 |
| Jan 01 | Dept 3 |
| Jan 02 | Dept 1 |
| Jan 02 | Dept 2 |
| Jan 02 | Dept 3 |
| ... | ... |
| Jan 31 | Dept 1 |
| Jan 31 | Dept 2 |
| Jan 31 | Dept 3 |
+--------+------------+
Virgülle ayrılmış tablolar listesi yazarsak, aynısını alırız:
-- CROSS JOINing two tables:
SELECT * FROM table1, table2
An INNER JOIN
sadece ilişkisel cebirde CROSS JOIN
filtre yükleminin çağrıldığı bir filtredir Theta
.
Örneğin:
SELECT *
-- Same as before
FROM generate_series(
'2017-01-01'::TIMESTAMP,
'2017-01-01'::TIMESTAMP + INTERVAL '1 month -1 day',
INTERVAL '1 day'
) AS days(day)
-- Now, exclude all days/departments combinations for
-- days before the department was created
JOIN departments AS d ON day >= d.created_at
Anahtar kelimenin INNER
isteğe bağlı olduğunu unutmayın (MS Access hariç).
( sonuç örnekleri için makaleye bakın )
Özel bir tür Theta-JOIN, en çok kullandığımız equi JOIN'dir. Yüklem, bir tablonun birincil anahtarını başka bir tablonun yabancı anahtarıyla birleştirir. Sakila veritabanını gösterim amacıyla kullanırsak şunu yazabiliriz:
SELECT *
FROM actor AS a
JOIN film_actor AS fa ON a.actor_id = fa.actor_id
JOIN film AS f ON f.film_id = fa.film_id
Bu, tüm aktörleri filmleriyle birleştirir.
Veya bazı veritabanlarında:
SELECT *
FROM actor
JOIN film_actor USING (actor_id)
JOIN film USING (film_id)
USING()
Sözdizimi operasyonun tabloları JOIN ve bu iki sütun üzerinde eşitlik yüklemi yaratır her iki tarafında bulunması gereken bir sütun belirtmek için izin verir.
Diğer yanıtlar bu "JOIN tipini" ayrı olarak listeledi, ancak bu mantıklı değil. Sadece Theta-JOIN veya INNER JOIN'in özel bir örneği olan equi JOIN için bir sözdizimi şeker formudur. NATURAL JOIN , birleştirilen her iki tablo için ortak olan tüm sütunları toplar ve USING()
bu sütunları birleştirir . Kazara eşleşmelerden ( Sakila veritabanındakiLAST_UPDATE
sütunlar gibi) dolayı neredeyse hiç yararlı değildir .
İşte sözdizimi:
SELECT *
FROM actor
NATURAL JOIN film_actor
NATURAL JOIN film
Şimdi, birkaç kartezyen üründen bir tane oluşturduğundan OUTER JOIN
biraz farklıdır . Yazabiliriz:INNER JOIN
UNION
-- Convenient syntax:
SELECT *
FROM a LEFT JOIN b ON <predicate>
-- Cumbersome, equivalent syntax:
SELECT a.*, b.*
FROM a JOIN b ON <predicate>
UNION ALL
SELECT a.*, NULL, NULL, ..., NULL
FROM a
WHERE NOT EXISTS (
SELECT * FROM b WHERE <predicate>
)
Kimse ikincisini yazmak istemez, bu yüzden yazıyoruz OUTER JOIN
(genellikle veritabanları tarafından daha iyi optimize edilir).
Gibi INNER
, anahtar kelime OUTER
burada, isteğe bağlıdır.
OUTER JOIN
üç çeşittir:
LEFT [ OUTER ] JOIN
: JOIN
İfadenin sol tablosu yukarıda gösterildiği gibi birleşime eklenir.RIGHT [ OUTER ] JOIN
: JOIN
İfadenin sağ tablosu yukarıda gösterildiği gibi birleşime eklenir.FULL [ OUTER ] JOIN
: JOIN
İfadenin her iki tablosu da yukarıda gösterildiği gibi birleşmeye eklenir.Tüm bunlar anahtar kelimeyle USING()
veya ile birleştirilebilir NATURAL
( Aslında NATURAL FULL JOIN
son zamanlarda gerçek bir dünya kullanım durumum vardı )
Oracle ve SQL Server'da, OUTER JOIN
SQL standardının bunun için bir sözdizimine sahip olmadan önce desteklenen bazı tarihi, kullanımdan kaldırılmış sözdizimleri vardır :
-- Oracle
SELECT *
FROM actor a, film_actor fa, film f
WHERE a.actor_id = fa.actor_id(+)
AND fa.film_id = f.film_id(+)
-- SQL Server
SELECT *
FROM actor a, film_actor fa, film f
WHERE a.actor_id *= fa.actor_id
AND fa.film_id *= f.film_id
Bunu söyledikten sonra, bu sözdizimini kullanmayın. Bunu burada listeliyorum, böylece eski blog yayınlarından / eski kodlardan tanıyabilirsiniz.
OUTER JOIN
Birkaç kişi bunu biliyor, ancak SQL standardı bölümlenmiş OUTER JOIN
(ve Oracle bunu uygular) belirtir . Bunun gibi şeyler yazabilirsiniz:
WITH
-- Using CONNECT BY to generate all dates in January
days(day) AS (
SELECT DATE '2017-01-01' + LEVEL - 1
FROM dual
CONNECT BY LEVEL <= 31
),
-- Our departments
departments(department, created_at) AS (
SELECT 'Dept 1', DATE '2017-01-10' FROM dual UNION ALL
SELECT 'Dept 2', DATE '2017-01-11' FROM dual UNION ALL
SELECT 'Dept 3', DATE '2017-01-12' FROM dual UNION ALL
SELECT 'Dept 4', DATE '2017-04-01' FROM dual UNION ALL
SELECT 'Dept 5', DATE '2017-04-02' FROM dual
)
SELECT *
FROM days
LEFT JOIN departments
PARTITION BY (department) -- This is where the magic happens
ON day >= created_at
Sonucun bölümleri:
+--------+------------+------------+
| day | department | created_at |
+--------+------------+------------+
| Jan 01 | Dept 1 | | -- Didn't match, but still get row
| Jan 02 | Dept 1 | | -- Didn't match, but still get row
| ... | Dept 1 | | -- Didn't match, but still get row
| Jan 09 | Dept 1 | | -- Didn't match, but still get row
| Jan 10 | Dept 1 | Jan 10 | -- Matches, so get join result
| Jan 11 | Dept 1 | Jan 10 | -- Matches, so get join result
| Jan 12 | Dept 1 | Jan 10 | -- Matches, so get join result
| ... | Dept 1 | Jan 10 | -- Matches, so get join result
| Jan 31 | Dept 1 | Jan 10 | -- Matches, so get join result
Buradaki nokta, birleştirme işleminin bölümlenmiş tarafındaki tüm satırların JOIN
"JOIN'in diğer tarafında" eşleşen bir şey olursa olsun sonuçta sona erecek olmasıdır . Uzun lafın kısası: Bu, raporlardaki seyrek verileri doldurmak içindir. Çok kullanışlı!
Ciddi anlamda? Başka cevap yok mu? Elbette hayır, çünkü SQL'de yerel bir sözdizimi yok, maalesef (aşağıdaki ANTI JOIN gibi). Ancak , örneğin filmlerde oynamış tüm aktörleri bulmak için IN()
ve kullanabiliriz EXISTS()
:
SELECT *
FROM actor a
WHERE EXISTS (
SELECT * FROM film_actor fa
WHERE a.actor_id = fa.actor_id
)
WHERE a.actor_id = fa.actor_id
Yarı öncül katılmak gibi yüklem hareket eder. Buna inanmıyorsanız, yürütme planlarına bakın, örneğin Oracle. Veritabanının EXISTS()
yüklemi değil, bir SEMI JOIN işlemini yürüttüğünü göreceksiniz .
Bu yarı tam tersidir JOIN ( kullanmamaya dikkat NOT IN
rağmen , önemli bir ihtar vardır gibi)
İşte filmsiz tüm aktörler:
SELECT *
FROM actor a
WHERE NOT EXISTS (
SELECT * FROM film_actor fa
WHERE a.actor_id = fa.actor_id
)
Bazı kişiler (özellikle MySQL kullanıcıları) ayrıca ANTI JOIN yazarlar:
SELECT *
FROM actor a
LEFT JOIN film_actor fa
USING (actor_id)
WHERE film_id IS NULL
Bence tarihi sebep performans.
Aman Tanrım, bu çok havalı. Bundan bahseden tek kişi ben miyim? İşte harika bir sorgu:
SELECT a.first_name, a.last_name, f.*
FROM actor AS a
LEFT OUTER JOIN LATERAL (
SELECT f.title, SUM(amount) AS revenue
FROM film AS f
JOIN film_actor AS fa USING (film_id)
JOIN inventory AS i USING (film_id)
JOIN rental AS r USING (inventory_id)
JOIN payment AS p USING (rental_id)
WHERE fa.actor_id = a.actor_id -- JOIN predicate with the outer query!
GROUP BY f.film_id
ORDER BY revenue DESC
LIMIT 5
) AS f
ON true
Oyuncu başına TOP 5 gelir getiren filmler bulacak. Her şey için bir TOP-N sorgusuna ihtiyacınız LATERAL JOIN
olduğunda, arkadaşınız olacaktır. SQL Server kullanıcısıysanız JOIN
, adın altında bu türü biliyorsunuzAPPLY
SELECT a.first_name, a.last_name, f.*
FROM actor AS a
OUTER APPLY (
SELECT f.title, SUM(amount) AS revenue
FROM film AS f
JOIN film_actor AS fa ON f.film_id = fa.film_id
JOIN inventory AS i ON f.film_id = i.film_id
JOIN rental AS r ON i.inventory_id = r.inventory_id
JOIN payment AS p ON r.rental_id = p.rental_id
WHERE fa.actor_id = a.actor_id -- JOIN predicate with the outer query!
GROUP BY f.film_id
ORDER BY revenue DESC
LIMIT 5
) AS f
Tamam, belki de bu hile, çünkü a LATERAL JOIN
veya APPLY
ifade gerçekten birkaç satır üreten bir "ilişkili alt sorgu" dur. Ancak "ilişkili alt sorgulara" izin verirsek, aynı zamanda ...
Bu yalnızca Oracle ve Informix tarafından (bildiklerime göre) uygulanır, ancak diziler ve / veya XML kullanılarak PostgreSQL'de ve XML kullanarak SQL Server'da taklit edilebilir.
MULTISET
ilişkili bir alt sorgu üretir ve ortaya çıkan satır kümesini dış sorguya yerleştirir. Aşağıdaki sorgu tüm aktörleri seçer ve her aktör için filmlerini iç içe bir koleksiyonda toplar:
SELECT a.*, MULTISET (
SELECT f.*
FROM film AS f
JOIN film_actor AS fa USING (film_id)
WHERE a.actor_id = fa.actor_id
) AS films
FROM actor
Görüldüğü gibi, orada sadece "sıkıcı" den JOIN daha türleridir INNER
, OUTER
ve CROSS JOIN
genellikle bahsedilmektedir. Makalemde daha fazla ayrıntı var . Ve lütfen, onları göstermek için Venn diyagramlarını kullanmayı bırakın.
Ben evcil hayvan peeve itmek: USING anahtar kelime.
JOIN'in her iki tarafında da her iki tablonun yabancı anahtarları düzgün bir şekilde adlandırılmışsa (yani, sadece "id değil, aynı ad), bu kullanılabilir:
SELECT ...
FROM customers JOIN orders USING (customer_id)
Bunu çok pratik, okunabilir ve yeterince sık kullanmıyorum.