MySQL'de FULL OUTER JOIN nasıl yapılır?


654

MySQL'de Tam Dış Birleştirme yapmak istiyorum. Mümkün mü? Tam Dış Birleştirme MySQL tarafından destekleniyor mu?



4
Bu sorunun daha iyi cevapları var
Julio Marins

Buradaki cevaplara dikkat edin. SQL standardı, birleştirme birleşiminin satırlar birleşimindeki iç birleşim olduğunu, nulls tarafından genişletilen tüm eşleşmeyen sol tablo satırlarının birleşmesi, null'lar tarafından genişletilen tüm sağ tablo satırlarını birleştirir. Buradaki cevapların çoğu yanlıştır (yorumlara bakın) ve yanlış olmayanlar genel durumu ele almaz. Çok sayıda (haksız) upvote olmasına rağmen. (Cevabımı gör.)
philipxy

Birincil olmayan anahtarlara / gruplandırılmış sütunlara katılmaya çalıştığınızda ne olur? devlet "devlet" başına sattığım bir sorgu var gibi, "satıyor" ve devlet "devlet", "giderler" başına başka bir gider, her iki sorgu grubu ("devlet") tarafından kullanın. Sol ve sağ arasındaki birleşmeyi iki sorgu arasında birleştirdiğimde, satımları olan birkaç satır alıyorum, masrafları yok, masrafları olan birkaç tane var, ancak satışları yok, her şey bu noktaya kadar. satıyor ve giderleri ve tekrarlanan bir "devlet" sütun ... pek bir sorun değil ama doğru hissetmiyorum ...
Jairo Lozano

1
@JairoLozano Sorgulamak için kısıtlamalara gerek yoktur. Kısıtlamalar fazladan sorgular tutsa da, aksi takdirde istenen cevabı döndürmez. Kısıtlamalar, verilen bağımsız değişkenler için getirilerin tam olarak birleştirilmesini etkilemez. Açıkladığınız sorun, yazdığınız sorgunun yanlış sorgu olmasıdır. (Muhtemelen, her birinin muhtemelen birleştirme ve / veya toplamayı içeren bazı alt sorguların bazılarının muhtemelen farklı bir anahtarı içerdiği bazı birleştirmeler istedikleri yaygın hata, ancak yanlışlıkla birleştirme işleminin ardından tüm toplama işlemlerini veya birleştirme işlemlerini önceki toplamalar üzerinde yapmaya çalışırlar. .)
philipxy

Yanıtlar:


669

MySQL'de FULL JOINS'iniz yok, ancak onları taklit edebileceğinizden emin olabilirsiniz .

Bu SO sorudan kopyalanan bir örnek ÖRNEK için var:

iki tablo ile t1, t2:

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id

Yukarıdaki sorgu, TAM ÇIKIŞ BİRLEŞTİRME işleminin yinelenen satır üretmeyeceği özel durumlar için geçerlidir. Yukarıdaki sorgu UNION, sorgu deseni tarafından tanıtılan yinelenen satırları kaldırmak için ayarlanan operatöre bağlıdır . İkinci sorgu için bir anti-birleştirme deseni kullanarak yinelenen satırlar girmekten kaçınabiliriz ve daha sonra iki seti birleştirmek için bir UNION ALL set operatörü kullanabiliriz. Bir FULL OUTER JOIN'in yinelenen satırları döndüreceği daha genel bir durumda, bunu yapabiliriz:

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION ALL
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.id IS NULL

33
Aslında yazdığınız şey doğru değil. Çünkü bir sendika yaptığınızda kopyaları kaldıracaksınız ve bazen iki farklı tabloya katıldığınızda kopyalar olması gerekiyor.
Pavle Lekic

158
Bu doğru örnek:(SELECT ... FROM tbl1 LEFT JOIN tbl2 ...) UNION ALL (SELECT ... FROM tbl1 RIGHT JOIN tbl2 ... WHERE tbl1.col IS NULL)
Pavle Lekic

8
Fark şu ki, ben UNION ALL'u
Pavle Lekic

5
Şimdi görüyorum ki kendin söyledin üzgünüm. Belki de yanlış gittiği ve BİRLİK TÜMÜ'nün her zaman daha verimli olacağı düşünülürse cevabınızı güncelleyebilirsiniz.
ysth

10
@ ypercube: t1ve içinde yinelenen satır yoksa, bu yanıttaki t2sorgu TAM DIŞ BİRLEŞTİRME öykünen bir sonuç kümesi döndürür. Ama daha genel durumda, örneğin, SEÇ liste dönen satırları benzersiz yapmak için yeterli sütunlar / ifadeler içermiyor, sonra bu sorgu kalıptır yetersiz bir üreteceği setini çoğaltmak FULL OUTER JOIN. Daha sadık bir öykünme elde etmek için, UNION ALLayarlanmış bir operatöre ihtiyacımız olacak ve sorgulardan birinin bir anti-birleştirme modeline ihtiyacı olacaktır . Pavle Lekic'ten (yukarıdaki) yorum doğru sorgu desenini verir .
spencer7593

351

Pablo Santa Cruz'un verdiği cevap doğrudur; ancak, herhangi birinin bu sayfada tökezlemesi ve daha fazla açıklama istemesi durumunda, ayrıntılı bir döküm.

Örnek Tablolar

Aşağıdaki tablolara sahip olduğumuzu varsayalım:

-- t1
id  name
1   Tim
2   Marta

-- t2
id  name
1   Tim
3   Katarina

İç Bağlantılar

Bir iç birleşim, şöyle:

SELECT *
FROM `t1`
INNER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

Yalnızca her iki tabloda da görünen kayıtları alalım, şöyle:

1 Tim  1 Tim

İç birleşimlerin bir yönü yoktur (sol veya sağ gibi), açıkça çift yönlüdürler - her iki tarafta da bir eşleşmeye ihtiyacımız var.

Dış Bağlantılar

Dış birleşimler, diğer tabloda eşleşmeyebilecek kayıtları bulmak içindir. Bu nedenle, birleştirmenin hangi tarafında eksik kayıt olmasına izin verileceğini belirtmeniz gerekir.

LEFT JOINve RIGHT JOINkısaltmasıdır edilir LEFT OUTER JOINve RIGHT OUTER JOIN; Dış birleşimler ve iç birleşimler kavramlarını güçlendirmek için aşağıdaki tam adlarını kullanacağım.

Sol dış katılma

Sol bir dış birleşim, şöyle:

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

... sağdaki tabloda bir eşleşme olup olmadıklarına bakılmaksızın, soldaki tablodaki tüm kayıtları alacağız, şöyle:

1 Tim   1    Tim
2 Marta NULL NULL

Sağ Dış Bağlantı

Sağ dış birleşim, şöyle:

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

... soldaki tabloda bir eşleşme olup olmadıklarına bakılmaksızın, sağdaki tüm kayıtları bize aşağıdaki gibi alır:

1    Tim   1  Tim
NULL NULL  3  Katarina

Tam Dış Bağlantı

Tam bir dış birleşim, diğer tabloda bir eşleşme olsun ya da olmasın, her iki tabloda da tüm kayıtları verir; her iki tarafta da eşleşmenin olmadığı NULL'lar. Sonuç şöyle görünecektir:

1    Tim   1    Tim
2    Marta NULL NULL
NULL NULL  3    Katarina

Ancak, Pablo Santa Cruz'un işaret ettiği gibi, MySQL bunu desteklemiyor. Sol birleşim ve sağ birleşim birliği yaparak böyle taklit edebiliriz:

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`

UNION

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

UNION"Bu sorguların ikisini de çalıştır, sonra sonuçları üst üste yığar" anlamında düşünebilirsin ; satırların bazıları ilk sorgudan, bazıları ise ikinci sorgudan gelecek.

Unutulmamalıdır ki UNION, MySQL'deki a , tam kopyaları ortadan kaldıracaktır: Tim, her iki sorguda da görünecektir, ancak UNIONyalnızca bir kez onu listeliyor. Veritabanı gurusu meslektaşım bu davranışa güvenilmemesi gerektiğini düşünüyor. Bu yüzden daha açık WHEREolmak gerekirse, ikinci sorguya bir madde ekleyebiliriz :

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`

UNION

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`
WHERE `t1`.`id` IS NULL;

Eğer Öte yandan, istediği nedense çiftleri görmek için şunu kullanabilirsiniz UNION ALL.


4
MySQL için, çakışma yoksa UNION ALL yerine UNION kullanmaktan kaçınmak istersiniz (yukarıdaki Pavle'ın yorumuna bakın). Cevabınızdaki bu etkiye biraz daha bilgi ekleyebiliyorsanız, bu sorunun daha ayrıntılı olması nedeniyle tercih edilen cevap olacağını düşünüyorum.
Garen

2
"Veritabanı gurusu meslektaşım" dan tavsiye doğrudur. İlişkisel model açısından (Ted Codd ve Chris Date tarafından yapılan tüm teorik çalışmalar), son formun bir sorgusu, iki farklı seti birleştirdiği için bir TAM DIŞ BAĞLANTI öykünür, İkinci sorgu "kopyalar" ( zaten ilk sorgu tarafından döndürülen satırlar) a FULL OUTER JOIN. Bu şekilde sorgulama yapmak ve bu kopyaları kaldırmak için UNION kullanmak yanlış değildir. Ancak a'yı gerçekten çoğaltmak için FULL OUTER JOIN, anti-birleştirme için sorgulardan birine ihtiyacımız var.
spencer7593

1
@IstiaqueAhmed: amaç, TAM DIŞ BİRLEŞME işlemini taklit etmektir. İkinci sorguda bu koşula ihtiyacımız var, böylece yalnızca eşleşmesi olmayan satırları (bir anti-birleştirme kalıbı.) Döndürür. Bu koşul olmadan, sorgu bir dış birleşmedir ... eşleşen satırların yanı sıra eşleşmeyen satırları da döndürür. Ve satırlar maç olduğunu zaten ilk sorgu tarafından döndürülen. İkinci sorgu aynı satırları döndürürse (tekrar), satırları çoğaltırız ve sonucumuz FULL OUTER JOIN ile eşdeğer olmaz .
spencer7593

1
@IstiaqueAhmed: Bir UNIONişlemin bu kopyaları kaldıracağı doğrudur ; ancak TAM DIŞ BİRLEŞTİRME tarafından döndürülen yinelenen satırlar da dahil olmak üzere TÜM yinelenen satırları kaldırır. Taklit etmek a FULL JOIN biçin doğru desen (a LEFT JOIN b) UNION ALL (b ANTI JOIN a).
spencer7593

1
Harika bir açıklama ile çok özlü cevap. Bunun için teşekkürler.
Najeeb

35

Bir unionsorgu kullanılması yinelenenleri kaldırır ve bu full outer joinişlemin davranışından farklıdır ve yinelenenleri asla kaldırmaz:

[Table: t1]                            [Table: t2]
value                                  value
-------                                -------
1                                      1
2                                      2
4                                      2
4                                      5

Bu beklenen sonuçtur full outer join:

value | value
------+-------
1     | 1
2     | 2
2     | 2
Null  | 5
4     | Null
4     | Null

Bu, aşağıdakilerle birlikte leftve kullanmanın sonucudur :right Joinunion

value | value
------+-------
Null  | 5 
1     | 1
2     | 2
4     | Null

[SQL Fiddle]

Önerdiğim sorgu:

select 
    t1.value, t2.value
from t1 
left outer join t2  
  on t1.value = t2.value
union all      -- Using `union all` instead of `union`
select 
    t1.value, t2.value
from t2 
left outer join t1 
  on t1.value = t2.value
where 
    t1.value IS NULL 

Beklenen sonuçla aynı olan yukarıdaki sorgunun sonucu:

value | value
------+-------
1     | 1
2     | 2
2     | 2
4     | NULL
4     | NULL
NULL  | 5

[SQL Fiddle]


@Steve Chambers : [Yorumlardan, çok teşekkürler!]
Not: Bu hem verimlilik hem de aynı sonuçları üretmek için en iyi çözüm olabilir FULL OUTER JOIN. Bu blog gönderisi ayrıca iyi açıklıyor - Yöntem 2'den alıntı yapmak için: "Bu, yinelenen satırları doğru bir şekilde işler ve olmaması gereken hiçbir şey içermez. UNION ALLDüz UNIONtutmak yerine, kullanmak istediğim kopyaları ortadan kaldırmak gerekir. yinelenenleri sıralamaya ve kaldırmaya gerek olmadığından büyük sonuç kümelerinde önemli ölçüde daha verimli olabilir. "


full outer joinGörselleştirme ve matematikten gelen başka bir çözüm eklemeye karar verdim , yukarıda daha iyi değil daha okunabilir:

Tam dış araçları katılmak (t1 ∪ t2)tüm: t1veya t2
(t1 ∪ t2) = (t1 ∩ t2) + t1_only + t2_onlyher ikisi de bütün: t1ve t2artı tüm t1bu olmayan t2ve artı tüm t2bu değildir t1:

-- (t1 ∩ t2): all in both t1 and t2
select t1.value, t2.value
from t1 join t2 on t1.value = t2.value    
union all  -- And plus 
-- all in t1 that not exists in t2
select t1.value, null
from t1
where not exists( select 1 from t2 where t2.value = t1.value)    
union all  -- and plus
-- all in t2 that not exists in t1
select null, t2.value
from t2
where not exists( select 1 from t1 where t2.value = t1.value)

[SQL Fiddle]


Aynı görev çekme zamanlarını yapıyoruz, t1 ve t2 için alt sorgu varsa, mysql aynı görevi daha çok kez yapmak zorunda, değil mi? Bu durumda takma ad kullanarak bunu kaldırabilir miyiz
?:

Bazı geçici tablolar kullanmanızı öneririm;).
shA.t

5
Bu yöntem, hem verimlilik hem de a ile aynı sonuçları üretmek için en iyi çözüm gibi görünmektedir FULL OUTER JOIN. Bu blog yazısı da iyi açıklıyor - Yöntem 2'den alıntı yapmak için: "Bu, yinelenen satırları doğru bir şekilde işler ve olmaması gereken hiçbir şeyi içermez. İstediğim kopyaları ortadan kaldıracak düz UNION yerine UNION ALL kullanmak gerekir Yinelenenleri sıralamaya ve kaldırmaya gerek olmadığından bu, büyük sonuç kümelerinde önemli ölçüde daha etkili olabilir. "
Steve Chambers

2
@SteveChambers çok geç, ama yorumunuz için teşekkürler. Daha sonra vurgulanan daha fazla cevap için yorumunuzu ekledim, Eğer kabul etmiyorsanız lütfen geri alın;).
shA.t

Sorun değil @ shA.t - IMO bu gerçekten daha fazla oy ve / veya kabul edilen cevap olmalıdır.
Steve Chambers

6

MySql'de FULL-OUTER-JOIN sözdizimi yoktur. Hem LEFT JOIN hem de RIGHT JOIN yaparak aşağıdaki gibi taklit etmelisiniz.

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id  
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id

Ancak MySql'de RIGHT JOIN sözdizimi de yoktur. MySql'in dış birleştirme basitleştirmesine göre, sağ birleştirme, sorgudaki t1 ve t2'yi FROMve ONsorgudaki yan tümceyi değiştirerek eşdeğer sol birleştirmeye dönüştürülür . Böylece, MySql Sorgu Optimize Edici orijinal sorguyu aşağıdakine çevirir -

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id  
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id

Şimdi olduğu gibi orijinal sorgu yazma bir zarar bir WHERE yan tümcesi gibi yüklemler varsa demek ama, orada katılmadan önce- on yüklemi veya bir VE yüklemi ONbir olan fıkra, katılmak sırasında- yüklem, sonra sizi şeytana bir göz atmak isteyebilir; ayrıntılarda.

MySql sorgu optimizatörü, tahminleri boş olarak reddedilirse rutin olarak kontrol eder . Reddedilen Tanım ve Örnekler Şimdi, DOĞRU BİRLEŞTİRME yaptıysanız, ancak t1 sütunundaki NEREDE yordamı ile, reddedilen bir senaryoya girme riskiyle karşı karşıya kalabilirsiniz .

Örneğin, aşağıdaki sorgu -

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'

Sorgu Optimize Edici tarafından aşağıdakilere çevrilir-

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id
WHERE t1.col1 = 'someValue'

Böylece tabloların sırası değişti, ancak yüklem t1'e hala uygulandı, ancak t1 şimdi 'ON' yan tümcesinde. T1.col1 NOT NULL sütunu olarak tanımlanırsa , bu sorgu null reddedilir .

Boş olarak reddedilen herhangi bir dış birleşim (sol, sağ, dolu) MySql tarafından iç birleşime dönüştürülür.

Bu nedenle, beklediğiniz sonuçlar MySql'in döndürdüğünden tamamen farklı olabilir. MySql'in RIGHT JOIN ile ilgili bir hata olduğunu düşünebilirsiniz, ama bu doğru değil. Sadece MySql sorgu optimize edici nasıl çalışır. Bu yüzden sorumlu geliştirici, sorguyu oluştururken bu nüanslara dikkat etmek zorundadır.


4

SQLite'de şunları yapmalısınız:

SELECT * 
FROM leftTable lt 
LEFT JOIN rightTable rt ON lt.id = rt.lrid 
UNION
SELECT lt.*, rl.*  -- To match column set
FROM rightTable rt 
LEFT JOIN  leftTable lt ON lt.id = rt.lrid

Kullanabilir miyiz? gibi: SELECT * leftTable'TAN LEFT JOIN rightTable'YA katıl rt ON lt.id = rt.lrid UNION SELECT lt. *, rl. * - LeftTable'dan sağa sütun sütun eşleşmesi lt RIGHT JOT rightTable rt ON lt.id = rt.lrid ;
Kabir Hossain

evet ama SQLite doğru birleşimleri desteklemiyor, ancak
MYSQL'de

4

Yukarıdaki cevapların hiçbiri gerçekten doğru değildir, çünkü yinelenen değerler olduğunda anlambilimleri takip etmezler.

(Bu kopyadan ) gibi bir sorgu için :

SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.Name = t2.Name;

Doğru eşdeğer:

SELECT t1.*, t2.*
FROM (SELECT name FROM t1 UNION  -- This is intentionally UNION to remove duplicates
      SELECT name FROM t2
     ) n LEFT JOIN
     t1
     ON t1.name = n.name LEFT JOIN
     t2
     ON t2.name = n.name;

Bunun NULLdeğerlerle çalışması için gerekirse (bu da gerekli olabilir), bunun yerine NULL-safe karşılaştırma operatörünü kullanın .<=>=


3
bu genellikle iyi bir çözümdür, ancak sütun boş FULL OUTER JOINolduğunda bir kereden farklı sonuçlar verebilir name. union allAnti-birleştirme deseni ile Sorgu dış doğru davranışı katılması yeniden gerekir, ancak çözelti daha uygun bir bağlama ve tablolar üzerinde etkin olan kısıtlamalar bulunmamasına bağlıdır.
fthiella

@fthiella. . . Bu iyi bir nokta. Cevabı ayarladım.
Gordon Linoff

1
Tamam, ama boş güvenli karşılaştırma operatörü tam dış sen t1 ve t2 hem boş adlara sahip durumda davranış katılmak farklı olan başarılı katılmak yapacak
fthiella

@fthiella. . . Bunu yapmanın en iyi yolunu düşünmem gerekecek. Ancak kabul edilen cevabın ne kadar yanlış olduğu düşünüldüğünde, hemen hemen her şey doğru cevaba daha yakındır. (Her iki tarafta birden fazla anahtar varsa bu cevap yanlıştır.)
Gordon Linoff

1
Evet, kabul edilen cevap yanlış, genel bir çözüm olarak kullanmak doğru olduğunu düşünüyorum union all, ancak bu cevap, mevcut kopyaları tutacak ancak yenilerini eklemeyi önleyen birinci veya ikinci sorguda anti-birleştirme desenini kaçırıyor. Bağlama bağlı olarak diğer çözümler (bunun gibi) daha uygun olabilir.
fthiella

3

Değiştirilmiş shA.t sorgusu daha fazla netlik için:

-- t1 left join t2
SELECT t1.value, t2.value
FROM t1 LEFT JOIN t2 ON t1.value = t2.value   

    UNION ALL -- include duplicates

-- t1 right exclude join t2 (records found only in t2)
SELECT t1.value, t2.value
FROM t1 RIGHT JOIN t2 ON t1.value = t2.value
WHERE t2.value IS NULL 

3

Aşağıdakileri yapabilirsiniz:

(SELECT 
    *
FROM
    table1 t1
        LEFT JOIN
    table2 t2 ON t1.id = t2.id
WHERE
    t2.id IS NULL)
UNION ALL
 (SELECT 
    *
FROM
    table1 t1
        RIGHT JOIN
    table2 t2 ON t1.id = t2.id
WHERE
    t1.id IS NULL);

1

Cross Join Solution hakkında ne söyledin ?

SELECT t1.*, t2.*
FROM table1 t1
INNER JOIN table2 t2 
ON 1=1;

2
Hayır, bu çapraz bir birleşim. T1'deki her satırı t2'deki her bir satırla eşleştirecek select (select count(*) from t1) * (select count(*) from t2))ve sonuç kümesindeki satırlarla birlikte tüm olası kombinasyonların kümesini verecektir .
Marc L.

Bu kod soruyu cevaplayabilirken, sorunun nasıl ve neden çözüldüğüne dair ek bağlam sağlamak yanıtlayıcının uzun vadeli değerini artıracaktır.
Alexander

Hangi ekleme yardımcı olabilir? belki tr örnek?
Süper Mario

0
SELECT
    a.name,
    b.title
FROM
    author AS a
LEFT JOIN
    book AS b
    ON a.id = b.author_id
UNION
SELECT
    a.name,
    b.title
FROM
    author AS a
RIGHT JOIN
    book AS b
    ON a.id = b.author_id

0

Ayrıca mümkündür, ancak seçimde aynı alan adlarından bahsetmeniz gerekir.

SELECT t1.name, t2.name FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT t1.name, t2.name FROM t2
LEFT JOIN t1 ON t1.id = t2.id

Bu, soldaki bir birleştirmeden elde edilen sonuçları çoğaltmaktadır.
Matthew

-1

Cevabı düzeltirim ve işler tüm satırları içerir (Pavle Lekic'in cevabına dayanarak)

    (
    SELECT a.* FROM tablea a
    LEFT JOIN tableb b ON a.`key` = b.key
    WHERE b.`key` is null
    )
    UNION ALL
    (
    SELECT a.* FROM tablea a
    LEFT JOIN tableb b ON a.`key` = b.key
    where  a.`key` = b.`key`
    )
    UNION ALL
    (
    SELECT b.* FROM tablea a
    right JOIN tableb b ON b.`key` = a.key
    WHERE a.`key` is null
    );

Hayır, bu, yalnızca tableaeşleşme olmayan satırları döndürecek tablebve tam tersi bir tür "yalnızca dış" birleştirme türüdür . UNION ALLYalnızca bu iki tabloda eşit sıralı sütunlar varsa ve bu garanti edilmediğinde çalışırsınız .
Marc L.

çalışır, geçici veritabanı tablea (1,2,3,4,5,6) ve tableb (4,5,6,7,8,9) üzerinde oluşturuyorum, satırlarında 3 sütun "id", "number" ve "isim_sayısı" olarak metin ve sonuç olarak sadece çalışır (1,2,3,7,8,9)
Rubén Ruíz

1
Bu bir dış birleşim değil. Dış birleşim de eşleşen üyeleri içerir.
Marc L.

bu yeni cümle tüm sonuçları var 1,2, ..., 9
Rubén Ruíz

-2

Cevap:

SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.id = t2.id;

Aşağıdaki gibi yeniden oluşturulabilir:

 SELECT t1.*, t2.* 
 FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp
 LEFT JOIN t1 ON t1.id = tmp.id
 LEFT JOIN t2 ON t2.id = tmp.id;

Bir UNION veya UNION ALL yanıtının kullanılması, temel tabloların yinelenen girişleri olduğu kenar durumunu kapsamaz.

Açıklama:

BİRLİĞİ veya BİRLİĞİ TÜMÜNÜN kaplayamayacağı bir uç dava var. TAM DIŞ BAĞLANTILARI desteklemediğinden bunu mysql'de test edemeyiz, ancak bunu destekleyen bir veritabanında gösterebiliriz:

 WITH cte_t1 AS
 (
       SELECT 1 AS id1
       UNION ALL SELECT 2
       UNION ALL SELECT 5
       UNION ALL SELECT 6
       UNION ALL SELECT 6
 ),
cte_t2 AS
(
      SELECT 3 AS id2
      UNION ALL SELECT 4
      UNION ALL SELECT 5
      UNION ALL SELECT 6
      UNION ALL SELECT 6
)
SELECT  *  FROM  cte_t1 t1 FULL OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2;

This gives us this answer:

id1  id2
1  NULL
2  NULL
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

UNION çözümü:

SELECT  * FROM  cte_t1 t1 LEFT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2
UNION    
SELECT  * FROM cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2

Yanlış bir cevap verir:

 id1  id2
NULL  3
NULL  4
1  NULL
2  NULL
5  5
6  6

UNION ALL çözümü:

SELECT  * FROM cte_t1 t1 LEFT OUTER join cte_t2 t2 ON t1.id1 = t2.id2
UNION ALL
SELECT  * FROM  cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2

Ayrıca yanlış.

id1  id2
1  NULL
2  NULL
5  5
6  6
6  6
6  6
6  6
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

Halbuki bu sorgu:

SELECT t1.*, t2.*
FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp 
LEFT JOIN t1 ON t1.id = tmp.id 
LEFT JOIN t2 ON t2.id = tmp.id;

Aşağıdakileri verir:

id1  id2
1  NULL
2  NULL
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

Sıra farklı, ancak aksi takdirde doğru cevapla eşleşiyor.


Bu sevimli, ama UNION ALLçözümü yanlış tanıtıyor . Ayrıca, UNIONgerekli tekilleştirme nedeniyle büyük kaynak tablolarda daha yavaş kullanılacak bir çözüm sunar . Son olarak, derlenmeyecektir, çünkü alan idalt sorguda mevcut değildir tmp.
Marc L.

Hız hakkında hiç bir iddiada bulunmadım ve OP de hız hakkında hiçbir şey söylemedi. BİRLİĞİ TÜMÜ (hangisini kullanacağınıza güvenmiyorsanız) ve bu her ikisinin de doğru cevabı verdiğini varsayarsak, birinin daha hızlı olduğunu iddia etmek istersek, kıyaslama kriterleri sağlamamız gerekirdi ve bu OP soru.
Angelos

Kimliğin alt sorguda bulunmamasına ilişkin gözlemle ilgili olarak, yazım hatasını düzelttim - işaret ettiğiniz için teşekkür ederim. Yanlış beyanda bulunma talebiniz belirsizdir - belki daha fazla bilgi verebilirseniz, bunu ele alabilirim. Sevimlilik hakkındaki son gözleminizde, herhangi bir yorumum yok, sql mantığına odaklanmayı tercih ederim.
Angelos

3
Yanlış beyan: " UNION ALLÇözüm: ... Ayrıca yanlış." Sunduğunuz kod where t1.id1 is null, içinde sağlanması gereken sağ birleştirme ( ) yönteminden kesişim-hariç tutma özelliğini dışarıda bırakır UNION ALL. Yani çözümünüz, diğer çözümlerden biri yanlış uygulandığında diğerlerini çöker. "Sevimlilik" noktasında. Bu çok minnettardı, özür dilerim.
Marc L.

-3

SQL standart diyor full join onolduğunu inner join onsatırları union allboş değerlere uzatılan eşsiz sol tablo satırları union allsağ tablo satırları boş değerlere uzatılabilir. Yani inner join onsatırlar union allsatırları left join onancak inner join on union allsatırları right join ondeğil inner join on.

Yani left join onsatırlar union all right join oniçeride değil inner join on. Eğer biliyorsanız Veya inner join onsonucun "daha sonra belirli bir sağ tablo sütununda boş değer içeremez right join ondeğil satırları inner join on" in satırlarıdır right join onile onuzatılabilir durumda ando sütun is null.

Benzer şekilde right join on union alluygun left join onsatırlar.

Kimden “INNER JOIN” ve “OUTER JOIN” arasındaki fark nedir? :

(SQL Standard 2006 SQL / Foundation 7.7 Sözdizimi Kuralları 1, Genel Kurallar 1 b, 3 c & d, 5 b.)

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.