MySQL ON vs UTILISATION?

252

Dans un MySQL JOIN, quelle est la différence entre ONet USING()? Pour autant que je sache, la USING()syntaxe est juste plus pratique, alors qu'elle ONpermet un peu plus de flexibilité lorsque les noms de colonne ne sont pas identiques. Cependant, cette différence est si minime qu'on pourrait penser qu'ils s'en débarrasseraient USING().

Y a-t-il plus que cela à l'œil nu? Si oui, que dois-je utiliser dans une situation donnée?

Nathanael
la source
1
Il y a aussi NATURAL JOIN: stackoverflow.com/questions/8696383/…
allyourcode
Notez qu'il usinga une autre utilisation que les jointures Voir stackoverflow.com/a/13750399/632951
Pacerier

Réponses:

400

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

L'UTILISATION est utile lorsque les deux tables partagent une colonne du même nom exact auquel elles se joignent. Dans ce cas, on peut dire:

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

Un autre plaisir supplémentaire est qu'il n'est pas nécessaire de qualifier pleinement les colonnes de jointure:

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

Pour illustrer, 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 film.film_idqualification dans la SELECTclause. Il serait invalide de dire simplement film_idcar cela créerait une ambiguïté:

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

Quant à select *, la colonne de jointure apparaît deux fois dans l'ensemble de résultats avec ONalors 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>
Shlomi Noach
la source
2
+1 Belle réponse sur la différence syntaxique. Je suis curieux de connaître les différences de performances, le cas échéant. J'imagine USINGinterprète ON.
Jason McCreary
9
En fait, les deux interprètent à l'ancienne style Thêta. Vous pouvez le voir en appelant EXPLAIN EXTENDED sur votre requête, suivi de SHOW WARNINGS.
Shlomi Noach
2
vous pouvez également faire la USING(catégorie ,field_id )qui est utile lors de la jonction par des clés primaires composites, j'ai également entendu que l'optimiseur utilise USINGpour améliorer les performances dans certains cas
Timo Huovinen
Est-ce USINGune définition MySQL ou standard?
PhoneixS
5
@PhoneixS c'est dans la norme ANSI SQL 92
Shlomi Noach
18

Je pensais pouvoir participer ici quand j'aurais trouvé ONplus utile que USING. C'est lorsque les OUTERjointures sont introduites dans les requêtes.

ONbénéficie de la possibilité de OUTERrestreindre l'ensemble de résultats de la table sur laquelle se joint une requête tout en conservant la OUTERjointure. Tenter de restreindre l'ensemble de résultats en spécifiant une WHEREclause va effectivement transformer la OUTERjointure en INNERjointure.

Certes, cela peut être un cas d'angle relatif. Cela vaut la peine de le faire cependant .....

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)
; 
Tom Mac
la source
4
Point extrêmement bon. De tous les avantages usingfournis, il ne peut pas être combiné avec d'autres prédicats: select*from t join t2 using(i) and on 1ne fonctionnerait pas.
Pacerier
where hasAirport ;- Qu'est-ce que ça veut dire ? aucune valeur n'est comparable.
Istiaque Ahmed
Notez également que vous pouvez faire bien plus de comparaisons avec ON qu'avec juste =. Comme SELECT * FROM country LEFT JOIN city ON country.countryId=city.countryId AND city.city BETWEEN 'C' AND 'E' listera tous les pays, mais seulement les villes commençant par C ou D (le cas échéant). (Plus les villes appelées «E»)
Roemer
J'ai même fait une fois un JOIN avec une sous-requête dans ON !!! Tout cela est possible et parfois très efficace.
Roemer
11

Wikipedia contient les informations suivantes sur USING:

Cependant, la construction USING est 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 n'apparaîtront qu'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 y aura une seule colonne DepartmentID et aucun employee.DepartmentID ou department.DepartmentID.

Tableaux dont il parlait:

entrez la description de l'image ici

La documentation Postgres les définit également assez bien:

La clause ON est le type de condition de jointure le plus général: 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 où les deux côtés de la jointure utilisent le même nom pour la ou les colonnes de jointure. Il prend une liste séparée par des virgules des noms de colonnes partagées et forme une condition de jointure qui inclut une comparaison d'égalité pour chacun. Par exemple, joindre T1 et T2 avec 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 produit toutes les colonnes de T1 suivies de toutes les colonnes de T2, JOIN USING produit 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, suivie de toutes les colonnes restantes de T2 .

Robert Rocha
la source
1

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é sur 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é des SELECTcommandes en utilisant JOINet USINGdans phpMyAdmin et dans Terminal (ligne de commande), et celles de phpMyAdmin produisent des réponses déroutantes:

1) une LIMITclause à la fin semble être ignorée.
2) le nombre supposé de lignes tel que rapporté en haut de la page avec les résultats est parfois faux: par exemple 4 sont retournés, mais en haut il indique "Affichage des lignes 0 - 24 (2503 au total, la requête a pris 0,0018 secondes.) "

La connexion normale à mysql et l'exécution des mêmes requêtes ne produisent pas ces erreurs. Ces erreurs ne se produisent pas non plus lors de l'exécution de la même requête dans phpMyAdmin à l'aide de JOIN ... ON .... Vraisemblablement un bogue phpMyAdmin.

Mike rongeur
la source