MySQL TRÊN vs SỬ DỤNG?


252

Trong một MySQL JOIN, sự khác biệt giữa ONvà là USING()gì? Theo như tôi có thể nói, USING()chỉ là cú pháp thuận tiện hơn, trong khi ONcho phép linh hoạt hơn một chút khi tên cột không giống nhau. Tuy nhiên, sự khác biệt đó là rất nhỏ, bạn nghĩ rằng họ sẽ bỏ đi USING().

Có nhiều điều này hơn là bắt mắt? Nếu có, tôi nên sử dụng cái nào trong một tình huống nhất định?


1
Ngoài ra còn có THAM GIA TỰ NHIÊN: stackoverflow.com/questions/8696383/ từ
allyourcode

Lưu ý rằng usingcó một cách sử dụng khác ngoài tham gia. Xem stackoverflow.com/a/13750399/632951
Pacerier

Câu trả lời:


400

Nó chủ yếu là đường cú pháp, nhưng một số khác biệt đáng chú ý:

ON là tổng quát hơn của hai. Người ta có thể nối các bảng TRÊN một cột, một tập hợp các cột và thậm chí là một điều kiện. Ví dụ:

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

SỬ DỤNG rất hữu ích khi cả hai bảng chia sẻ một cột có cùng tên mà chúng tham gia. Trong trường hợp này, người ta có thể nói:

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

Một điều tuyệt vời nữa là người ta không cần phải đủ điều kiện tham gia các cột tham gia:

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

Để minh họa, để làm như trên với ON , chúng ta sẽ phải viết:

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

Lưu ý trình film.film_idđộ trong SELECTmệnh đề. Sẽ không hợp lệ nếu chỉ nói film_idvì điều đó sẽ tạo ra sự mơ hồ:

LRI 1052 (23000): Cột 'film_id' trong danh sách trường không rõ ràng

Đối với select *, cột tham gia xuất hiện trong tập kết quả hai lần ONtrong khi nó chỉ xuất hiện một lần với 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 Câu trả lời hay về sự khác biệt cú pháp. Tôi tò mò về sự khác biệt hiệu suất, nếu có. Tôi tưởng tượng USINGthông dịch đến ON.
Jason McCreary

9
Trên thực tế, cả hai đều diễn giải theo phong cách Theta cũ. Bạn có thể thấy điều đó bằng cách gọi EXPLAIN EXTENDED trên truy vấn của bạn, theo sau là SHOW WARNING.
Shlomi Noach

2
bạn cũng có thể thực hiện USING(danh mục ,field_id )rất hữu ích khi tham gia bằng các khóa chính tổng hợp, tôi cũng nghe nói rằng trình tối ưu hóa sẽ sử dụng USINGđể cải thiện hiệu suất trong một số trường hợp
Timo Huovinen

USINGmột định nghĩa MySQL hay nó là tiêu chuẩn?
PhoneixS

5
@PhoneixS, nó nằm trong tiêu chuẩn ANSI SQL 92
Shlomi Noach

18

Nghĩ rằng tôi sẽ sứt mẻ ở đây khi tôi thấy ONcó ích hơn USING. Đó là khi OUTERtham gia được giới thiệu vào các truy vấn.

ONlợi ích từ việc cho phép tập hợp kết quả của bảng mà truy vấn đang OUTERtham gia bị hạn chế trong khi duy trì liên OUTERkết. Cố gắng hạn chế các kết quả được đặt thông qua việc chỉ định một WHEREmệnh đề sẽ, một cách hiệu quả, thay đổi phép OUTERnối thành một phép INNERnối.

Cấp này có thể là một trường hợp góc tương đối. Đáng để đưa ra ngoài mặc dù .....

Ví dụ:

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
Điểm cực kỳ tốt. Trong tất cả các lợi thế usingcung cấp, nó không thể được kết hợp với các vị từ khác: sẽ không select*from t join t2 using(i) and on 1hoạt động.
Pacerier

where hasAirport ;- Điều đó có nghĩa là gì ? không có giá trị nào để so sánh với
Istiaque Ahmed

Cũng lưu ý rằng bạn có thể thực hiện nhiều cách so sánh với ON hơn là chỉ =. Like SELECT * FROM country LEFT JOIN city ON country.countryId=city.countryId AND city.city BETWEEN 'C' AND 'E' sẽ liệt kê tất cả các quốc gia nhưng chỉ các thành phố bắt đầu bằng C hoặc D (nếu có). (Cộng với các thị trấn được gọi là 'E')
RoTable

Tôi thậm chí đã từng THAM GIA với một truy vấn con trong ON !!! Đó là tất cả có thể và đôi khi có hiệu quả cao.
RoTable

11

Wikipedia có các thông tin sau về USING:

Tuy nhiên, cấu trúc USING không chỉ đơn thuần là đường cú pháp, vì tập kết quả khác với tập kết quả của phiên bản với vị từ rõ ràng. Cụ thể, bất kỳ cột nào được đề cập trong danh sách SỬ DỤNG sẽ chỉ xuất hiện một lần, với tên không đủ tiêu chuẩn, thay vì một lần cho mỗi bảng trong liên kết. Trong trường hợp trên, sẽ có một cột DepartmentID duy nhất và không có nhân viên.DepidorID hoặc bộ phận.DepidorID.

Những cái bàn mà nó đang nói đến:

nhập mô tả hình ảnh ở đây

Các Postgres tài liệu cũng định nghĩa chúng khá tốt:

Mệnh đề ON là loại điều kiện nối chung nhất: nó có biểu thức giá trị Boolean cùng loại như được sử dụng trong mệnh đề WHERE. Một cặp hàng từ T1 và T2 khớp nhau nếu biểu thức ON ước tính là đúng.

Mệnh đề USING là một tốc ký cho phép bạn tận dụng tình huống cụ thể trong đó cả hai mặt của phép nối sử dụng cùng tên cho (các) cột tham gia. Nó lấy một danh sách được phân tách bằng dấu phẩy của các tên cột được chia sẻ và tạo thành một điều kiện nối bao gồm một so sánh bằng cho mỗi cái. Ví dụ: tham gia T1 và T2 với USING (a, b) tạo ra điều kiện nối ON T1.a = T2.a VÀ T1.b = T2.b.

Hơn nữa, đầu ra của THAM GIA SỬ DỤNG ngăn chặn các cột dư thừa: không cần phải in cả hai cột khớp nhau, vì chúng phải có các giá trị bằng nhau. Trong khi THAM GIA BẬT tạo ra tất cả các cột từ T1 theo sau là tất cả các cột từ T2, THAM GIA SỬ DỤNG tạo một cột đầu ra cho mỗi cặp cột được liệt kê (theo thứ tự được liệt kê), theo sau là các cột còn lại từ T1, tiếp theo là các cột còn lại từ T2 .


1

Đối với những người thử nghiệm điều này trong phpMyAdmin, chỉ cần một từ:

phpMyAdmin dường như có một vài vấn đề với USING. Đối với bản ghi này là phpMyAdmin chạy trên Linux Mint, phiên bản: "4.5.4.1deb2ubfox2", Máy chủ cơ sở dữ liệu: "10.2.14-MariaDB-10.2.14 + maria ~ xenial - mariadb.org phân phối nhị phân".

Tôi đã chạy SELECTcác lệnh bằng cách sử dụng JOINUSINGtrong cả phpMyAdmin và trong Terminal (dòng lệnh) và các lệnh trong phpMyAdmin tạo ra một số phản hồi khó hiểu:

1) một LIMITmệnh đề ở cuối dường như bị bỏ qua.
2) số lượng hàng được cho là được báo cáo ở đầu trang với kết quả đôi khi sai: ví dụ 4 được trả về, nhưng ở trên cùng có ghi "Hiển thị các hàng 0 - 24 (tổng cộng 2503, Truy vấn mất 0,0018 giây.) "

Đăng nhập vào mysql bình thường và chạy các truy vấn tương tự không tạo ra các lỗi này. Cũng không xảy ra các lỗi này khi chạy cùng một truy vấn trong phpMyAdmin JOIN ... ON .... Có lẽ là một lỗi phpMyAdmin.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.