Bagaimana cara melakukan FULL OUTER JOIN di MySQL?

654

Saya ingin melakukan Full Outer Join di MySQL. Apakah ini mungkin? Apakah Full Outer Join didukung oleh MySQL?

Spencer
sumber
2
kemungkinan duplikat dari MySQL Full Outer Join Syntax Error
Joe Stefanelli
4
Pertanyaan ini memiliki jawaban yang lebih baik
Julio Marins
Waspadalah terhadap jawabannya di sini. Standar SQL mengatakan bergabung penuh pada adalah bergabung dalam pada baris union semua baris tabel kiri tak tertandingi diperpanjang oleh nulls union semua baris tabel kanan diperpanjang oleh nol. Sebagian besar jawaban di sini salah (lihat komentar) & jawaban yang tidak salah tidak menangani kasus umum. Meskipun ada banyak (tidak dibenarkan) upvotes. (Lihat jawaban saya.)
philipxy
Bagaimana dengan saat Anda mencoba bergabung dengan kunci non-utama / kolom yang dikelompokkan? seperti saya memiliki permintaan penjualan per negara bagian "negara", "penjualan" dan satu lagi pengeluaran per negara "negara bagian", "biaya", kedua kueri menggunakan grup dengan ("negara"). Ketika saya melakukan penyatuan antara kiri dan kanan bergabung antara dua pertanyaan saya mendapatkan beberapa baris dengan menjual tetapi tanpa biaya, beberapa lagi dengan pengeluaran tetapi tidak ada penjualan, semuanya sampai pada titik ini, tetapi saya juga mendapatkan beberapa dengan keduanya menjual dan mengeluarkan biaya dan kolom "negara" berulang ... tidak banyak masalah tetapi tidak terasa benar ...
Jairo Lozano
1
@JairoLozano Kendala tidak diperlukan untuk kueri. Meskipun ketika kendala menahan pertanyaan tambahan mengembalikan jawaban yang diinginkan yang sebaliknya tidak. Kendala tidak memengaruhi apa yang bergabung secara penuh pada pengembalian untuk argumen yang diberikan. Masalah yang Anda uraikan adalah kueri yang Anda tulis adalah kueri yang salah. (Agaknya kesalahan umum di mana orang menginginkan beberapa gabungan, masing-masing mungkin melibatkan kunci yang berbeda, dari beberapa subkueri, masing-masing mungkin melibatkan gabungan dan / atau agregasi, tetapi mereka keliru mencoba melakukan semua penggabungan lalu semua agregasi atau agregasi atas agregasi sebelumnya .)
philipxy

Jawaban:

669

Anda tidak memiliki GABUNGAN LENGKAP pada MySQL, tetapi Anda pasti bisa meniru mereka .

Untuk kode SAMPLE yang ditranskripsi dari pertanyaan SO ini, Anda memiliki:

dengan dua tabel 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

Kueri di atas berfungsi untuk kasus khusus di mana operasi FULL OUTER JOIN tidak akan menghasilkan baris duplikat. Kueri di atas tergantung pada UNIONoperator yang ditetapkan untuk menghapus baris duplikat yang diperkenalkan oleh pola kueri. Kita bisa menghindari memperkenalkan baris duplikat dengan menggunakan pola anti-gabung untuk kueri kedua, dan kemudian menggunakan operator set UNION ALL untuk menggabungkan dua set. Dalam kasus yang lebih umum, di mana FULL OUTER JOIN akan mengembalikan baris duplikat, kita bisa melakukan ini:

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
Pablo Santa Cruz
sumber
33
Sebenarnya hal yang Anda tulis tidak benar. Karena ketika Anda melakukan UNION Anda akan menghapus duplikat, dan kadang-kadang ketika Anda bergabung dengan dua tabel yang berbeda harus ada duplikat.
Pavle Lekic
158
Ini adalah contoh yang benar:(SELECT ... FROM tbl1 LEFT JOIN tbl2 ...) UNION ALL (SELECT ... FROM tbl1 RIGHT JOIN tbl2 ... WHERE tbl1.col IS NULL)
Pavle Lekic
8
Jadi bedanya adalah saya melakukan join inklusif kiri dan kemudian eksklusif eksklusif menggunakan UNION ALL
Pavle Lekic
5
dan saya melihat sekarang bahwa Anda mengatakannya sendiri, maaf. Mungkin Anda dapat memperbarui jawaban Anda, mengingat ada kasus yang salah dan bahwa UNION ALL selalu lebih efisien?
ysth
10
@ ypercube: Jika tidak ada baris duplikat di t1dan t2, kueri dalam jawaban ini mengembalikan resultset yang mengemulasi FULL OUTER JOIN. Tetapi dalam kasus yang lebih umum, misalnya, daftar SELECT tidak mengandung kolom / ekspresi yang cukup untuk membuat baris yang dikembalikan unik, maka pola kueri ini tidak cukup untuk mereproduksi set yang akan diproduksi oleh a FULL OUTER JOIN. Untuk mendapatkan emulasi yang lebih setia, kita membutuhkan UNION ALLoperator yang ditetapkan, dan salah satu pertanyaan membutuhkan pola anti-gabung . Komentar dari Pavle Lekic (di atas) memberikan pola kueri yang benar .
spencer7593
351

Jawaban yang diberikan Pablo Santa Cruz benar; namun, jika ada yang menemukan halaman ini dan ingin klarifikasi lebih lanjut, ini adalah rinciannya.

Contoh Tabel

Misalkan kita memiliki tabel berikut:

-- t1
id  name
1   Tim
2   Marta

-- t2
id  name
1   Tim
3   Katarina

Gabungan Dalam

Gabungan dalam, seperti ini:

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

Akan membuat kami hanya catatan yang muncul di kedua tabel, seperti ini:

1 Tim  1 Tim

Gabungan dalam tidak memiliki arah (seperti kiri atau kanan) karena keduanya dua arah secara eksplisit - kami membutuhkan kecocokan di kedua sisi.

Gabungan Luar

Gabungan luar, di sisi lain, adalah untuk menemukan catatan yang mungkin tidak memiliki kecocokan di tabel lain. Dengan demikian, Anda harus menentukan sisi gabung mana yang diizinkan memiliki catatan yang hilang.

LEFT JOINdan RIGHT JOINmerupakan singkatan untuk LEFT OUTER JOINdan RIGHT OUTER JOIN; Saya akan menggunakan nama lengkap mereka di bawah ini untuk memperkuat konsep joins luar vs joins dalam.

Kiri Luar Gabung

Gabung luar kiri, seperti ini:

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

... akan memberi kita semua catatan dari tabel kiri terlepas dari apakah mereka memiliki kecocokan di tabel kanan, seperti ini:

1 Tim   1    Tim
2 Marta NULL NULL

Gabung Luar Kanan

Gabung luar kanan, seperti ini:

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

... akan memberi kita semua catatan dari tabel kanan terlepas dari apakah mereka memiliki kecocokan di tabel kiri, seperti ini:

1    Tim   1  Tim
NULL NULL  3  Katarina

Gabung Luar Penuh

Gabungan luar penuh akan memberi kita semua catatan dari kedua tabel, terlepas dari apakah mereka memiliki kecocokan di tabel lain, dengan NULL di kedua sisi di mana tidak ada kecocokan. Hasilnya akan terlihat seperti ini:

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

Namun, seperti yang ditunjukkan Pablo Santa Cruz, MySQL tidak mendukung ini. Kita dapat menirunya dengan melakukan UNION dari join kiri dan join kanan, seperti ini:

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`;

Anda dapat menganggap UNIONsebagai "menjalankan kedua pertanyaan ini, lalu menumpuk hasilnya di atas satu sama lain"; beberapa baris akan berasal dari permintaan pertama dan beberapa dari yang kedua.

Perlu dicatat bahwa a UNIONdi MySQL akan menghilangkan duplikat yang tepat: Tim akan muncul di kedua pertanyaan di sini, tetapi hasil dari UNIONsatu - satunya daftar dia sekali. Rekan guru basis data saya merasa bahwa perilaku ini tidak boleh diandalkan. Jadi untuk lebih eksplisit tentang itu, kita bisa menambahkan WHEREklausa ke kueri kedua:

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;

Di sisi lain, jika Anda ingin melihat duplikat karena suatu alasan, Anda bisa menggunakannya UNION ALL.

Nathan Long
sumber
4
Untuk MySQL Anda benar-benar ingin menghindari menggunakan UNION alih-alih UNION ALL jika tidak ada tumpang tindih (lihat komentar Pavle di atas). Jika Anda dapat menambahkan lebih banyak info ke efek itu dalam jawaban Anda di sini, saya pikir itu akan menjadi jawaban yang disukai untuk pertanyaan ini karena lebih menyeluruh.
Garen
2
Rekomendasi dari "kolega guru basis data" sudah benar. Dalam hal model relasional (semua karya teoretis yang dilakukan oleh Ted Codd dan Chris Date), kueri dari bentuk terakhir mengemulasi FULL OUTER JOIN, karena menggabungkan dua set yang berbeda, Query kedua tidak memperkenalkan "duplikat" ( baris sudah dikembalikan oleh permintaan pertama) yang tidak akan diproduksi oleh a FULL OUTER JOIN. Tidak ada yang salah dengan melakukan kueri seperti itu, dan menggunakan UNION untuk menghapus duplikat itu. Tetapi untuk benar-benar meniru FULL OUTER JOIN, kita perlu salah satu pertanyaan untuk menjadi anti-gabung.
spencer7593
1
@IstiaqueAhmed: tujuannya adalah untuk meniru operasi FULL OUTER JOIN. Kami membutuhkan kondisi itu dalam permintaan kedua sehingga hanya mengembalikan baris yang tidak memiliki kecocokan (pola anti-gabung.). Tanpa kondisi itu, kueri adalah gabungan luar ... ia mengembalikan baris yang cocok dengan yang tidak cocok. Dan baris yang cocok sudah dikembalikan oleh kueri pertama. Jika kueri kedua mengembalikan baris yang sama (lagi), kami menduplikasi baris dan hasil kami tidak akan setara dengan FULL OUTER JOIN.
spencer7593
1
@IstiaqueAhmed: Memang benar suatu UNIONoperasi akan menghapus duplikat tersebut; tetapi itu juga menghapus SEMUA baris duplikat, termasuk baris duplikat yang akan dikembalikan oleh FULL OUTER JOIN. Untuk meniru a FULL JOIN b, pola yang benar adalah (a LEFT JOIN b) UNION ALL (b ANTI JOIN a).
spencer7593
1
Jawaban yang sangat singkat dengan penjelasan yang bagus. Terima kasih untuk ini.
Najeeb
35

Menggunakan unionkueri akan menghapus duplikat, dan ini berbeda dari perilaku full outer joinyang tidak pernah menghapus duplikat apa pun:

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

Ini adalah hasil yang diharapkan dari full outer join:

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

Ini adalah hasil dari menggunakan leftdan right Joindengan union:

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

[SQL Fiddle]

Permintaan saya yang disarankan adalah:

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 

Hasil kueri di atas sama dengan hasil yang diharapkan:

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

[SQL Fiddle]


@Steve Chambers : [Dari komentar, dengan banyak terima kasih!]
Catatan: Ini mungkin solusi terbaik, baik untuk efisiensi dan untuk menghasilkan hasil yang sama seperti a FULL OUTER JOIN. Posting blog ini juga menjelaskannya dengan baik - mengutip dari Metode 2: "Ini menangani duplikat baris dengan benar dan tidak termasuk apa pun yang tidak seharusnya. Ini perlu untuk digunakan UNION ALLalih-alih polos UNION, yang akan menghilangkan duplikat yang ingin saya pertahankan. Ini mungkin jauh lebih efisien pada set hasil yang besar, karena tidak perlu menyortir dan menghapus duplikat. "


Saya memutuskan untuk menambahkan solusi lain yang datang dari full outer joinvisualisasi dan matematika, tidak lebih baik dari yang di atas tetapi lebih mudah dibaca:

Gabung luar penuh berarti (t1 ∪ t2): semua di dalam t1atau di t2
(t1 ∪ t2) = (t1 ∩ t2) + t1_only + t2_only: semua dalam keduanya t1dan t2ditambah semua t1yang tidak ada di dalam t2dan ditambah semua t2yang tidak ada di 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]

shA.t
sumber
Kami melakukan tugas yang sama dengan kali derek, Jika ada permintaan sub untuk t1 dan t2 maka mysql harus melakukan tugas yang sama lebih banyak kali, bukan? Bisakah kita menghapus ini menggunakan alias dalam situasi ini
?:
Saya sarankan Anda untuk menggunakan beberapa tabel sementara;).
shA.t
5
Metode ini tampaknya menjadi solusi terbaik, baik untuk efisiensi maupun untuk menghasilkan hasil yang sama seperti a FULL OUTER JOIN. Posting blog ini juga menjelaskannya dengan baik - mengutip dari Metode 2: "Ini menangani duplikat baris dengan benar dan tidak termasuk apa pun yang tidak seharusnya. Ini perlu untuk menggunakan UNION ALL alih-alih UNION polos, yang akan menghilangkan duplikat yang saya ingin tetap. Ini mungkin jauh lebih efisien pada set hasil yang besar, karena tidak perlu menyortir dan menghapus duplikat. "
Steve Chambers
2
@SteveChambers sudah terlambat, tapi terima kasih atas komentar Anda. Saya menambahkan komentar Anda untuk kemudian menjawab untuk lebih banyak disoroti, Jika Anda tidak setuju silakan putar kembali;).
shA.t
Tidak masalah @ shA.t - IMO ini seharusnya benar-benar memiliki lebih banyak upvotes dan / atau menjadi jawaban yang diterima.
Steve Chambers
6

MySql tidak memiliki sintaks FULL-OUTER-JOIN. Anda harus mencontoh dengan melakukan LEFT JOIN dan RIGHT JOIN sebagai berikut-

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

Tetapi MySql juga tidak memiliki sintaks KANAN BERGABUNG. Menurut penyederhanaan gabung luar MySql, gabung kanan dikonversi ke gabung kiri setara dengan mengganti t1 dan t2 di dalam FROMdan ONklausa dalam kueri. Dengan demikian, Pengoptimal Kueri MySql menerjemahkan kueri asli menjadi yang berikut -

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

Sekarang, tidak ada salahnya menulis kueri asli apa adanya, tetapi katakan jika Anda memiliki predikat seperti klausa WHERE, yang merupakan predikat sebelum bergabung atau predikat DAN pada ONklausa, yang merupakan predikat saat bergabung , maka Anda mungkin ingin melihat iblis; yang secara rinci.

Pengoptimal permintaan MySql secara rutin memeriksa predikat jika mereka ditolak nol . Definisi dan Contoh Null-Rejected Sekarang, jika Anda telah melakukan RIGHT JOIN, tetapi dengan predikat WHERE pada kolom dari t1, maka Anda mungkin berisiko mengalami skenario yang ditolak-nol .

Misalnya, kueri berikut ini -

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'

diterjemahkan ke berikut ini oleh Pengoptimal Permintaan-

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'

Jadi urutan tabel telah berubah, tetapi predikatnya masih diterapkan ke t1, tetapi t1 sekarang berada di klausa 'ON'. Jika t1.col1 didefinisikan sebagai NOT NULL kolom, maka kueri ini akan ditolak-nol .

Gabung luar apa pun (kiri, kanan, penuh) yang ditolak-nol dikonversi menjadi gabung-dalam oleh MySql.

Dengan demikian hasil yang Anda harapkan mungkin sama sekali berbeda dari apa yang dikembalikan MySql. Anda mungkin berpikir itu bug dengan MySql's RIGHT JOIN, tapi itu tidak benar. Ini hanya cara kerja pengoptimal permintaan MySql. Jadi pengembang yang bertanggung jawab harus memperhatikan nuansa ini ketika dia membangun kueri.

TABUT
sumber
4

Dalam SQLite Anda harus melakukan ini:

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
Rami Jamleh
sumber
Bisakah kita menggunakannya? seperti sebagai: PILIH * DARI KIRI Lt. KIRI BERGABUNG DENGAN Kt. Rt. ON lt.id = rt.lrid UNION PILIH lt. *, rl. * - Untuk mencocokkan kolom yang diatur DARI KIRI. ;
Kabir Hossain
ya tapi SQLite tidak mendukung hak bergabung tetapi ya di MYSQL ya
Rami Jamleh
4

Tidak ada jawaban di atas yang benar, karena mereka tidak mengikuti semantik ketika ada nilai duplikat.

Untuk kueri seperti (dari duplikat ini ):

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

Setara yang benar adalah:

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;

Jika Anda membutuhkan ini untuk bekerja dengan NULLnilai - nilai (yang mungkin juga diperlukan), maka gunakan NULLoperator perbandingan -safe, <=>bukan =.

Gordon Linoff
sumber
3
ini sering merupakan solusi yang baik, tetapi mungkin memberikan hasil yang berbeda dari FULL OUTER JOINkapan pun namekolomnya nol. The union allquery dengan pola anti-bergabung harus mereproduksi luar bergabung perilaku benar, tetapi solusi yang lebih tepat tergantung pada konteks dan kendala yang aktif pada tabel.
fthiella
@fthiella. . . Itu poin yang bagus. Saya menyesuaikan jawabannya.
Gordon Linoff
1
oke, tetapi operator pembanding nol-aman akan membuat join berhasil, yang berbeda dari perilaku join luar penuh jika Anda memiliki nama null baik di t1 dan di t2
fthiella
@fthiella. . . Saya harus memikirkan cara terbaik untuk melakukan ini. Tetapi mengingat betapa salahnya jawaban yang diterima, hampir semuanya lebih mendekati jawaban yang benar. (Jawaban itu hanya salah jika ada banyak kunci di kedua sisi.)
Gordon Linoff
1
ya jawaban yang diterima salah, sebagai solusi umum saya pikir itu benar untuk digunakan union all, tetapi jawaban itu melewatkan pola anti-gabung baik dalam kueri pertama atau kedua yang akan membuat duplikat yang ada tetapi mencegah menambahkan yang baru. Tergantung pada konteksnya solusi lain (seperti ini) mungkin lebih tepat.
fthiella
3

Permintaan shA.t yang dimodifikasi untuk kejelasan lebih lanjut:

-- 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 
a20
sumber
3

Anda dapat melakukan hal berikut:

(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);
lolo
sumber
1

apa yang Anda katakan tentang solusi Cross join ?

SELECT t1.*, t2.*
FROM table1 t1
INNER JOIN table2 t2 
ON 1=1;
Super Mario
sumber
2
Tidak, ini adalah gabungan silang. Ini akan cocok dengan setiap baris di t1 ke setiap baris di t2, menghasilkan himpunan semua kombinasi yang mungkin, dengan select (select count(*) from t1) * (select count(*) from t2))baris di himpunan hasil.
Marc L.
Sementara kode ini dapat menjawab pertanyaan, memberikan konteks tambahan tentang bagaimana dan mengapa memecahkan masalah akan meningkatkan nilai jangka panjang jawaban.
Alexander
Tambahan apa yang mungkin bermanfaat? mungkin contohnya?
Super 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
Alex Pliutau
sumber
0

Itu juga mungkin, tetapi Anda harus menyebutkan nama bidang yang sama di pilih.

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
alamelu
sumber
Ini hanya menggandakan hasil dari bergabung kiri.
Matius Baca
-1

Saya memperbaiki respons, dan pekerjaan mencakup semua baris (berdasarkan respons Pavle Lekic)

    (
    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
    );
Rubén Ruíz
sumber
Tidak, ini adalah tipe gabungan "luar saja", yang hanya akan mengembalikan baris dari tableayang tidak memiliki kecocokan di tablebdan sebaliknya. Anda mencoba UNION ALL, yang hanya akan berfungsi jika dua tabel ini memiliki kolom pesanan yang setara, yang tidak dijamin.
Marc L.
berfungsi, saya buat di temp basis data tablea (1,2,3,4,5,6) dan tableb (4,5,6,7,8,9) barisnya memiliki 3 cols "id", "number" dan "name_number" sebagai teks, dan hanya berfungsi dalam hasil (1,2,3,7,8,9)
Rubén Ruíz
1
Itu bukan bagian luar. Gabung luar juga mencakup anggota yang cocok.
Marc L.
kalimat baru itu memiliki semua hasil 1,2, ..., 9
Rubén Ruíz
-2

Menjawab:

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

Dapat diciptakan kembali sebagai berikut:

 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;

Menggunakan jawaban UNION atau UNION ALL tidak mencakup kasus tepi di mana tabel dasar memiliki entri yang digandakan.

Penjelasan:

Ada kasus tepi yang UNION atau UNION ALL tidak bisa tutupi. Kami tidak dapat menguji ini di mysql karena tidak mendukung FULL OUTER JOINs, tetapi kami dapat mengilustrasikannya pada database yang mendukungnya:

 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

Solusi UNION:

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

Memberikan jawaban yang salah:

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

Solusi UNION ALL:

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

Juga salah.

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

Sedangkan kueri ini:

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;

Memberi yang berikut:

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

Urutannya berbeda, tetapi jika tidak cocok dengan jawaban yang benar.

Angelos
sumber
Itu lucu, tetapi salah mengartikan UNION ALLsolusinya. Juga, ini menyajikan solusi menggunakan UNIONyang akan lebih lambat pada tabel sumber besar karena de-duplikasi yang diperlukan. Akhirnya, itu tidak akan dikompilasi, karena bidang iditu tidak ada di subquery tmp.
Marc L.
Saya tidak pernah membuat klaim tentang kecepatan, dan OP juga tidak menyebutkan apa pun tentang kecepatan. Dengan asumsi UNION ALL (Anda tidak bergantung tentukan yang mana) dan ini keduanya memberikan jawaban yang benar, jika kami ingin membuat pernyataan bahwa yang lebih cepat, kami perlu memberikan tolok ukur, dan itu akan keluar dari OP pertanyaan.
Angelos
Mengenai pengamatan tentang id yang tidak ada dalam sub-kueri, saya mengoreksi kesalahan ketik - terima kasih telah menunjukkannya. Klaim keliru Anda tidak jelas - jika mungkin Anda bisa memberikan lebih banyak informasi, saya bisa mengatasinya. Pada pengamatan terakhir Anda tentang kelucuan, saya tidak punya komentar, saya lebih suka fokus pada logika sql.
Angelos
3
Misrepresents: " UNION ALLSolusinya: ... Juga salah." Kode yang Anda tampilkan menghilangkan intersection-exclusion dari right-join ( where t1.id1 is null) yang harus disediakan di UNION ALL. Dengan kata lain, solusi Anda mengalahkan semua yang lain, hanya ketika salah satu solusi lainnya tidak diimplementasikan dengan benar. Pada "kelucuan," poin diambil. Itu serampangan, permintaan maaf saya.
Marc L.
-3

Standar SQL mengatakan full join onadalahinner join on baris union alltertandingi baris tabel kiri diperpanjang oleh nulls union allkanan baris tabel diperpanjang oleh nulls. Yakni inner join onbaris union alldalam left join ontapi bukan inner join on union allbaris right join ontapi tidak inner join on.

Yaitu left join onbarisunion all right join on tidak masuk inner join on. Atau jika Anda tahu inner join onhasil Anda tidak dapat memiliki nol di kolom tabel kanan tertentu maka " right join onbaris tidak dalam inner join on" adalah baris right join ondengan onkondisi yang diperpanjang oleh andkolom ituis null .

Yaitu right join on union allsesuai jugaleft join on baris yang .

Dari Apa perbedaan antara "INNER JOIN" dan "OUTER JOIN"? :

(SQL Standard 2006 SQL / Foundation 7.7 Sintaks Aturan 1, Aturan Umum 1 b, 3 c & d, 5 b.)

philipxy
sumber