MySQL ON vs USING?

252

En un MySQL JOIN, ¿cuál es la diferencia entre ONy USING()? Por lo que puedo decir, USING()es una sintaxis más conveniente, mientras que ONpermite un poco más de flexibilidad cuando los nombres de columna no son idénticos. Sin embargo, esa diferencia es tan pequeña que pensarías que simplemente la eliminarían USING().

¿Hay más en esto de lo que parece? En caso afirmativo, ¿qué debo usar en una situación dada?

Natanael
fuente
1
También hay NATURAL JOIN: stackoverflow.com/questions/8696383/…
allyourcode
Tenga en cuenta que usingtiene otro uso además de las uniones. Ver stackoverflow.com/a/13750399/632951
Pacerier

Respuestas:

400

Es principalmente azúcar sintáctico, pero hay un par de diferencias notables:

ON es el más general de los dos. Uno puede unir tablas EN una columna, un conjunto de columnas e incluso una condición. Por ejemplo:

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

USING es útil cuando ambas tablas comparten una columna del mismo nombre exacto en el que se unen. En este caso, uno puede decir:

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

Un buen regalo adicional es que uno no necesita calificar completamente las columnas de unión:

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

Para ilustrar, para hacer lo anterior con ON , tendríamos que escribir:

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

Observe la film.film_idcalificación en la SELECTcláusula. Sería inválido decirlo film_idya que eso crearía una ambigüedad:

ERROR 1052 (23000): la columna 'film_id' en la lista de campos es ambigua

En cuanto a select *, la columna de unión aparece en el conjunto de resultados dos veces con, ONmientras que solo aparece una vez con 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
fuente
2
+1 Buena respuesta sobre la diferencia sintáctica. Tengo curiosidad por las diferencias de rendimiento, si las hay. Me imagino que USINGinterpreta ON.
Jason McCreary
99
En realidad, ambos interpretan al viejo estilo Theta. Puede ver eso invocando EXPLICAR EXTENDIDO en su consulta, seguido de MOSTRAR ADVERTENCIAS.
Shlomi Noach
2
también puede hacer la USING(categoría ,field_id, )que es útil cuando se une mediante claves primarias compuestas, también escuché que el optimizador sí usa USINGpara mejorar el rendimiento en algunos casos
Timo Huovinen
¿Es USINGuna definición MySQL o es estándar?
PhoneixS
55
@PhoneixS está en el estándar ANSI SQL 92
Shlomi Noach
18

Pensé que me pondría aquí cuando me haya parecido ONmás útil que USING. Es cuandoOUTER uniones se introducen en las consultas.

ONse beneficia de permitir que el conjunto de resultados de la tabla a la que se OUTERune una consulta se restrinja mientras se mantiene la OUTERunión. Intentar restringir los resultados establecidos mediante la especificación de una WHEREcláusula, efectivamente, cambiará la OUTERunión en unINNER unión.

De acuerdo, esto puede ser un caso relativo de esquina. Vale la pena poner por ahí aunque .....

Por ejemplo:

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
fuente
44
Muy buen punto. De todas las ventajas que usingofrece, no se puede combinar con otros predicados: select*from t join t2 using(i) and on 1no funcionaría.
Pacerier
where hasAirport ;- Qué significa esto ? no hay valor para comparar.
Istiaque Ahmed
También tenga en cuenta que puede hacer muchas más comparaciones con ON que simplemente =. Like SELECT * FROM country LEFT JOIN city ON country.countryId=city.countryId AND city.city BETWEEN 'C' AND 'E' enumerará todos los países, pero solo las ciudades que comienzan con C o D (si corresponde). (Más ciudades llamadas 'E')
Roemer
¡Incluso una vez hice una JOIN con una subconsulta en el ON! Todo es posible y, a veces, altamente efectivo.
Roemer
11

Wikipedia tiene la siguiente información sobre USING:

Sin embargo, la construcción USING es más que un simple azúcar sintáctico, ya que el conjunto de resultados difiere del conjunto de resultados de la versión con el predicado explícito. Específicamente, cualquier columna mencionada en la lista USING aparecerá solo una vez, con un nombre no calificado, en lugar de una vez para cada tabla en la unión. En el caso anterior, habrá una sola columna DepartmentID y ningún empleado.DepartmentID o department.DepartmentID.

Tablas de las que estaba hablando:

ingrese la descripción de la imagen aquí

La documentación de Postgres también los define bastante bien:

La cláusula ON es el tipo más general de condición de unión: toma una expresión de valor booleano del mismo tipo que se usa en una cláusula WHERE. Un par de filas de T1 y T2 coinciden si la expresión ON se evalúa como verdadera.

La cláusula USING es una forma abreviada que le permite aprovechar la situación específica en la que ambos lados de la unión usan el mismo nombre para las columnas de unión. Toma una lista separada por comas de los nombres de columna compartidos y forma una condición de unión que incluye una comparación de igualdad para cada uno. Por ejemplo, unir T1 y T2 con USING (a, b) produce la condición de unión ON T1.a = T2.a AND T1.b = T2.b.

Además, la salida de JOIN USING suprime las columnas redundantes: no es necesario imprimir las dos columnas coincidentes, ya que deben tener valores iguales. Mientras JOIN ON produce todas las columnas de T1 seguidas de todas las columnas de T2, JOIN USING produce una columna de salida para cada uno de los pares de columnas enumerados (en el orden indicado), seguida de las columnas restantes de T1, seguidas de las columnas restantes de T2 .

Robert Rocha
fuente
1

Para aquellos que experimentan con esto en phpMyAdmin, solo una palabra:

phpMyAdmin parece tener algunos problemas con USING. Para el registro, esto es phpMyAdmin ejecutado en Linux Mint, versión: "4.5.4.1deb2ubuntu2", Servidor de base de datos: "10.2.14-MariaDB-10.2.14 + maria ~ xenial - distribución binaria mariadb.org".

He ejecutado SELECTcomandos usando JOINy USINGen phpMyAdmin y en Terminal (línea de comando), y los de phpMyAdmin producen algunas respuestas desconcertantes:

1) una LIMITcláusula al final parece ser ignorada.
2) el supuesto número de filas según se informa en la parte superior de la página con los resultados a veces es incorrecto: por ejemplo, se devuelven 4, pero en la parte superior dice "Mostrando filas 0 - 24 (2503 en total, la consulta tomó 0.0018 segundos). "

Iniciar sesión en mysql normalmente y ejecutar las mismas consultas no produce estos errores. Tampoco se producen estos errores al ejecutar la misma consulta en phpMyAdmin usando JOIN ... ON .... Presumiblemente un error phpMyAdmin.

Mike roedor
fuente