เข้าร่วมภายในกับข้อที่


941

NOT NULLสำหรับความเรียบง่ายสมมติช่องที่เกี่ยวข้องทั้งหมดที่มี

คุณทำได้:

SELECT
    table1.this, table2.that, table2.somethingelse
FROM
    table1, table2
WHERE
    table1.foreignkey = table2.primarykey
    AND (some other conditions)

หรืออื่น ๆ:

SELECT
    table1.this, table2.that, table2.somethingelse
FROM
    table1 INNER JOIN table2
    ON table1.foreignkey = table2.primarykey
WHERE
    (some other conditions)

ทั้งสองทำงานในลักษณะเดียวกันMySQLหรือไม่




18
หากฉันเข้าใจถูกต้องตัวแปรแรกคือไวยากรณ์โดยนัย ANSI SQL-89 และตัวแปรที่สองคือไวยากรณ์เข้าร่วม ANSI SQL-92 อย่างชัดเจน ทั้งคู่จะส่งผลให้ผลลัพธ์เดียวกันในการปรับใช้ SQL ให้สอดคล้องและทั้งคู่จะส่งผลให้มีแผนแบบสอบถามเดียวกันในการปรับใช้ SQL ที่ทำได้ดี ฉันชอบไวยากรณ์ของ SQL-89 โดยส่วนตัว แต่หลายคนชอบไวยากรณ์ของ SQL-92
Mikko Rantalainen

11
@ โฮแกนฉันได้ชี้ให้เห็นชื่ออย่างเป็นทางการสำหรับไวยากรณ์ที่แตกต่างกัน ไม่มีคำตอบที่สะกดชื่อเต็มอย่างชัดเจนดังนั้นฉันจึงตัดสินใจเพิ่มคำเหล่านั้นเป็นความคิดเห็น อย่างไรก็ตามความคิดเห็นของฉันไม่ได้ตอบคำถามจริงดังนั้นฉันจึงเพิ่มเติมว่าเป็นความคิดเห็นไม่ใช่คำตอบ (คำตอบที่โหวตอย่างสูงมีการอ้างสิทธิ์เช่น "INNER JOIN คือ ANSI ไวยากรณ์" และ "นัยเข้าร่วมไวยากรณ์ ANSI เก่ากว่า" ซึ่งไม่ได้กล่าวอะไรเลยเพราะไวยากรณ์ทั้งสองนั้นแตกต่างกันไปตามไวยากรณ์ ANSI)
Mikko Rantalainen

คำตอบ:


710

INNER JOIN เป็นไวยากรณ์ ANSI ที่คุณควรใช้

โดยทั่วไปถือว่าอ่านได้มากขึ้นโดยเฉพาะเมื่อคุณเข้าร่วมตารางจำนวนมาก

นอกจากนี้ยังสามารถเปลี่ยนได้อย่างง่ายดายด้วยOUTER JOINสิ่งที่ต้องการ

WHEREไวยากรณ์แบบเชิงสัมพันธ์มุ่งเน้นมากขึ้น

ผลลัพธ์ของสองตารางJOINed เป็นผลิตภัณฑ์คาร์ทีเซียนของตารางที่ใช้ตัวกรองซึ่งเลือกเฉพาะแถวเหล่านั้นที่มีการจับคู่คอลัมน์ที่เข้าร่วม

เห็นได้ง่ายกว่าด้วยWHEREไวยากรณ์

สำหรับตัวอย่างของคุณใน MySQL (และโดยทั่วไปใน SQL) แบบสอบถามทั้งสองนี้มีความหมายเหมือนกัน

นอกจากนี้โปรดทราบว่า MySQL ยังมีSTRAIGHT_JOINข้อ

การใช้ข้อนี้คุณสามารถควบคุมJOINลำดับ: ตารางใดที่ถูกสแกนในลูปด้านนอกและอันไหนที่อยู่ในลูปด้านใน

คุณไม่สามารถควบคุมสิ่งนี้ใน MySQL โดยใช้WHEREไวยากรณ์


10
ขอบคุณ Quassnoi คุณมีรายละเอียดมากมายในคำตอบของคุณ มันยุติธรรมหรือไม่ที่จะบอกว่า "ใช่คำค้นหาเหล่านั้นจะเทียบเท่ากัน แต่คุณควรใช้การรวมภายในเพราะสามารถอ่านได้ง่ายขึ้นและปรับเปลี่ยนได้ง่ายขึ้น"?
allyourcode

8
@allyourcode: สำหรับOracle, SQL Server, MySQLและPostgreSQL- ใช่ สำหรับระบบอื่นอาจจะเหมือนกัน แต่คุณควรตรวจสอบ
Quassnoi

13
FWIW การใช้เครื่องหมายจุลภาคที่มีเงื่อนไขการเข้าร่วมในWHEREข้อนี้ยังอยู่ในมาตรฐาน ANSI
Bill Karwin

1
@Bill Karwin: JOINคำหลักไม่ได้เป็นส่วนหนึ่งของมาตรฐานที่เป็นกรรมสิทธิ์จนกระทั่งเมื่อไม่นานมานี้ซึ่งอาจดูเหมือนว่า มันเข้ามาOracleในรุ่น9และเป็นPostgreSQLรุ่นเท่านั้น7.2(ทั้งคู่เปิดตัว2001) ลักษณะที่ปรากฏของคำหลักนี้เป็นส่วนหนึ่งของANSIการยอมรับมาตรฐานและนั่นคือสาเหตุที่คำหลักนี้มักเกี่ยวข้องกับANSIแม้ว่าข้อเท็จจริงที่ว่าหลังสนับสนุนเครื่องหมายจุลภาคเป็นคำCROSS JOINเหมือนกัน
Quassnoi

9
อย่างไรก็ตามการรวม ANSI SQL-89 ที่ระบุจะต้องทำด้วยเครื่องหมายจุลภาคและเงื่อนไขในWHEREข้อ (โดยไม่มีเงื่อนไขการเข้าร่วมจะเท่ากับการเข้าร่วมข้ามตามที่คุณพูด) ANSI SQL-92 เพิ่มJOINคีย์เวิร์ดและไวยากรณ์ที่เกี่ยวข้อง แต่ยังสนับสนุนไวยากรณ์แบบคอมม่าสำหรับคอมแพตทิเบิลย้อนหลัง
Bill Karwin

182

คนอื่น ๆ ได้ชี้ให้เห็นว่าINNER JOINช่วยให้มนุษย์อ่านได้และนั่นคือสิ่งที่สำคัญที่สุดฉันเห็นด้วย
ให้ฉันพยายามอธิบายว่าทำไมไวยากรณ์การเข้าร่วมอ่านได้ง่ายขึ้น

SELECTแบบสอบถามพื้นฐานคือ:

SELECT stuff
FROM tables
WHERE conditions

SELECTประโยคบอกเราว่าสิ่งที่เราได้รับกลับมา FROMประโยคบอกเราที่เราได้รับจากและWHEREประโยคบอกเราที่คนที่เราได้รับ

JOIN เป็นคำสั่งเกี่ยวกับตารางการผูกเข้าด้วยกันอย่างไร (ตามความเป็นจริงแล้วเป็นตารางเดียว)

องค์ประกอบการสืบค้นใด ๆ ที่ควบคุมตาราง - ที่ที่เราได้รับสิ่งของ - ความหมายของFROMประโยค (และแน่นอนว่าเป็นที่ที่JOINองค์ประกอบ) การใส่องค์ประกอบการรวมไว้ในส่วนWHEREคำสั่ง conflates สิ่งที่และที่มานั่นคือเหตุผลที่ต้องการJOINไวยากรณ์


7
ขอบคุณสำหรับการชี้แจงว่าทำไมการรวมภายในเป็นที่ต้องการคาร์ล ฉันคิดว่าคำตอบของคุณนั้นแฝงอยู่ในคนอื่น ๆ แต่โดยทั่วไปมักจะดีกว่า (ใช่ฉันเป็นแฟนงูหลาม)
allyourcode

2
ความหมายของ ON และ WHERE หมายความว่าสำหรับ JOIN หลังจากเข้าร่วม OUTER ครั้งสุดท้ายมันไม่สำคัญว่าคุณจะใช้อะไร แม้ว่าคุณลักษณะในฐานะส่วนหนึ่งของการเข้าร่วมมันเป็นยังกรองหลังจากผลิตภัณฑ์ Cartesian ทั้งเปิดและที่กรองผลิตภัณฑ์คาร์ทีเซียน แต่จะต้องใช้ ON หรือ subselect กับ WHERE ก่อน OUTER JOIN ครั้งสุดท้าย (ร่วมไม่ได้ "กับ" คู่คอลัมน์สองตารางสามารถร่วมแสดงบนเงื่อนไขใด ๆ นั่นเป็นเพียงวิธีการตีความร่วมบนความเท่าเทียมกันของคอลัมน์โดยเฉพาะ...)
philipxy

แม้ว่าคุณจะใช้ WHERE เพื่อให้ได้ผลเหมือนกันของ INNER JOIN คุณก็จะพูดถึงสองตารางในส่วน FROM ของข้อความค้นหา ดังนั้นโดยทั่วไปคุณยังคงหมายความว่าคุณจะได้รับข้อมูลของคุณในข้อจากดังนั้นผมคิดว่าคุณไม่สามารถพูดได้ว่ามันจำเป็นต้อง "conflates ที่และที่จาก"
cybergeek654

@ArsenKhachaturyan เพียงเพราะมีการใช้คำหลักหรือตัวระบุในข้อความไม่ได้แปลว่าเป็นรูปแบบรหัสและต้องการรหัส นั่นคือตัวเลือกการจัดรูปแบบที่สามารถไปทางใดก็ได้ & หากมีเหตุผลที่จะแก้ไขที่นี่ก็เป็นเหตุผลที่ทุกโพสต์จะได้รับการแก้ไขอย่างต่อเนื่องในรูปแบบอื่น ๆ - ซึ่งก็คือการพูดว่ามันไม่สมเหตุสมผล (การเพิ่มรูปแบบโค้ดต่อคำแบบอินไลน์อาจเป็นการยากที่จะอ่าน) เช่นเดียวกับการแบ่งย่อหน้าที่นี่ - พวกเขาไม่ได้ชี้แจงโดยเฉพาะอย่างยิ่ง เช่นเดียวกันกับ 'ซึ่ง' vs 'ที่' และชื่อของภาษาการเขียนโปรแกรมไม่ควรอยู่ในรูปแบบของรหัส PS คุณเพิ่มข้อผิดพลาดการแบ่งบรรทัด
philipxy

@philipxy ตามที่คุณพูดถึง "มันไม่ได้หมายความว่า ... " แต่ก็ไม่ได้หมายความว่าจะไม่สามารถทำเครื่องหมายด้วยคำหลักรหัสได้ ใช่เป็นทางเลือกที่จะทำ แต่มีการโพสต์จำนวนมากโดยไม่ทราบข้อเท็จจริงนั้น ดังนั้นการตัดสินใจของฉันในการเปลี่ยนแปลงไม่ได้มีวัตถุประสงค์เพื่อทำลายสิ่งใด แต่ทำให้อ่านง่ายขึ้น หากคุณสังเกตเห็นว่ามีการหยุดพักหลังจากการเปลี่ยนแปลงเกิดขึ้นขออภัยสำหรับสิ่งนั้นและคุณสามารถยกเลิกการเปลี่ยนแปลงนั้น
Arsen Khachaturyan

143

การใช้ข้อความสั่งแบบมีเงื่อนไขใน ON / WHERE

ที่นี่ฉันได้อธิบายเกี่ยวกับขั้นตอนการประมวลผลแบบสอบถามแบบตรรกะ


การอ้างอิง: การ สืบค้นT-SQL ของMicrosoft® SQL Server ™ 2005
สำนักพิมพ์: Microsoft Press
Pub วันที่: 7 มีนาคม 2549
พิมพ์ ISBN-10: 0-7356-2313-9
พิมพ์ ISBN-13: 978-0-7356-2313-2
หน้า: 640

ภายในการสืบค้น T-SQL T-SQL ของMicrosoft® SQL Server ™ 2005

(8)  SELECT (9) DISTINCT (11) TOP <top_specification> <select_list>
(1)  FROM <left_table>
(3)       <join_type> JOIN <right_table>
(2)       ON <join_condition>
(4)  WHERE <where_condition>
(5)  GROUP BY <group_by_list>
(6)  WITH {CUBE | ROLLUP}
(7)  HAVING <having_condition>
(10) ORDER BY <order_by_list>

สิ่งที่สังเกตเห็นได้อย่างแรกของ SQL ที่แตกต่างจากภาษาการเขียนโปรแกรมอื่นคือลำดับที่ประมวลผลโค้ด ในภาษาโปรแกรมส่วนใหญ่รหัสจะถูกประมวลผลตามลำดับที่ถูกเขียน ใน SQL ส่วนคำสั่งแรกที่ถูกประมวลผลคือส่วนคำสั่ง FROM ในขณะที่ส่วนคำสั่ง SELECT ซึ่งปรากฏขึ้นครั้งแรกนั้นจะได้รับการประมวลผลเกือบจะสุดท้าย

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

คำอธิบายสั้น ๆ ของขั้นตอนการประมวลผลแบบสอบถามตรรกะ

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

  1. จาก: ผลิตภัณฑ์คาร์ทีเซียน (cross join) ดำเนินการระหว่างสองตารางแรกในส่วนคำสั่ง FROM และผลลัพธ์ตารางเสมือน VT1 จะถูกสร้างขึ้น

  2. ON: ตัวกรอง ON จะใช้กับ VT1 เฉพาะแถวที่มีค่า<join_condition>เป็น TRUE เท่านั้นที่ถูกแทรกไปยัง VT2

  3. OUTER (join): หากระบุ OUTER JOIN (ตรงข้ามกับ CROSS JOIN หรือ INNER JOIN) แถวจากตารางหรือตารางที่สงวนไว้ซึ่งไม่พบการแข่งขันจะถูกเพิ่มไปยังแถวจาก VT2 เป็นแถวด้านนอก VT3 หากมีมากกว่าสองตารางปรากฏในส่วนคำสั่ง FROM จะใช้ขั้นตอนที่ 1 ถึง 3 ซ้ำ ๆ กันระหว่างผลลัพธ์ของการเข้าร่วมครั้งล่าสุดและตารางถัดไปในส่วนคำสั่ง FROM จนกว่าจะประมวลผลตารางทั้งหมด

  4. ตำแหน่ง: ตัวกรองตำแหน่งถูกใช้กับ VT3 เฉพาะแถวที่มีค่า<where_condition>เป็น TRUE เท่านั้นที่ถูกแทรกไปยัง VT4

  5. GROUP BY: แถวจาก VT4 ถูกจัดเรียงเป็นกลุ่มตามรายการคอลัมน์ที่ระบุไว้ใน GROUP BY clause สร้าง VT5 แล้ว

  6. CUBE | ROLLUP: Supergroups (กลุ่มของกลุ่ม) ถูกเพิ่มลงในแถวจาก VT5 สร้าง VT6

  7. HAVING: ตัวกรอง HAVING ถูกนำไปใช้กับ VT6 เฉพาะกลุ่มที่ใส่<having_condition>TRUE ไว้กับ VT7

  8. SELECT: รายการ SELECT ได้รับการดำเนินการสร้าง VT8

  9. DISTINCT: แถวที่ซ้ำกันจะถูกลบออกจาก VT8 สร้าง VT9 แล้ว

  10. ORDER BY: แถวจาก VT9 เรียงตามรายการคอลัมน์ที่ระบุไว้ในข้อ ORDER BY เคอร์เซอร์ถูกสร้างขึ้น (VC10)

  11. TOP: เลือกจำนวนหรือเปอร์เซ็นต์ของแถวที่ระบุตั้งแต่ต้น VC10 ตาราง VT11 ถูกสร้างและส่งคืนไปยังผู้เรียก



ดังนั้น (เข้าร่วมภายใน) ON จะกรองข้อมูล (จำนวนข้อมูลของ VT จะลดลงที่นี่) ก่อนที่จะใช้ WHERE clause เงื่อนไขการเข้าร่วมที่ตามมาจะถูกดำเนินการกับข้อมูลที่กรองซึ่งปรับปรุงประสิทธิภาพ หลังจากนั้นเฉพาะเงื่อนไข WHERE ที่จะใช้เงื่อนไขตัวกรอง

(การใช้ข้อความสั่งแบบมีเงื่อนไขใน ON / WHERE จะไม่สร้างความแตกต่างมากนักในบางกรณีทั้งนี้ขึ้นอยู่กับจำนวนตารางที่คุณเข้าร่วมและจำนวนแถวที่มีในแต่ละตารางการเข้าร่วม)


10
"ดังนั้น (INNER JOIN) ON จะกรองข้อมูล (จำนวนข้อมูลของ VT จะลดลงที่นี่) ก่อนที่จะใช้ WHERE clause" ไม่จำเป็น. บทความเกี่ยวกับลำดับของการประมวลผลเชิงตรรกะ เมื่อคุณพูดโดยเฉพาะอย่างยิ่งการดำเนินงานที่จะทำสิ่งหนึ่งก่อนสิ่งอื่นที่คุณกำลังพูดคุยเกี่ยวกับการดำเนินการตามคำสั่งของการประมวลผล การใช้งานจะได้รับอนุญาตให้ทำการปรับแต่งตามต้องการตราบใดที่ผลลัพธ์นั้นเหมือนกับว่าการนำไปปฏิบัติตามลำดับเชิงตรรกะ Joe Celko เขียนเกี่ยวกับเรื่องนี้ใน Usenet มาก
Mike Sherrill 'Cat Recall'

@rafidheen "(เข้าร่วมภายใน) เปิดจะกรองข้อมูล ... ก่อนที่จะใช้คำสั่ง WHERE ... ซึ่งช่วยเพิ่มประสิทธิภาพการทำงาน" จุดดี. "หลังจากนั้นเฉพาะเงื่อนไข WHERE ที่จะใช้เงื่อนไขตัวกรอง" แล้วประโยค HAVING ล่ะ?
James

@ James อ้างว่าโดย rafidheen นั้นผิด ดู 'เข้าร่วมการเพิ่มประสิทธิภาพ' ในคู่มือ นอกจากนี้ความคิดเห็นอื่น ๆ ของฉันในหน้านี้ (และ MikeSherrill'CatRecall''s.) คำอธิบาย "ตรรกะ" ดังกล่าวอธิบายถึงค่าผลลัพธ์ไม่ใช่วิธีการคำนวณจริง และพฤติกรรมการใช้งานดังกล่าวไม่รับประกันว่าจะไม่เปลี่ยนแปลง
philipxy

67

ไวยากรณ์ของ ANSI ที่เข้าร่วมโดยนัยนั้นเก่ากว่าไม่ค่อยชัดเจนและไม่แนะนำ

นอกจากนี้พีชคณิตเชิงสัมพันธ์ช่วยให้การแลกเปลี่ยนของภาคแสดงใน WHEREข้อและINNER JOINดังนั้นแม้จะINNER JOINสอบถามด้วยWHEREข้อสามารถมีภาคที่จัดเรียงใหม่โดยเพิ่มประสิทธิภาพ

ฉันแนะนำให้คุณเขียนข้อความค้นหาด้วยวิธีที่ง่ายที่สุด

บางครั้งสิ่งนี้รวมถึงการทำ INNER JOIN "ค่อนข้างไม่สมบูรณ์" และวางหลักเกณฑ์บางอย่างในWHEREเพียงเพื่อทำให้รายการของเกณฑ์การกรองง่ายขึ้น

ตัวอย่างเช่นแทนที่จะเป็น:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
    AND c.State = 'NY'
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
    AND a.Status = 1

เขียน:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
WHERE c.State = 'NY'
    AND a.Status = 1

แต่แน่นอนว่าขึ้นอยู่กับ


16
ตัวอย่างแรกของคุณทำให้สมองของฉันเจ็บมากขึ้นอย่างแน่นอน ไม่มีใครทำอย่างนั้นจริง ๆ ? ถ้าฉันพบใครสักคนที่ทำเช่นนั้นมันจะไม่เป็นไรสำหรับฉันที่จะเอาชนะเขาเหนือหัวหรือไม่?
allyourcode

3
ฉันค้นหาเกณฑ์ที่เหมาะสมที่สุด หากฉันเข้าร่วมกับตารางค้นหาสแนปชอตที่สอดคล้องกับกาลเวลา (และฉันไม่มีมุมมองหรือ UDF ที่บังคับใช้การเลือกวันที่ที่ถูกต้อง) ฉันจะรวมวันที่มีผลในการเข้าร่วมและไม่ใช่ใน WHERE เพราะน้อย มีแนวโน้มที่จะถูกลบโดยไม่ตั้งใจ
Cade Roux

14
@allyourcode: แม้ว่าจะยากที่จะเห็นการเข้าร่วมประเภทนี้ใน INNER JOIN มันเป็นเรื่องธรรมดามากสำหรับ RIGHT JOIN และ LEFT JOINS - การระบุรายละเอียดเพิ่มเติมใน predicate เข้าร่วมช่วยลดความจำเป็นในการค้นหาย่อยและป้องกันการรวมภายนอกของคุณโดยไม่ตั้งใจ เข้าสู่ INNER JOIN (แม้ว่าฉันยอมรับว่าสำหรับผู้เข้าร่วมภายในฉันมักจะใส่ c.State = 'NY' ไว้ในส่วนคำสั่ง WHERE)
Dave Markle

1
@ รหัสแน่นอนฉันทำอย่างนั้น! และฉันเห็นด้วยกับเคด .. ฉันอยากรู้ว่ามีเหตุผลที่เหมาะสมที่จะไม่
Arth

31

การเข้าร่วมโดยนัย (ซึ่งเป็นที่รู้จักกันในคำถามแรกของคุณ) ทำให้เกิดความสับสนอ่านยากและรักษาได้ยากขึ้นเมื่อคุณต้องการเริ่มเพิ่มตารางลงในแบบสอบถามของคุณ ลองนึกภาพการทำแบบสอบถามเดียวกันและประเภทของการเข้าร่วมในสี่หรือห้าตารางที่แตกต่างกัน ... มันเป็นฝันร้าย

การใช้การเข้าร่วมที่ชัดเจน (ตัวอย่างที่สองของคุณ) นั้นสามารถอ่านได้และง่ายต่อการดูแลรักษามากขึ้น


48
ฉันไม่เห็นด้วยมากกว่านี้ เข้าร่วมไวยากรณ์นั้นใช้คำฟุ่มเฟือยและยากต่อการจัดระเบียบ ฉันมีคำถามมากมายที่เข้าร่วม 5, 10, 15 ตารางโดยใช้ส่วนคำสั่ง WHERE รวมและสามารถอ่านได้อย่างสมบูรณ์ การเขียนแบบสอบถามใหม่โดยใช้ไวยากรณ์ของ JOIN จะทำให้เกิดปัญหาที่อ่านไม่ออก ซึ่งแสดงให้เห็นว่าไม่มีคำตอบที่ถูกต้องสำหรับคำถามนี้และมันขึ้นอยู่กับสิ่งที่คุณพอใจ
โนอาห์ Yetter

33
โนอาห์ฉันคิดว่าคุณอาจอยู่ในชนกลุ่มน้อยที่นี่
matt b

2
ฉันได้ +1 ด้านและโนอาห์ ฉันชอบความหลากหลาย :) ฉันสามารถดูได้ว่าโนอาห์มาจากไหน การรวมภายในไม่ได้เพิ่มอะไรใหม่ในภาษาและแน่นอนยิ่งขึ้น ในทางกลับกันมันสามารถทำให้สภาพ 'ที่' ของคุณสั้นลงมากซึ่งมักจะหมายความว่าอ่านง่ายกว่า
allyourcode

5
ฉันจะสมมติว่า DBMS ที่มีสติจะแปลแบบสอบถามทั้งสองเป็นแผนปฏิบัติการเดียวกัน อย่างไรก็ตามในความเป็นจริงแต่ละ DBMS จะแตกต่างกันและวิธีเดียวที่จะทราบได้อย่างแน่นอนคือการตรวจสอบแผนการดำเนินการ (เช่นคุณจะต้องทดสอบด้วยตัวเอง)
matt b

เป็นจริงหรือไม่ตามที่ @rafidheen แนะนำในคำตอบอื่น (คำสั่งที่มีลำดับของการดำเนินการ SQL อย่างละเอียด) ซึ่ง JOIN จะถูกกรองทีละครั้งช่วยลดขนาดของ opertations เข้าร่วมเมื่อเปรียบเทียบกับการรวม cartesian เต็มรูปแบบของตาราง 3 ตัวหรือมากกว่า WHERE ตัวกรองถูกนำไปใช้ย้อนหลังหรือไม่ ถ้าเป็นเช่นนั้นขอแนะนำให้ JOIN เสนอการปรับปรุงประสิทธิภาพ (รวมถึงข้อดีของการรวมซ้าย / ขวาเช่นเดียวกับการหาคำตอบอื่น)
James

26

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

นอกจากนี้สำหรับการบำรุงรักษาหากคุณมีการเข้าร่วมไขว้ในไวยากรณ์เก่าผู้ดูแลจะทราบได้อย่างไรว่าคุณมีหนึ่ง (มีสถานการณ์ที่จำเป็นต้องใช้การรวมข้าม) หรือหากเป็นอุบัติเหตุที่ควรได้รับการแก้ไข

ให้ฉันชี้ไปที่คำถามนี้เพื่อดูว่าทำไมไวยากรณ์โดยนัยไม่ดีถ้าคุณใช้การรวมซ้าย Sybase * = ถึง Ansi Standard ที่มีตารางด้านนอก 2 แบบสำหรับตารางด้านในเดียวกัน

บวก (พูดจาโผงผางส่วนบุคคลที่นี่) มาตรฐานการใช้การรวมอย่างชัดเจนมีอายุมากกว่า 20 ปีซึ่งหมายความว่าไวยากรณ์การเข้าร่วมโดยนัยได้ล้าสมัยในช่วง 20 ปีที่ผ่านมา คุณจะเขียนรหัสแอปพลิเคชันโดยใช้ไวยากรณ์ที่ล้าสมัยไปแล้ว 20 ปีหรือไม่ ทำไมคุณต้องการเขียนรหัสฐานข้อมูลนั่นคืออะไร?


3
@HLGEM: แม้ว่าฉันจะเห็นด้วยอย่างชัดเจนว่าการเข้าร่วมที่ชัดเจนนั้นดีกว่า แต่ก็มีหลายกรณีที่คุณเพียงแค่ต้องใช้ไวยากรณ์เก่า ตัวอย่างโลกแห่งความจริง: ANSI JOIN เข้าสู่ Oracle เฉพาะในรุ่น 9i ซึ่งเปิดตัวในปี 2544 และจนกระทั่งเมื่อปีที่แล้ว (16 ปีจากช่วงเวลาที่เผยแพร่มาตรฐาน) ฉันต้องสนับสนุนการติดตั้ง 8i ซึ่งเรามี เพื่อปล่อยการอัปเดตที่สำคัญ ฉันไม่ต้องการบำรุงรักษาชุดอัปเดตสองชุดดังนั้นเราจึงพัฒนาและทดสอบการอัปเดตกับฐานข้อมูลทั้งหมดรวมถึง 8i ซึ่งหมายความว่าเราไม่สามารถใช้ ANSI JOIN ได้
Quassnoi

+1 จุดที่น่าสนใจเมื่อคุณชี้ให้เห็นว่า sintax ที่ไม่มี INNER JOIN มีแนวโน้มที่จะเกิดข้อผิดพลาดมากกว่า ฉันสับสนเกี่ยวกับประโยคสุดท้ายของคุณเมื่อคุณพูดว่า "... มาตรฐานที่ใช้ตัวเชื่อมอย่างชัดเจนคืออายุ 17 ปี" ดังนั้นคุณจึงแนะนำให้ใช้คำหลัก INNER JOIN หรือไม่
Marco Demaio

1
@Marco Demaio ใช่ใช้ INNER JOIN หรือ JOIN เสมอ (ทั้งสองนี้เหมือนกัน) หรือ LEFT JOIN หรือ RIGHT JOIN หรือ CROSS JOIN และไม่เคยใช้เครื่องหมายคอมม่าโดยปริยาย
HLGEM

2
"ทำไมคุณต้องการเขียนรหัสฐานข้อมูลที่อายุ [20 ปี]" - ฉันสังเกตเห็นว่าคุณเขียน SQL โดยใช้HAVINGซึ่งเป็น 'ล้าสมัย' ตั้งแต่ SQL เริ่มสนับสนุนตารางที่ได้รับ ฉันยังสังเกตเห็นว่าคุณไม่ได้ใช้NATURAL JOINแม้ว่าฉันจะโต้แย้งว่ามันทำให้INNER JOIN'ล้าสมัย' ใช่คุณมีเหตุผลของคุณ (ไม่จำเป็นต้องระบุอีกครั้งที่นี่!) จุดของฉันคือผู้ที่ชอบใช้ไวยากรณ์เก่ามีเหตุผลเช่นกันและอายุสัมพัทธ์ของไวยากรณ์นั้นน้อยถ้าความเกี่ยวข้องใด ๆ
oneday เมื่อ

1
ที่ยังอยู่ในมาตรฐาน (แสดงให้ฉันเห็นว่ามันไม่ได้อยู่ที่ไหน) ดังนั้นไม่มีอะไรล้าสมัยอย่างเห็นได้ชัด นอกจากนี้ "มากกว่าการแก้ไขเข้าร่วม" แสดงให้เห็นว่าฉันนักพัฒนาที่ควรจะเก็บไว้ห่างจาก DBMSs โดยทั่วไปให้ห่างไกลออกไป
Jürgen A. Erhard

12

พวกเขามีความหมายที่มนุษย์สามารถอ่านได้แตกต่างกัน

อย่างไรก็ตามขึ้นอยู่กับเครื่องมือเพิ่มประสิทธิภาพคิวรีอาจมีความหมายเหมือนกันกับเครื่อง

คุณควรอ่านโค้ดทุกครั้ง

กล่าวคือหากนี่คือความสัมพันธ์ในตัวให้ใช้การเข้าร่วมที่ชัดเจน หากคุณกำลังจับคู่กับข้อมูลที่เกี่ยวข้องอย่างอ่อนแอให้ใช้คำสั่ง where


11

มาตรฐาน SQL: 2003 เปลี่ยนกฎที่มีความสำคัญมาก่อนดังนั้นคำสั่ง JOIN จึงมีความสำคัญเหนือกว่าการเข้าร่วม "จุลภาค" สิ่งนี้สามารถเปลี่ยนผลลัพธ์ของแบบสอบถามของคุณได้จริงขึ้นอยู่กับวิธีการตั้งค่า สิ่งนี้ทำให้เกิดปัญหาบางอย่างสำหรับบางคนเมื่อ MySQL 5.0.12 เปลี่ยนไปใช้เป็นมาตรฐาน

ดังนั้นในตัวอย่างของคุณแบบสอบถามของคุณจะทำงานเหมือนเดิม แต่ถ้าคุณเพิ่มตารางที่สาม: SELECT ... จาก table1, table2 เข้าร่วม table3 ON ... WHERE ...

ก่อน MySQL 5.0.12, table1 และ table2 จะเข้าร่วมก่อนจากนั้น table3 ตอนนี้ (5.0.12 ขึ้นไป), table2 และ table3 เข้าร่วมก่อนจากนั้น table1 มันไม่ได้เปลี่ยนผลลัพธ์เสมอไป แต่สามารถทำได้และคุณอาจไม่รู้ด้วยซ้ำ

ฉันไม่เคยใช้ไวยากรณ์ "จุลภาค" อีกต่อไปโดยเลือกตัวอย่างที่สองของคุณ สามารถอ่านได้มากขึ้นแล้วเงื่อนไขการเข้าร่วมอยู่กับการเข้าร่วมไม่ได้แยกออกเป็นส่วนข้อความค้นหาแยกต่างหาก


SQL มาตรฐานไม่เปลี่ยนแปลง MySQL ผิดและตอนนี้ถูกต้อง ดูคู่มือ MySQL
philipxy

4

ฉันรู้ว่าคุณกำลังพูดถึง MySQL แต่อย่างไรก็ตาม: ใน Oracle 9 การรวมที่ชัดเจนและการรวมโดยนัยจะสร้างแผนการดำเนินการที่แตกต่างกัน AFAIK ที่ได้รับการแก้ไขใน Oracle 10+: ไม่มีความแตกต่างอีกต่อไป


1

ไวยากรณ์การเข้าร่วม ANSI สามารถพกพาได้อย่างแน่นอนยิ่งขึ้น

ฉันกำลังจะทำการอัพเกรด Microsoft SQL Server และฉันยังจะพูดถึงว่าไม่สนับสนุนไวยากรณ์ = * และ * = สำหรับการรวมภายนอกใน SQL Server (โดยไม่มีโหมดความเข้ากันได้) สำหรับเซิร์ฟเวอร์ SQL sql และใหม่กว่า


2
แม้ใน SQL Server 2000 = และ =อาจให้ผลลัพธ์ที่ผิดและไม่ควรใช้
HLGEM

2
*=และ=*ไม่เคยเป็น ANSI และไม่เคยเป็นสัญกรณ์ที่ดี นั่นเป็นเหตุผลที่ถูกต้องบน - สำหรับเชื่อม outer ในกรณีที่ไม่มี subselects (ซึ่งได้รับการเพิ่มในเวลาเดียวกันดังนั้นพวกเขาจึงไม่จำเป็นต้องใช้จริงในการ CROSS & INNER ร่วม.)
philipxy

1

หากคุณมักจะเขียนโปรแกรมขั้นตอนการจัดเก็บแบบไดนามิกคุณจะตกหลุมรักกับตัวอย่างที่สองของคุณ (โดยใช้ที่) หากคุณมีพารามิเตอร์อินพุตที่หลากหลายและ morph ยุ่งมากนั่นเป็นวิธีเดียว ไม่เช่นนั้นทั้งคู่จะใช้แผนคิวรีเดียวกันดังนั้นจึงไม่มีความแตกต่างที่ชัดเจนในการค้นหาแบบคลาสสิก

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