MySQL ON vs USING?

252

JOINWas ist in einem MySQL der Unterschied zwischen ONund USING()? Soweit ich das beurteilen kann, USING()ist die Syntax nur bequemer, während sie ONetwas flexibler ist, wenn die Spaltennamen nicht identisch sind. Dieser Unterschied ist jedoch so gering, dass man meinen würde, sie würden ihn einfach beseitigen USING().

Gibt es mehr, als man denkt? Wenn ja, welche sollte ich in einer bestimmten Situation verwenden?

Nathanael
quelle
1
Es gibt auch NATURAL JOIN: stackoverflow.com/questions/8696383/…
allyourcode
Beachten Sie, dass usinges neben Joins noch eine andere Verwendung gibt. Siehe stackoverflow.com/a/13750399/632951
Pacerier

Antworten:

400

Es ist meistens syntaktischer Zucker, aber ein paar Unterschiede sind bemerkenswert:

ON ist das allgemeinere der beiden. Man kann Tabellen auf einer Spalte, einer Reihe von Spalten und sogar einer Bedingung verbinden. Beispielsweise:

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

USING ist nützlich, wenn beide Tabellen eine Spalte mit genau demselben Namen verwenden, der sie beitreten. In diesem Fall kann man sagen:

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

Ein weiterer Vorteil ist, dass die Verbindungsspalten nicht vollständig qualifiziert werden müssen:

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

Um dies zu veranschaulichen und mit ON zu tun , müssten wir schreiben:

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

Beachten Sie die film.film_idQualifikation in der SELECTKlausel. Es wäre ungültig, nur zu sagen, film_idda dies zu einer Mehrdeutigkeit führen würde:

FEHLER 1052 (23000): Die Spalte 'film_id' in der Feldliste ist nicht eindeutig

Was select *erscheint der Fügespalt in der Ergebnismenge zweimal mit , ONwährend es nur einmal erscheint mit 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
quelle
2
+1 Schöne Antwort auf den syntaktischen Unterschied. Ich bin neugierig auf Leistungsunterschiede, wenn überhaupt. Ich stelle mir USINGdolmetschen vor ON.
Jason McCreary
9
Eigentlich interpretieren beide den einfachen alten Theta-Stil. Sie können dies sehen, indem Sie EXPLAIN EXTENDED für Ihre Abfrage aufrufen, gefolgt von SHOW WARNINGS.
Shlomi Noach
2
Sie können auch die USING(Kategorie ,field_id ausführen, )was nützlich ist, wenn Sie zusammengesetzte Primärschlüssel verwenden. Außerdem habe ich gehört, dass der Optimierer USINGin einigen Fällen die Leistung verbessert
Timo Huovinen,
Ist USINGeine MySQL-Definition oder Standard?
PhoneixS
5
@PhoneixS ist es im ANSI SQL 92 Standard
Shlomi Noach
18

Ich dachte, ich würde hier einspringen, wenn ich festgestellt habe ON, dass es nützlicher ist als USING. Dies ist der OUTERFall, wenn Verknüpfungen in Abfragen eingeführt werden.

ONprofitiert davon, dass die Ergebnismenge der Tabelle, zu der eine Abfrage OUTERbeitritt, eingeschränkt werden kann, während die OUTERVerknüpfung beibehalten wird . Wenn Sie versuchen, die Ergebnismenge durch Angabe einer WHEREKlausel einzuschränken , wird der OUTERJoin effektiv in einen INNERJoin umgewandelt.

Zugegeben, dies kann ein relativer Eckfall sein. Es lohnt sich jedoch, es herauszubringen .....

Beispielsweise:

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
quelle
4
Extrem guter Punkt. Von allen Vorteilen usingkann es nicht mit anderen Prädikaten kombiniert werden: select*from t join t2 using(i) and on 1würde nicht funktionieren.
Pacerier
where hasAirport ;- was bedeutet das ? Es gibt keinen Wert zum Vergleichen.
Istiaque Ahmed
Beachten Sie auch, dass Sie mit ON weitaus mehr Vergleiche durchführen können als nur =. Like SELECT * FROM country LEFT JOIN city ON country.countryId=city.countryId AND city.city BETWEEN 'C' AND 'E' listet alle Länder auf, außer nur die Städte, die mit C oder D beginnen (falls vorhanden). (Plus Städte namens 'E')
Roemer
Ich habe einmal sogar einen JOIN mit einer Unterabfrage im ON gemacht !!! Es ist alles möglich und manchmal sehr effektiv.
Roemer
11

Wikipedia hat folgende Informationen über USING:

Das USING-Konstrukt ist jedoch mehr als nur syntaktischer Zucker, da sich die Ergebnismenge von der Ergebnismenge der Version mit dem expliziten Prädikat unterscheidet. Insbesondere werden alle in der USING-Liste genannten Spalten nur einmal mit einem nicht qualifizierten Namen und nicht einmal für jede Tabelle im Join angezeigt. Im obigen Fall gibt es eine einzelne DepartmentID-Spalte und keine Mitarbeiter.DepartmentID oder Abteilung.DepartmentID.

Tabellen, über die gesprochen wurde:

Geben Sie hier die Bildbeschreibung ein

Die Postgres- Dokumentation definiert sie auch ziemlich gut:

Die ON-Klausel ist die allgemeinste Art der Verknüpfungsbedingung: Sie verwendet einen Booleschen Wertausdruck der gleichen Art wie in einer WHERE-Klausel. Ein Zeilenpaar aus T1 und T2 stimmt überein, wenn der ON-Ausdruck true ergibt.

Die USING-Klausel ist eine Abkürzung, mit der Sie die spezielle Situation nutzen können, in der beide Seiten des Joins denselben Namen für die Join-Spalte (n) verwenden. Es verwendet eine durch Kommas getrennte Liste der gemeinsam genutzten Spaltennamen und bildet eine Verknüpfungsbedingung, die für jede einen Gleichheitsvergleich enthält. Wenn Sie beispielsweise T1 und T2 mit USING (a, b) verbinden, wird die Verbindungsbedingung ON T1.a = T2.a UND T1.b = T2.b erzeugt.

Darüber hinaus unterdrückt die Ausgabe von JOIN USING redundante Spalten: Es ist nicht erforderlich, beide übereinstimmenden Spalten zu drucken, da sie gleiche Werte haben müssen. Während JOIN ON alle Spalten von T1 gefolgt von allen Spalten von T2 erzeugt, erzeugt JOIN USING eine Ausgabespalte für jedes der aufgelisteten Spaltenpaare (in der aufgelisteten Reihenfolge), gefolgt von allen verbleibenden Spalten von T1, gefolgt von allen verbleibenden Spalten von T2 .

Robert Rocha
quelle
1

Für diejenigen, die in phpMyAdmin damit experimentieren, nur ein Wort:

phpMyAdmin scheint einige Probleme mit zu haben USING. Für den Datensatz ist dies phpMyAdmin, ausgeführt unter Linux Mint, Version: "4.5.4.1deb2ubuntu2", Datenbankserver: "10.2.14-MariaDB-10.2.14 + maria ~ xenial - mariadb.org Binärdistribution".

Ich habe SELECTBefehle mit JOINund USINGsowohl in phpMyAdmin als auch in Terminal (Befehlszeile) ausgeführt, und diejenigen in phpMyAdmin erzeugen einige verwirrende Antworten:

1) Eine LIMITKlausel am Ende scheint ignoriert zu werden.
2) Die angenommene Anzahl von Zeilen, wie oben auf der Seite mit den Ergebnissen angegeben, ist manchmal falsch: Zum Beispiel werden 4 zurückgegeben, aber oben steht "Zeilen 0 - 24 anzeigen (2503 insgesamt, Abfrage dauerte 0,0018 Sekunden.) ""

Wenn Sie sich normal bei MySQL anmelden und dieselben Abfragen ausführen, treten diese Fehler nicht auf. Diese Fehler treten auch nicht auf, wenn dieselbe Abfrage in phpMyAdmin mit ausgeführt wird JOIN ... ON .... Vermutlich ein phpMyAdmin-Fehler.

Mike Nagetier
quelle