web-dev-qa-db-fra.com

MySQL ON vs USING?

Dans un MySQL JOIN, quelle est la différence entre ON et USING()? Autant que je sache, USING() est simplement une syntaxe plus pratique, alors que ON permet un peu plus de flexibilité lorsque les noms de colonnes ne sont pas identiques. Cependant, cette différence est si mineure, on pourrait penser qu'ils se contenteraient de supprimer USING().

Y a-t-il plus que ce que l’œil perçoit? Si oui, lequel devrais-je utiliser dans une situation donnée?

232
Nathanael

Il s'agit principalement de sucre syntaxique, mais quelques différences sont à noter:

ON est le plus général des deux. On peut joindre des tables sur une colonne, un ensemble de colonnes et même une condition. Par exemple:

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

USING est utile lorsque les deux tables partagent une colonne du même nom exact sur lequel elles sont jointes. Dans ce cas, on peut dire:

_SELECT ... FROM film JOIN film_actor USING (film_id) WHERE ...
_

Un traitement supplémentaire de Nice est qu'il n'est pas nécessaire de qualifier complètement les colonnes de jonction:

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

Pour illustrer cela, pour faire ce qui précède avec ON, il faudrait écrire:

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

Notez la qualification _film.film_id_ dans la clause SELECT. Il serait invalide de simplement dire _film_id_ car cela créerait une ambiguïté:

ERREUR 1052 (23000): La colonne 'film_id' dans la liste de champs est ambiguë

En ce qui concerne select *, la colonne de jointure apparaît deux fois dans le jeu de résultats avec ON alors qu'elle n'apparaît qu'une seule fois avec 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>
_
363
Shlomi Noach

Je pensais pouvoir participer ici quand j’aurais trouvé ON plus utile que USING. C'est lorsque OUTER que des jointures sont introduites dans des requêtes.

ON profite de la possibilité de restreindre le jeu de résultats de la table qu'une requête est OUTER à joindre tout en conservant la jointure OUTER. Tenter de restreindre le jeu de résultats en spécifiant une clause WHERE modifiera effectivement la jonction OUTER en une jonction INNER.

Accordé cela peut être un cas de coin relatif. Ça vaut le coup d'y aller si .....

Par exemple:

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

Wikipedia possède les informations suivantes sur USING:

La construction USING est toutefois plus qu'un simple sucre syntaxique, car l'ensemble de résultats diffère de l'ensemble de résultats de la version avec le prédicat explicite. Plus précisément, toutes les colonnes mentionnées dans la liste USING apparaîtront une seule fois, avec un nom non qualifié, plutôt qu'une seule fois pour chaque table de la jointure. Dans le cas ci-dessus, il n'y aura qu'une seule colonne DepartmentID et aucun employé.DepartmentID ou department.DepartmentID.

Tables dont il parlait:

enter image description here

La documentation de Postgres les définit également très bien:

La clause ON est le type le plus général de condition de jointure: elle prend une expression de valeur booléenne du même type que celle utilisée dans une clause WHERE. Une paire de lignes de T1 et T2 correspond si l'expression ON est évaluée à true.

La clause USING est un raccourci qui vous permet de tirer parti de la situation spécifique dans laquelle les deux côtés de la jointure utilisent le même nom pour la ou les colonnes de jointure. Il faut une liste séparée par des virgules des noms de colonne partagés et forme une condition de jointure qui inclut une comparaison d'égalité pour chacun. Par exemple, joindre T1 et T2 à USING (a, b) produit la condition de jointure ON T1.a = T2.a ET T1.b = T2.b.

De plus, la sortie de JOIN USING supprime les colonnes redondantes: il n'est pas nécessaire d'imprimer les deux colonnes correspondantes, car elles doivent avoir des valeurs égales. Alors que JOIN ON génère toutes les colonnes de T1 suivies de toutes les colonnes de T2, JOIN USING génère une colonne de sortie pour chacune des paires de colonnes répertoriées (dans l'ordre indiqué), suivie de toutes les colonnes restantes de T1, suivies de toutes les colonnes restantes de T2. .

9
Robert Rocha

Pour ceux qui expérimentent cela dans phpMyAdmin, juste un mot:

phpMyAdmin semble avoir quelques problèmes avec USING. Pour mémoire, il s'agit de phpMyAdmin exécuté sous Linux Mint, version: "4.5.4.1deb2ubuntu2", serveur de base de données: "10.2.14-MariaDB-10.2.14 + maria ~ xenial - distribution binaire mariadb.org".

J'ai exécuté SELECT commandes en utilisant JOIN et USING dans phpMyAdmin et dans Terminal (ligne de commande), et celles dans phpMyAdmin produisent des réponses déroutantes:

1) une clause LIMIT à la fin semble être ignorée.
2) le nombre supposé de lignes indiqué en haut de la page avec les résultats est parfois erroné: par exemple, 4 sont renvoyés, mais en haut, il est indiqué "Affichage des lignes 0 à 24 (2503 au total, Requête a pris 0,0018 secondes.) "

Se connecter à mysql normalement et exécuter les mêmes requêtes ne génère pas ces erreurs. Ces erreurs ne se produisent pas non plus lors de l'exécution de la même requête dans phpMyAdmin avec JOIN ... ON .... Vraisemblablement un bogue phpMyAdmin.

0
mike rodent