MySQL ON vs USING?


252

In un MySQL JOIN, qual è la differenza tra ONe USING()? Per quanto ne so, USING()è solo una sintassi più conveniente, mentre ONconsente un po 'più di flessibilità quando i nomi delle colonne non sono identici. Tuttavia, quella differenza è così minore, penseresti che eliminerebbero USING().

C'è di più in questo di quanto sembri? Se sì, quale dovrei usare in una determinata situazione?



Nota che usingha un altro utilizzo oltre ai join. Vedere stackoverflow.com/a/13750399/632951
Pacerier

Risposte:


400

È principalmente zucchero sintattico, ma un paio di differenze sono degne di nota:

ON è il più generale dei due. Si possono unire le tabelle su una colonna, un insieme di colonne e persino una condizione. Per esempio:

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

L'USO è utile quando entrambe le tabelle condividono una colonna con lo stesso identico nome a cui si uniscono. In questo caso, si potrebbe dire:

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

Un'ulteriore piacevole sorpresa è che non è necessario qualificare completamente le colonne di unione:

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

Per illustrare, per fare quanto sopra con ON , dovremmo scrivere:

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

Si noti la film.film_idqualificazione nella SELECTclausola. Sarebbe invalido solo dire film_idpoiché ciò creerebbe un'ambiguità:

ERRORE 1052 (23000): la colonna 'film_id' nell'elenco dei campi è ambigua

Per quanto riguarda select *, la colonna di unione appare nel set di risultati due volte con ONmentre appare una sola volta 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>

2
+1 Bella risposta sulla differenza sintattica. Sono curioso delle differenze di prestazioni, se presenti. Immagino che USINGinterpreti ON.
Jason McCreary,

9
In realtà, entrambi interpretano il semplice vecchio stile Theta. Puoi vederlo invocando EXPLAIN EXTENDED sulla tua query, seguito da SHOW WARNINGS.
Shlomi Noach,

2
puoi anche fare la USING(categoria ,field_id )che è utile quando ti unisci con chiavi primarie composite, ho anche sentito che l'ottimizzatore usa USINGper migliorare le prestazioni in alcuni casi
Timo Huovinen il

È USINGuna definizione di MySQL o è standard?
PhoneixS,

5
@PhoneixS è nello standard ANSI SQL 92
Shlomi Noach il

18

Ho pensato di aggiungere qui quando ho scoperto ONdi essere più utile di USING. È quando i OUTERjoin vengono introdotti nelle query.

ONtrae vantaggio dal consentire la OUTERrestrizione del set di risultati della tabella a cui si unisce una query mantenendo lo stesso OUTER. Il tentativo di limitare il set di risultati specificando una WHEREclausola cambierà effettivamente il OUTERjoin in un INNERjoin.

Concesso, questo potrebbe essere un caso relativo relativo. Vale la pena metterlo fuori però .....

Per esempio:

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)
; 

4
Punto estremamente positivo. Di tutti i vantaggi usingofferti, non può essere combinato con altri predicati: select*from t join t2 using(i) and on 1non funzionerebbe.
Pacerier,

where hasAirport ;- Cosa significa questo ? nessun valore è lì per confrontare.
Istiaque Ahmed,

Si noti inoltre che è possibile eseguire più confronti con ON rispetto a solo =. Like SELECT * FROM country LEFT JOIN city ON country.countryId=city.countryId AND city.city BETWEEN 'C' AND 'E' elencherà tutti i paesi, ma solo le città che iniziano con C o D (se presenti). (Più città chiamate 'E')
Roemer

Una volta ho anche fatto un JOIN con una subquery in ON !!! È tutto possibile e talvolta altamente efficace.
Roemer,

11

Wikipedia ha le seguenti informazioni su USING:

Il costrutto USING è più che semplice zucchero sintattico, tuttavia, poiché il set di risultati differisce dal set di risultati della versione con il predicato esplicito. In particolare, tutte le colonne menzionate nell'elenco USING verranno visualizzate una sola volta, con un nome non qualificato, anziché una volta per ogni tabella nel join. Nel caso sopra, ci sarà una singola colonna DepartmentID e nessun dipendente.DepartmentID o department.DepartmentID.

Tabelle di cui stava parlando:

inserisci qui la descrizione dell'immagine

La documentazione di Postgres li definisce anche abbastanza bene:

La clausola ON è il tipo più generale di condizione di join: accetta un'espressione di valore booleano dello stesso tipo utilizzata in una clausola WHERE. Una coppia di righe da T1 e T2 corrispondono se l'espressione ON viene valutata vera.

La clausola USING è una scorciatoia che consente di sfruttare la situazione specifica in cui entrambi i lati del join usano lo stesso nome per le colonne di join. Prende un elenco separato da virgole dei nomi delle colonne condivise e forma una condizione di join che include un confronto di uguaglianza per ciascuno. Ad esempio, l'unione di T1 e T2 con USING (a, b) produce la condizione di unione ON T1.a = T2.a E T1.b = T2.b.

Inoltre, l'output di JOIN USING elimina le colonne ridondanti: non è necessario stampare entrambe le colonne corrispondenti, poiché devono avere valori uguali. Mentre JOIN ON produce tutte le colonne da T1 seguite da tutte le colonne da T2, JOIN USING produce una colonna di output per ciascuna delle coppie di colonne elencate (nell'ordine elencato), seguita da tutte le colonne rimanenti da T1, seguite da eventuali colonne rimanenti da T2 .


1

Per coloro che sperimentano questo in phpMyAdmin, basta una parola:

phpMyAdmin sembra avere qualche problema con USING. Per la cronaca questo è phpMyAdmin eseguito su Linux Mint, versione: "4.5.4.1deb2ubuntu2", server database: "10.2.14-MariaDB-10.2.14 + maria ~ xenial - distribuzione binaria mariadb.org".

Ho eseguito SELECTi comandi utilizzando JOINe USINGsia in phpMyAdmin e nel Terminal (riga di comando), e quelli in phpMyAdmin produrre alcune risposte sconcertanti:

1) una LIMITclausola alla fine sembra essere ignorata.
2) il numero presunto di righe riportato nella parte superiore della pagina con i risultati è talvolta errato: ad esempio 4 vengono restituiti, ma nella parte superiore viene visualizzato il messaggio "Visualizzazione delle righe da 0 a 24 (2503 in totale, la query ha richiesto 0,0018 secondi.) "

Accedere a mysql normalmente ed eseguire le stesse query non produce questi errori. Né si verificano questi errori quando si esegue la stessa query in phpMyAdmin utilizzando JOIN ... ON .... Presumibilmente un bug phpMyAdmin.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.