MySQL ON กับการใช้งาน?


252

ใน MySQL JOINอะไรคือความแตกต่างระหว่างONและUSING()? เท่าที่ฉันสามารถบอกได้ว่าUSING()เป็นเพียงความสะดวกสบายมากขึ้นในขณะที่ไวยากรณ์ONช่วยให้มีความยืดหยุ่นมากขึ้นเล็กน้อยเมื่อชื่อคอลัมน์ไม่เหมือนกัน อย่างไรก็ตามความแตกต่างที่ให้เล็ก ๆ น้อย ๆ USING()ที่คุณจะคิดว่าพวกเขาต้องการเพียงแค่ทำไปด้วย

มีอะไรมากกว่านี้ตรงตา? ถ้าใช่ฉันควรใช้สิ่งใดในสถานการณ์ที่กำหนด


1
นอกจากนี้ยังมี NATURAL JOIN: stackoverflow.com/questions/8696383/…
allyourcode

โปรดทราบว่าusingมีการใช้งานอื่นนอกเหนือจากการเข้าร่วม ดูstackoverflow.com/a/13750399/632951
Pacerier

คำตอบ:


400

ส่วนใหญ่แล้วจะเป็นน้ำตาลซินแทคติค แต่มีความแตกต่างกันสองประการ:

ONเป็นเรื่องทั่วไปของทั้งสอง หนึ่งสามารถเข้าร่วมตารางในคอลัมน์ชุดของคอลัมน์และแม้กระทั่งเงื่อนไข ตัวอย่างเช่น:

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

การใช้จะมีประโยชน์เมื่อทั้งสองตารางแชร์คอลัมน์ที่มีชื่อเดียวกันกับที่พวกเขาเข้าร่วม ในกรณีนี้เราอาจพูดว่า:

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

การรักษาที่ดีเพิ่มเติมคือไม่จำเป็นต้องมีคุณสมบัติครบถ้วนสำหรับคอลัมน์การเข้าร่วม:

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

เพื่อแสดงให้เห็นถึงการทำข้างต้นกับONเราจะต้องเขียน:

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

สังเกตfilm.film_idคุณสมบัติในSELECTข้อ มันจะไม่ถูกต้องเพียงแค่พูดfilm_idตั้งแต่นั้นจะทำให้มีความกำกวม:

ข้อผิดพลาด 1052 (23000): คอลัมน์ 'film_id' ในรายการฟิลด์ไม่ชัดเจน

สำหรับselect *คอลัมน์การเข้าร่วมจะปรากฏในชุดผลลัพธ์สองครั้งพร้อมกับONจะปรากฏเพียงครั้งเดียวด้วย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 คำตอบที่ดีสำหรับความแตกต่างด้านโครงสร้าง ฉันอยากรู้เกี่ยวกับความแตกต่างด้านประสิทธิภาพถ้ามี ฉันคิดตีความไปUSING ON
Jason McCreary

9
ที่จริงแล้วทั้งสองตีความเป็นสไตล์ Theta แบบธรรมดา คุณสามารถเห็นได้ว่าการเรียกใช้ EXPLAIN EXTENDED จากการค้นหาของคุณตามด้วย SHOW WARNINGS
Shlomi Noach

2
คุณสามารถทำUSING(หมวดหมู่,field_id )ซึ่งเป็นประโยชน์เมื่อเข้าร่วมโดยคีย์หลักแบบคอมโพสิตนอกจากนี้ฉันได้ยินว่าเครื่องมือเพิ่มประสิทธิภาพใช้USINGเพื่อปรับปรุงประสิทธิภาพในบางกรณี
Timo Huovinen

คือUSINGนิยาม MySQL หรือมันเป็นมาตรฐาน?
PhoneixS

5
@ PhoneixS อยู่ในมาตรฐาน ANSI SQL 92
Shlomi Noach

18

คิดว่าฉันจะชิปในที่นี่ด้วยเมื่อฉันได้พบว่าจะมีประโยชน์มากกว่าON USINGเมื่อการOUTERรวมถูกนำไปใช้กับคิวรี

ONประโยชน์ที่ได้รับจากการอนุญาตให้ชุดผลลัพธ์ของตารางที่แบบสอบถามกำลังOUTERเข้าร่วมถูก จำกัด ในขณะที่ยังคงOUTERเข้าร่วม ความพยายามในการ จำกัด ผลลัพธ์ที่ตั้งไว้ผ่านการระบุWHEREข้อจะเปลี่ยนการOUTERเข้าร่วมเป็นการINNERเข้าร่วมได้อย่างมีประสิทธิภาพ

ได้รับนี้อาจเป็นกรณีมุมญาติ คุ้มค่าที่จะออกไปที่นั่นแม้ว่า .....

ตัวอย่างเช่น:

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
จุดที่ดีมาก จากข้อดีทั้งหมดที่usingมีให้ไม่สามารถใช้ร่วมกับเพรดิเคตอื่นได้: ไม่สามารถใช้select*from t join t2 using(i) and on 1งานได้
Pacerier

where hasAirport ;- สิ่งนี้หมายความว่า ? ไม่มีค่าที่จะเปรียบเทียบกับ
Istiaque Ahmed

นอกจากนี้โปรดทราบว่าคุณสามารถเปรียบเทียบได้มากกว่า ON = Like SELECT * FROM country LEFT JOIN city ON country.countryId=city.countryId AND city.city BETWEEN 'C' AND 'E' จะแสดงรายการทุกประเทศ แต่เป็นเพียงเมืองที่เริ่มต้นด้วย C หรือ D (ถ้ามี) (บวกเมืองที่เรียกว่า 'E')
Roemer

ฉันเคยเข้าร่วมกับแบบสอบถามย่อยใน ON! มันเป็นไปได้และบางครั้งมีประสิทธิภาพสูง
Roemer

11

Wikipediaมีข้อมูลเกี่ยวกับUSING:

การสร้างโดยใช้นั้นเป็นเพียงน้ำตาลซินแทคติคเพียงอย่างเดียวเนื่องจากชุดผลลัพธ์แตกต่างจากชุดผลลัพธ์ของเวอร์ชันที่มีภาคแสดงอย่างชัดเจน โดยเฉพาะคอลัมน์ใด ๆ ที่กล่าวถึงในรายการการใช้จะปรากฏเพียงครั้งเดียวด้วยชื่อที่ไม่มีเงื่อนไขแทนที่จะเป็นหนึ่งครั้งสำหรับแต่ละตารางในการเข้าร่วม ในกรณีข้างต้นจะมีคอลัมน์ DepartmentID เดียวและไม่มีพนักงานแผนก ID หรือแผนกแผนก

ตารางที่พูดถึง:

ป้อนคำอธิบายรูปภาพที่นี่

Postgresเอกสารนอกจากนี้ยังกำหนดให้พวกเขาสวยดี:

ส่วนคำสั่ง ON เป็นเงื่อนไขการเข้าร่วมแบบทั่วไปที่สุด: มันต้องใช้นิพจน์ค่าบูลีนชนิดเดียวกับที่ใช้ในส่วนคำสั่ง WHERE คู่ของแถวจาก T1 และ T2 ตรงกันหากนิพจน์ ON ประเมินค่าเป็นจริง

ประโยคการใช้เป็นข้อความย่อที่ช่วยให้คุณสามารถใช้ประโยชน์จากสถานการณ์เฉพาะที่ทั้งสองด้านของการเข้าร่วมใช้ชื่อเดียวกันสำหรับคอลัมน์การเข้าร่วม ใช้รายการที่คั่นด้วยเครื่องหมายจุลภาคของชื่อคอลัมน์ที่ใช้ร่วมกันและสร้างเงื่อนไขการรวมที่มีการเปรียบเทียบความเท่าเทียมกันสำหรับแต่ละรายการ ตัวอย่างเช่นการรวม T1 และ T2 ด้วยการใช้ (a, b) จะสร้างเงื่อนไขการเข้าร่วม ON T1.a = T2.a และ T1.b = T2.b

นอกจากนี้เอาต์พุตของ JOIN USING ยังไม่ใส่คอลัมน์ที่ซ้ำซ้อน: ไม่จำเป็นต้องพิมพ์ทั้งสองคอลัมน์ที่ตรงกันเนื่องจากจะต้องมีค่าเท่ากัน ในขณะที่ JOIN ON สร้างคอลัมน์ทั้งหมดจาก T1 ตามด้วยคอลัมน์ทั้งหมดจาก T2 แต่ JOIN USING จะสร้างคอลัมน์เอาต์พุตหนึ่งคอลัมน์สำหรับแต่ละคอลัมน์คู่ที่ระบุ (ตามลำดับที่แสดง) ตามด้วยคอลัมน์ที่เหลือจาก T1 ตามด้วยคอลัมน์ที่เหลือจาก T2 .


1

สำหรับผู้ที่ทดลองใช้สิ่งนี้ใน phpMyAdmin เพียงคำเดียว:

phpMyAdmin ดูเหมือนจะมีปัญหาUSINGเล็กน้อย สำหรับเร็กคอร์ดนี้คือ phpMyAdmin ทำงานบน Linux Mint เวอร์ชัน: "4.5.4.1deb2ubuntu2", เซิร์ฟเวอร์ฐานข้อมูล: "10.2.14-MariaDB-10.2.14 + maria ~ xenial - mariadb.org การแจกแจงแบบไบนารี"

ฉันรันSELECTคำสั่งโดยใช้JOINและUSINGในทั้ง phpMyAdmin และใน Terminal (บรรทัดคำสั่ง) และคำสั่งใน phpMyAdmin สร้างการตอบสนองที่ยุ่งเหยิง:

1) LIMITส่วนท้ายที่ปรากฏจะถูกละเว้น
2) จำนวนแถวที่ควรตามที่รายงานที่ด้านบนสุดของหน้าเว็บที่มีผลลัพธ์ไม่ถูกต้อง: ตัวอย่าง 4 จะถูกส่งกลับ แต่ที่ด้านบนจะมีข้อความระบุว่า "แสดงแถว 0 - 24 (รวม 2503 ทั้งหมดแบบสอบถามใช้เวลา 0.0018 วินาที) "

เข้าสู่ระบบ mysql ตามปกติและการเรียกใช้แบบสอบถามเดียวกันไม่ก่อให้เกิดข้อผิดพลาดเหล่านี้ ไม่ทำผิดพลาดเหล่านี้เกิดขึ้นเมื่อเรียกใช้แบบสอบถามเดียวกันใน phpMyAdmin JOIN ... ON ...ใช้ น่าจะเป็นข้อผิดพลาด phpMyAdmin

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.