Saya ingin melakukan Full Outer Join di MySQL. Apakah ini mungkin? Apakah Full Outer Join didukung oleh MySQL?
sql
mysql
join
outer-join
full-outer-join
Spencer
sumber
sumber
Jawaban:
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:
Kueri di atas berfungsi untuk kasus khusus di mana operasi FULL OUTER JOIN tidak akan menghasilkan baris duplikat. Kueri di atas tergantung pada
UNION
operator 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:sumber
(SELECT ... FROM tbl1 LEFT JOIN tbl2 ...) UNION ALL (SELECT ... FROM tbl1 RIGHT JOIN tbl2 ... WHERE tbl1.col IS NULL)
t1
dant2
, 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 aFULL OUTER JOIN
. Untuk mendapatkan emulasi yang lebih setia, kita membutuhkanUNION ALL
operator yang ditetapkan, dan salah satu pertanyaan membutuhkan pola anti-gabung . Komentar dari Pavle Lekic (di atas) memberikan pola kueri yang benar .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:
Gabungan Dalam
Gabungan dalam, seperti ini:
Akan membuat kami hanya catatan yang muncul di kedua tabel, seperti ini:
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 JOIN
danRIGHT JOIN
merupakan singkatan untukLEFT OUTER JOIN
danRIGHT 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:
... akan memberi kita semua catatan dari tabel kiri terlepas dari apakah mereka memiliki kecocokan di tabel kanan, seperti ini:
Gabung Luar Kanan
Gabung luar kanan, seperti ini:
... akan memberi kita semua catatan dari tabel kanan terlepas dari apakah mereka memiliki kecocokan di tabel kiri, seperti ini:
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:
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:
Anda dapat menganggap
UNION
sebagai "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
UNION
di MySQL akan menghilangkan duplikat yang tepat: Tim akan muncul di kedua pertanyaan di sini, tetapi hasil dariUNION
satu - satunya daftar dia sekali. Rekan guru basis data saya merasa bahwa perilaku ini tidak boleh diandalkan. Jadi untuk lebih eksplisit tentang itu, kita bisa menambahkanWHERE
klausa ke kueri kedua:Di sisi lain, jika Anda ingin melihat duplikat karena suatu alasan, Anda bisa menggunakannya
UNION ALL
.sumber
FULL OUTER JOIN
. Tidak ada yang salah dengan melakukan kueri seperti itu, dan menggunakan UNION untuk menghapus duplikat itu. Tetapi untuk benar-benar meniruFULL OUTER JOIN
, kita perlu salah satu pertanyaan untuk menjadi anti-gabung.UNION
operasi akan menghapus duplikat tersebut; tetapi itu juga menghapus SEMUA baris duplikat, termasuk baris duplikat yang akan dikembalikan oleh FULL OUTER JOIN. Untuk menirua FULL JOIN b
, pola yang benar adalah(a LEFT JOIN b) UNION ALL (b ANTI JOIN a)
.Menggunakan
union
kueri akan menghapus duplikat, dan ini berbeda dari perilakufull outer join
yang tidak pernah menghapus duplikat apa pun:Ini adalah hasil yang diharapkan dari
full outer join
:Ini adalah hasil dari menggunakan
left
danright Join
denganunion
:[SQL Fiddle]
Permintaan saya yang disarankan adalah:
Hasil kueri di atas sama dengan hasil yang diharapkan:
[SQL Fiddle]
Saya memutuskan untuk menambahkan solusi lain yang datang dari
full outer join
visualisasi dan matematika, tidak lebih baik dari yang di atas tetapi lebih mudah dibaca:[SQL Fiddle]
sumber
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. "MySql tidak memiliki sintaks FULL-OUTER-JOIN. Anda harus mencontoh dengan melakukan LEFT JOIN dan RIGHT JOIN sebagai berikut-
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
FROM
danON
klausa dalam kueri. Dengan demikian, Pengoptimal Kueri MySql menerjemahkan kueri asli menjadi yang berikut -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
ON
klausa, 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 . 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 -
diterjemahkan ke berikut ini oleh Pengoptimal Permintaan-
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.
sumber
Dalam SQLite Anda harus melakukan ini:
sumber
Tidak ada jawaban di atas yang benar, karena mereka tidak mengikuti semantik ketika ada nilai duplikat.
Untuk kueri seperti (dari duplikat ini ):
Setara yang benar adalah:
Jika Anda membutuhkan ini untuk bekerja dengan
NULL
nilai - nilai (yang mungkin juga diperlukan), maka gunakanNULL
operator perbandingan -safe,<=>
bukan=
.sumber
FULL OUTER JOIN
kapan punname
kolomnya nol. Theunion all
query dengan pola anti-bergabung harus mereproduksi luar bergabung perilaku benar, tetapi solusi yang lebih tepat tergantung pada konteks dan kendala yang aktif pada tabel.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.Permintaan shA.t yang dimodifikasi untuk kejelasan lebih lanjut:
sumber
Anda dapat melakukan hal berikut:
sumber
apa yang Anda katakan tentang solusi Cross join ?
sumber
select (select count(*) from t1) * (select count(*) from t2))
baris di himpunan hasil.sumber
Itu juga mungkin, tetapi Anda harus menyebutkan nama bidang yang sama di pilih.
sumber
Saya memperbaiki respons, dan pekerjaan mencakup semua baris (berdasarkan respons Pavle Lekic)
sumber
tablea
yang tidak memiliki kecocokan ditableb
dan sebaliknya. Anda mencobaUNION ALL
, yang hanya akan berfungsi jika dua tabel ini memiliki kolom pesanan yang setara, yang tidak dijamin.Menjawab:
Dapat diciptakan kembali sebagai berikut:
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:
Solusi UNION:
Memberikan jawaban yang salah:
Solusi UNION ALL:
Juga salah.
Sedangkan kueri ini:
Memberi yang berikut:
Urutannya berbeda, tetapi jika tidak cocok dengan jawaban yang benar.
sumber
UNION ALL
solusinya. Juga, ini menyajikan solusi menggunakanUNION
yang akan lebih lambat pada tabel sumber besar karena de-duplikasi yang diperlukan. Akhirnya, itu tidak akan dikompilasi, karena bidangid
itu tidak ada di subquerytmp
.UNION ALL
Solusinya: ... Juga salah." Kode yang Anda tampilkan menghilangkan intersection-exclusion dari right-join (where t1.id1 is null
) yang harus disediakan diUNION 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.Standar SQL mengatakan
full join on
adalahinner join on
barisunion all
tertandingi baris tabel kiri diperpanjang oleh nullsunion all
kanan baris tabel diperpanjang oleh nulls. Yakniinner join on
barisunion all
dalamleft join on
tapi bukaninner join on
union all
barisright join on
tapi tidakinner join on
.Yaitu
left join on
barisunion all
right join on
tidak masukinner join on
. Atau jika Anda tahuinner join on
hasil Anda tidak dapat memiliki nol di kolom tabel kanan tertentu maka "right join on
baris tidak dalaminner join on
" adalah barisright join on
denganon
kondisi yang diperpanjang olehand
kolom ituis null
.Yaitu
right join on
union all
sesuai jugaleft join on
baris yang .Dari Apa perbedaan antara "INNER JOIN" dan "OUTER JOIN"? :
sumber