web-dev-qa-db-ja.com

MySQL ON対USING?

MySQLのJOINでは、ONUSING()の違いは何ですか?私が言うことができる限り、USING()は単にもっと便利な構文ですが、ONは列名が同一でないときにもう少し柔軟性を与えます。しかし、その違いはそれほど重要ではないため、USING()を廃止したほうがよいと思います。

これには目に見える以上のものがありますか?もしそうなら、私は与えられた状況でどちらを使うべきですか?

225
Nathanael

これは主に構文糖ですが、いくつかの違いがあります。

ONは、2つのうちのより一般的です。 1つの列、一連の列、さらには条件で表を結合できます。例えば:

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

USINGは、両方のテーブルが結合するのとまったく同じ名前の列を共有する場合に便利です。この場合、人は言うかもしれません:

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

追加のNice扱いは、参加する列を完全に限定する必要がないことです。

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

たとえば、ONを使用して上記を実行するには、次のように記述します。

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 ...

SELECT句のfilm.film_id修飾に注意してください。 film_idを言うだけではあいまいさが生じるので無効です。

エラー1052(23000):フィールドリストの列 'film_id'があいまいです

select *の場合、結合列はONで2回出現しますが、USINGで1回だけ出現します。

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>
349
Shlomi Noach

ONUSINGよりも有用であることがわかったときに、ここでチップインします。 OUTER結合がクエリに導入されるときです。

ONは、OUTER結合を維持しながら、クエリがOUTER結合するテーブルの結果セットを制限できるという利点があります。 WHERE句を指定して結果セットを制限しようとすると、事実上OUTER結合がINNER結合に変更されます。

確かにこれは相対的なコーナーケースかもしれません。でもそこに出す価値は.....

例えば:

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)
; 
15
Tom Mac

WikipediaUSINGに関する以下の情報を持っています。

ただし、結果セットは明示的な述語を含むバージョンの結果セットとは異なるため、USING構文は単なる構文上の糖以上のものです。具体的には、USINGリストに記載されている列は、結合内の各テーブルに1回ではなく、非修飾名で1回だけ表示されます。上記の場合、単一のDepartmentID列があり、employee.DepartmentIDまたはdepartment.DepartmentIDはありません。

それが話していたテーブル:

enter image description here

Postgres のドキュメントもそれらをかなりよく定義しています:

ON句は最も一般的な種類の結合条件です。WHERE句で使用されているのと同じ種類のブール値式を取ります。 ON式がtrueと評価された場合、T1とT2からの行のペアが一致します。

USING句は、結合の両側で結合列に同じ名前を使用するという特定の状況を利用できるようにするための省略形です。これは共有列名のコンマ区切りリストを取り、それぞれの等価比較を含む結合条件を形成します。たとえば、T1とT2をUSING(a、b)で結合すると、T1.a = T2.aとT1.b = T2.bの結合条件が生成されます。

さらに、JOIN USINGの出力は冗長な列を抑制します。一致する列を同じ値にする必要があるため、一致する列の両方を印刷する必要はありません。 JOIN ONはT1からのすべての列に続いてT2からのすべての列を生成しますが、JOIN USINGはリストされた列のペアごとに1つの出力列を生成します。 。

9
Robert Rocha

PhpMyAdminでこれを試している人のために、単なるWord:

phpMyAdminはUSINGに関していくつか問題があるようです。記録としては、これはLinux Mint上で実行されるphpMyAdmin、バージョン: "4.5.4.1deb2ubuntu2"、データベースサーバー: "10.2.14-MariaDB-10.2.14 + maria〜xenial - mariadb.orgバイナリ配布"です。

PhpMyAdminとターミナル(コマンドライン)の両方でSELECTJOINを使用してUSINGコマンドを実行しましたが、phpMyAdminのコマンドは不可解な応答を生成します。

1)末尾のLIMIT句は無視されるようです。
2)ページ上部に報告された結果の想定される行数が間違っていることがあります。例えば4が返されますが、上部には「0 - 24行を表示(合計2503)、Query」と表示されます。 0.0018秒かかりました。」

通常mysqlにログオンして同じクエリを実行しても、これらのエラーは発生しません。 JOIN ... ON ...を使用してphpMyAdminで同じクエリを実行してもこれらのエラーは発生しません。おそらくphpMyAdminのバグです。

0
mike rodent