MySQL ON vs MENGGUNAKAN?

252

Dalam MySQL JOIN, apa perbedaan antara ONdan USING()? Sejauh yang saya tahu, USING()hanya sintaksis yang lebih nyaman, sedangkan ONmemungkinkan sedikit lebih banyak fleksibilitas ketika nama kolom tidak identik. Namun, perbedaan itu sangat kecil, Anda akan berpikir mereka hanya akan menghapus begitu saja USING().

Apakah ada yang lebih dari sekadar memenuhi mata? Jika ya, yang mana yang harus saya gunakan dalam situasi tertentu?

Nathanael
sumber
1
Ada juga ALAMI GABUNG: stackoverflow.com/questions/8696383/…
allyourcode
Catatan yang usingmemiliki penggunaan lain selain bergabung. Lihat stackoverflow.com/a/13750399/632951
Pacerier

Jawaban:

400

Ini sebagian besar gula sintaksis, tetapi beberapa perbedaan patut diperhatikan:

ON adalah yang lebih umum dari keduanya. Satu dapat bergabung tabel PADA kolom, satu set kolom dan bahkan suatu kondisi. Sebagai contoh:

SELECT * FROM world.City JOIN world.Country ON (City.CountryCode = Country.Code) WHERE ...

MENGGUNAKAN berguna ketika kedua tabel berbagi kolom dengan nama yang sama persis di mana mereka bergabung. Dalam hal ini, dapat dikatakan:

SELECT ... FROM film JOIN film_actor USING (film_id) WHERE ...

Perlakukan bagus tambahan adalah bahwa seseorang tidak perlu memenuhi syarat sepenuhnya kolom bergabung:

SELECT film.title, film_id -- film_id is not prefixed
FROM film
JOIN film_actor USING (film_id)
WHERE ...

Untuk mengilustrasikan, untuk melakukan hal di atas dengan ON , kita harus menulis:

SELECT film.title, film.film_id -- film.film_id is required here
FROM film
JOIN film_actor ON (film.film_id = film_actor.film_id)
WHERE ...

Perhatikan film.film_idkualifikasi dalam SELECTklausa. Tidak sah hanya mengatakan film_idkarena itu akan membuat ambiguitas:

GALAT 1052 (23000): Kolom 'film_id' dalam daftar bidang adalah ambigu

Adapun select *, kolom bergabung muncul di hasil yang ditetapkan dua kali dengan ONsementara itu hanya muncul sekali dengan USING:

mysql> create table t(i int);insert t select 1;create table t2 select*from t;
Query OK, 0 rows affected (0.11 sec)

Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0

Query OK, 1 row affected (0.19 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> select*from t join t2 on t.i=t2.i;
+------+------+
| i    | i    |
+------+------+
|    1 |    1 |
+------+------+
1 row in set (0.00 sec)

mysql> select*from t join t2 using(i);
+------+
| i    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

mysql>
Shlomi Noach
sumber
2
+1 Jawaban yang bagus tentang perbedaan sintaksis. Saya ingin tahu tentang perbedaan kinerja, jika ada. Saya membayangkan USINGpenerjemah ON.
Jason McCreary
9
Sebenarnya, keduanya menafsirkan gaya Theta tua polos. Anda dapat melihat bahwa dengan memanggil EXPLAIN DIPERPANJANGKAN pada permintaan Anda, diikuti oleh SHOW PERINGATAN.
Shlomi Noach
2
Anda juga dapat melakukan USING(kategori ,field_id )yang berguna ketika bergabung dengan kunci primer komposit, juga saya mendengar bahwa pengoptimal memang digunakan USINGuntuk meningkatkan kinerja dalam beberapa kasus
Timo Huovinen
Apakah USINGdefinisi MySQL atau standar?
PhoneixS
5
@PhoneixS ada dalam standar ANSI SQL 92
Shlomi Noach
18

Kupikir aku akan bermain di sini dengan ketika aku telah menemukan ONlebih bermanfaat daripada USING. Saat itulah OUTERbergabung diperkenalkan ke pertanyaan.

ONmanfaat dari mengijinkan kumpulan hasil dari tabel dimana kueri OUTERbergabung menjadi dibatasi sementara mempertahankan OUTERgabungan. Mencoba membatasi hasil yang ditetapkan melalui menentukan WHEREklausa akan, secara efektif, mengubah OUTERbergabung menjadi INNERbergabung.

Memang ini mungkin kasus sudut relatif. Layak diletakkan di sana .....

Sebagai contoh:

CREATE TABLE country (
   countryId int(10) unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
   country varchar(50) not null,
  UNIQUE KEY countryUIdx1 (country)
) ENGINE=InnoDB;

insert into country(country) values ("France");
insert into country(country) values ("China");
insert into country(country) values ("USA");
insert into country(country) values ("Italy");
insert into country(country) values ("UK");
insert into country(country) values ("Monaco");


CREATE TABLE city (
  cityId int(10) unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
  countryId int(10) unsigned not null,
  city varchar(50) not null,
  hasAirport boolean not null default true,
  UNIQUE KEY cityUIdx1 (countryId,city),
  CONSTRAINT city_country_fk1 FOREIGN KEY (countryId) REFERENCES country (countryId)
) ENGINE=InnoDB;


insert into city (countryId,city,hasAirport) values (1,"Paris",true);
insert into city (countryId,city,hasAirport) values (2,"Bejing",true);
insert into city (countryId,city,hasAirport) values (3,"New York",true);
insert into city (countryId,city,hasAirport) values (4,"Napoli",true);
insert into city (countryId,city,hasAirport) values (5,"Manchester",true);
insert into city (countryId,city,hasAirport) values (5,"Birmingham",false);
insert into city (countryId,city,hasAirport) values (3,"Cincinatti",false);
insert into city (countryId,city,hasAirport) values (6,"Monaco",false);

-- Gah. Left outer join is now effectively an inner join 
-- because of the where predicate
select *
from country left join city using (countryId)
where hasAirport
; 

-- Hooray! I can see Monaco again thanks to 
-- moving my predicate into the ON
select *
from country co left join city ci on (co.countryId=ci.countryId and ci.hasAirport)
; 
Tom Mac
sumber
4
Poin yang sangat bagus. Dari semua kelebihan yang usingdisediakan, tidak dapat digabungkan dengan predikat lain: select*from t join t2 using(i) and on 1tidak akan berfungsi.
Pacerier
where hasAirport ;- Apa artinya ini ? tidak ada nilai yang bisa dibandingkan.
Istiaque Ahmed
Perhatikan juga bahwa Anda dapat melakukan lebih banyak perbandingan dengan ON daripada hanya =. Sukai SELECT * FROM country LEFT JOIN city ON country.countryId=city.countryId AND city.city BETWEEN 'C' AND 'E' akan mendaftar semua negara tetapi hanya kota yang dimulai dengan C atau D (jika ada). (Plus kota yang disebut 'E')
Roemer
Saya bahkan pernah melakukan GABUNG dengan subquery di ON !!! Itu semua mungkin dan terkadang sangat efektif.
Roemer
11

Wikipedia memiliki informasi berikut tentang USING:

Akan tetapi, konstruk USING lebih dari sekadar gula sintaksis, karena himpunan hasil berbeda dari himpunan hasil versi dengan predikat eksplisit. Secara khusus, setiap kolom yang disebutkan dalam daftar USING akan muncul hanya sekali, dengan nama yang tidak memenuhi syarat, daripada satu kali untuk setiap tabel dalam gabungan. Dalam kasus di atas, akan ada satu kolom DepartmentID dan tidak ada karyawan. Departemen ID atau departemen. Departemen ID.

Tabel yang dibicarakan:

masukkan deskripsi gambar di sini

The Postgres dokumentasi juga mendefinisikan mereka cukup baik:

Klausa ON adalah jenis gabungan yang paling umum: dibutuhkan ekspresi nilai Boolean dari jenis yang sama seperti yang digunakan dalam klausa WHERE. Sepasang baris dari T1 dan T2 cocok jika ekspresi ON bernilai true.

Klausa PENGGUNAAN adalah singkatan yang memungkinkan Anda memanfaatkan situasi khusus di mana kedua sisi gabungan menggunakan nama yang sama untuk kolom gabungan. Dibutuhkan daftar yang dipisahkan koma dari nama kolom bersama dan membentuk kondisi gabungan yang mencakup perbandingan kesetaraan untuk masing-masing. Misalnya, bergabung dengan T1 dan T2 dengan MENGGUNAKAN (a, b) menghasilkan kondisi bergabung ON T1.a = T2.a DAN T1.b = T2.b.

Lebih jauh, output dari JOIN USING menekan kolom yang berlebihan: tidak perlu mencetak kedua kolom yang cocok, karena mereka harus memiliki nilai yang sama. Sementara BERGABUNG menghasilkan semua kolom dari T1 diikuti oleh semua kolom dari T2, GABUNG MENGGUNAKAN menghasilkan satu kolom output untuk masing-masing pasangan kolom yang terdaftar (dalam urutan yang tercantum), diikuti oleh kolom yang tersisa dari T1, diikuti oleh kolom yang tersisa dari T2 .

Robert Rocha
sumber
1

Bagi yang bereksperimen dengan ini di phpMyAdmin, cukup kata:

phpMyAdmin tampaknya memiliki beberapa masalah dengan USING. Sebagai catatan, ini adalah phpMyAdmin yang berjalan di Linux Mint, versi: "4.5.4.1deb2ubuntu2", server database: "10.2.14-MariaDB-10.2.14 + maria ~ xenial - mariadb.org binary distribution".

Saya telah menjalankan SELECTperintah menggunakan JOINdan USINGdi phpMyAdmin dan di Terminal (command line), dan yang di phpMyAdmin menghasilkan beberapa tanggapan membingungkan:

1) LIMITklausa di bagian akhir tampaknya diabaikan.
2) dugaan jumlah baris seperti yang dilaporkan di bagian atas halaman dengan hasil kadang-kadang salah: misalnya 4 dikembalikan, tetapi di atas dikatakan "Menampilkan baris 0 - 24 (total 2503, Kueri butuh 0,0018 detik.) "

Masuk ke mysql secara normal dan menjalankan kueri yang sama tidak menghasilkan kesalahan ini. Kesalahan ini juga tidak terjadi ketika menjalankan kueri yang sama di phpMyAdmin menggunakan JOIN ... ON .... Agaknya bug phpMyAdmin.

mike rodent
sumber