ความแตกต่างระหว่างตัวซ้าย, ขวา, ด้านนอกและด้านในคืออะไร?


562

ฉันสงสัยว่าจะสร้างความแตกต่างให้กับการรวมเหล่านี้ได้อย่างไร


60
จากการเข้ารหัสสยองขวัญคำอธิบายภาพของ SQL ร่วม
SQLMenace

3
นอกจากนี้ยังขึ้นอยู่กับระดับความเข้าใจของคุณสำหรับบางคนเช่นคุณว่าบทความไม่ได้ทำอะไรเลย แต่สำหรับคนที่อาจไม่เข้าใจการเข้าร่วมเป็นที่ชัดเจนสวย
SQLMenace

6
นี่คือซ้ำซ้อนของstackoverflow.com/questions/419375/sql-join-differencesและไม่ต้องสงสัยเลยว่าคนอื่น ๆ ...
cletus

1
สิ่งนี้ช่วยฉันได้มาก ... วิธีที่ง่ายที่สุดคือสร้างตารางทดสอบและเล่นกับพวกเขา = P
daGrevis

คำตอบ:


797

ตัวอย่างง่าย ๆ : สมมติว่าคุณมีStudentsตารางและLockersตาราง ใน SQL ตารางแรกที่คุณระบุในการเข้าร่วมStudentsเป็นตารางซ้ายและตารางที่สองLockersคือตารางขวา

นักเรียนแต่ละคนสามารถได้รับมอบหมายให้ล็อกเกอร์ดังนั้นจึงมีLockerNumberคอลัมน์ในStudentตาราง อาจมีนักเรียนมากกว่าหนึ่งคนที่อยู่ในตู้เก็บของเดียว แต่โดยเฉพาะอย่างยิ่งในช่วงต้นปีการศึกษาคุณอาจมีนักเรียนที่เข้ามาโดยไม่มีตู้เก็บของและตู้เก็บของบางตู้ที่ไม่มีนักเรียนมอบหมาย

สำหรับตัวอย่างนี้สมมติว่าคุณมีนักเรียน 100 คนซึ่ง 70 คนมีตู้เก็บของ คุณมีตู้เก็บของทั้งหมด50 ตู้ซึ่ง 40 ตู้มีนักเรียนอย่างน้อย 1 คนและตู้เก็บของ 10 ตู้ไม่มีนักเรียน

INNER JOINเทียบเท่ากับ " แสดงให้ฉันเห็นว่านักเรียนทุกคนมีตู้เก็บของ "
นักเรียนที่ไม่มีตู้เก็บของหรือตู้เก็บของที่ไม่มีนักเรียนหายไป
ส่งคืน 70 แถว

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

เข้าร่วมด้านขวาจะ " แสดงตู้เก็บของทั้งหมดและนักเรียนที่ได้รับมอบหมายถ้ามี "
สิ่งนี้สามารถใช้เพื่อระบุตู้เก็บของที่ไม่มีนักเรียนที่ได้รับมอบหมายหรือตู้เก็บของที่มีนักเรียนมากเกินไป
ส่งคืน 80 แถว (รายชื่อนักเรียน 70 คนในตู้เก็บของ 40 ตู้พร้อมตู้เก็บของ 10 ตู้ที่ไม่มีนักเรียน)

การเข้าร่วมด้านนอกเต็มรูปแบบจะไร้สาระและอาจไม่ได้ใช้งานมากนัก
บางอย่างเช่น " แสดงให้ฉันเห็นนักเรียนทุกคนและตู้เก็บของทั้งหมดและตรงกับพวกเขาในที่ที่คุณสามารถ "
ส่งคืน 110 แถว (นักเรียนทั้งหมด 100 คนรวมถึงนักเรียนที่ไม่มีตู้เก็บของรวมทั้งตู้เก็บของ 10 ตู้ที่ไม่มีนักเรียน)

ข้ามเข้าร่วมก็ค่อนข้างโง่ในสถานการณ์นี้
มันไม่ได้ใช้lockernumberฟิลด์ที่เชื่อมโยงในตารางนักเรียนดังนั้นโดยพื้นฐานแล้วคุณจะได้รายชื่อยักษ์ใหญ่ของการจับคู่แบบจับคู่ระหว่างนักเรียนกับล็อกเกอร์ที่เป็นไปได้ไม่ว่าจะมีอยู่จริงหรือไม่ก็ตาม
ส่งคืน 5,000 แถว (100 นักเรียน x ตู้เก็บของ 50) อาจเป็นประโยชน์ (ที่มีการกรอง) เป็นจุดเริ่มต้นเพื่อจับคู่นักเรียนใหม่กับตู้เก็บที่ว่างเปล่า


12
การใช้ตัวอย่างของคุณการเข้าร่วม CROSS จะมีประโยชน์ในฐานะจุดเริ่มต้นสำหรับการสร้างการกำหนดตู้เก็บของ: เริ่มต้นด้วยชุดค่าผสมที่เป็นไปได้ทั้งหมดแล้วใช้เกณฑ์อื่น ๆ เพื่อกรองผลลัพธ์จากรายการ
Joel Coehoorn

1
คำตอบที่ดี ฉันเชื่อว่า Cross Join มักใช้ในการสร้างข้อมูลการทดสอบจากไม่กี่แถวเมื่อคุณต้องการบันทึกจำนวนมาก
Eli

6
การเข้าร่วมด้านนอกเต็มรูปแบบจะมีประโยชน์เมื่อค้นหาข้อมูลเด็กกำพร้าหรือเมื่อเปรียบเทียบรุ่นชุดข้อมูลเดียวกันต่าง ๆ
Lara Dougan

3
Cross เข้าร่วมผลิตภัณฑ์คาร์ทีเซียน aka
JavaRocky

3
ฉันคิดว่าวิธีการเริ่มต้นค้นหาของคุณมีผลต่อผลลัพธ์ของประเภทการเข้าร่วม ยกตัวอย่างเช่นจะส่งผลให้ผลลัพธ์ที่แตกต่างกว่าSELECT * FROM students RIGHT OUTER JOIN lockers... SELECT * FROM lockers RIGHT OUTER JOIN students...คำตอบที่ดี แต่ชอบที่จะเห็นมันอัปเดตด้วยSQLคำค้นหาที่สมบูรณ์
jbmilgrom

141

การเข้าร่วมมีสามประเภท:

  • INNERเข้าร่วมเปรียบเทียบสองตารางและส่งกลับผลลัพธ์เฉพาะการแข่งขันที่มีอยู่ ระเบียนจากตารางที่ 1 จะทำซ้ำเมื่อตรงกับผลลัพธ์หลายรายการในอันดับที่ 2 การเข้าร่วมภายในมีแนวโน้มที่จะทำให้ชุดผลลัพธ์มีขนาดเล็กลง แต่เนื่องจากการบันทึกสามารถทำซ้ำได้จึงไม่รับประกัน
  • CROSSเข้าร่วมเปรียบเทียบสองตารางและกลับมารวมกันเป็นไปได้ของแถวจากทั้งสองตาราง คุณสามารถได้รับผลลัพธ์จำนวนมากจากการเข้าร่วมประเภทนี้ที่อาจไม่มีความหมายดังนั้นควรใช้ด้วยความระมัดระวัง
  • OUTERเข้าร่วมเปรียบเทียบสองตารางและส่งกลับข้อมูลเมื่อมีการแข่งขันหรือค่า NULL เช่นเดียวกับการเข้าร่วมของ INNER การทำเช่นนี้จะทำซ้ำแถวในตารางหนึ่งเมื่อตรงกับหลายระเบียนในตารางอื่น ตัวเชื่อมภายนอกมีแนวโน้มที่จะทำให้ชุดผลลัพธ์มีขนาดใหญ่ขึ้นเนื่องจากพวกเขาจะไม่ลบระเบียนใด ๆ ออกจากชุดด้วยตนเอง คุณต้องมีคุณสมบัติเข้าร่วม OUTER เพื่อกำหนดเวลาและสถานที่ที่จะเพิ่มค่า NULL:
    • LEFT หมายถึงเก็บระเบียนทั้งหมดจากตารางที่ 1 ไม่ว่าอะไรและแทรกค่า NULL เมื่อตารางที่ 2 ไม่ตรงกัน
    • RIGHT หมายถึงสิ่งที่ตรงกันข้าม: เก็บบันทึกทั้งหมดจากตารางที่ 2 ไม่ว่าอะไรและแทรกค่า NULL เมื่อเขาตารางที่ 1 ไม่ตรงกัน
    • FULL หมายถึงเก็บระเบียนทั้งหมดจากทั้งสองตารางและแทรกค่า NULL ในตารางใดก็ได้หากไม่มีการจับคู่

บ่อยครั้งที่คุณเห็นว่าOUTERคำหลักจะถูกตัดออกจากไวยากรณ์ แต่จะเป็นเพียง "LEFT JOIN", "RIGHT JOIN" หรือ "FULL JOIN" สิ่งนี้ทำได้เนื่องจากการเข้าร่วมภายในและ CROSS นั้นไม่มีความหมายใด ๆ เกี่ยวกับซ้ายขวาหรือเต็มดังนั้นสิ่งเหล่านี้เพียงพอสำหรับตัวเองที่จะบ่งบอกว่าการเข้าร่วม OUTER นั้นไม่น่าสงสัยเลย

นี่คือตัวอย่างของเวลาที่คุณอาจต้องการใช้แต่ละประเภท:

  • INNER: คุณต้องการส่งคืนระเบียนทั้งหมดจากตาราง "ใบแจ้งหนี้" พร้อมกับ "ใบแจ้งหนี้" ที่เกี่ยวข้อง สมมติว่าใบแจ้งหนี้ที่ถูกต้องทุกใบจะมีอย่างน้อยหนึ่งบรรทัด
  • OUTER: คุณต้องการส่งคืนระเบียน "InvoiceLines" ทั้งหมดสำหรับใบแจ้งหนี้เฉพาะพร้อมด้วยระเบียน "InventoryItem" ที่เกี่ยวข้อง นี่เป็นธุรกิจที่ขายบริการเช่นกันที่ InvoiceLines ทั้งหมดจะมี IventoryItem
  • CROSS: คุณมีตารางตัวเลขที่มี 10 แถวแต่ละค่าที่เก็บไว้คือ '0' ถึง '9' คุณต้องการสร้างตารางช่วงวันที่เพื่อเข้าร่วมเพื่อให้คุณได้รับหนึ่งระเบียนสำหรับแต่ละวันภายในช่วง ด้วยการเข้าร่วม CROSS ตารางนี้กับตัวเองซ้ำ ๆ คุณสามารถสร้างจำนวนเต็มต่อเนื่องได้มากเท่าที่คุณต้องการ (เมื่อคุณเริ่มต้นที่ 10 ต่อ 1 พลังงานแต่ละการรวมจะเพิ่ม 1 ไปยังเลขชี้กำลัง) จากนั้นใช้ฟังก์ชัน DATEADD () เพื่อเพิ่มค่าเหล่านั้นในวันที่ฐานของคุณสำหรับช่วง

1
ดี ฉันจะเพิ่มเฉพาะเมื่อคุณเขียน 'เข้าร่วม' เท่านั้นมันหมายถึงเข้าร่วมภายใน
matpop

47

มีเพียง 4 ชนิด:

  1. Inner join : ประเภทที่พบมากที่สุด แถวเอาต์พุตถูกสร้างขึ้นสำหรับแถวอินพุตทุกคู่ที่ตรงกับเงื่อนไขการรวม
  2. การรวมภายนอกด้านซ้าย : เช่นเดียวกับการรวมภายในยกเว้นว่าหากมีแถวใดที่ไม่พบแถวที่ตรงกันในตารางด้านขวาแถวจะแสดงผลลัพธ์ที่มีค่าจากตารางด้านซ้ายโดยมีNULLสำหรับแต่ละแถวค่าในตารางด้านขวา ซึ่งหมายความว่าทุกแถวจากตารางด้านซ้ายจะปรากฏอย่างน้อยหนึ่งครั้งในผลลัพธ์
  3. การรวมภายนอกด้านขวา : เหมือนกับการเข้าร่วมด้านนอกด้านซ้ายยกเว้นกับบทบาทของตารางที่ตรงกันข้าม
  4. การรวมภายนอกเต็มรูปแบบ : การรวมกันของการรวมภายนอกด้านซ้ายและขวา ทุกแถวจากตารางทั้งสองจะปรากฏในผลลัพธ์อย่างน้อยหนึ่งครั้ง

"การรวมข้าม" หรือ "การรวมคาร์ทีเซียน" เป็นเพียงการรวมภายในที่ไม่ได้ระบุเงื่อนไขการเข้าร่วมทำให้มีการส่งออกแถวคู่ทั้งหมด

ขอบคุณ RusselH ที่ชี้ให้เห็นว่าการเข้าร่วมเต็มรูปแบบซึ่งฉันได้ข้ามไป


1
สิ่งที่เกี่ยวกับการรวมภายนอกเต็มและข้ามเข้าร่วม (ผลิตภัณฑ์คาร์ทีเซียน)
SQLMenace

เต็มจริง ๆ แล้วเทียบเท่ากับการรวมภายนอกสองครั้ง
RussellH

25
FULL เป็นสิ่งที่คุณได้รับเมื่อคุณพลาดการเข้าร่วมภายในแล้วคุณถามคำถามที่นี่ "ทำไมฉันถึงได้รับ N ^ 2 แถวแทนที่จะเป็น N" จากนั้นทุกคนจะได้รับครอสที่คุณ
พอลทอมบลิ

24

SQL JOINS แตกต่าง:

ง่ายมากที่จะจำ:

INNER JOIN แสดงเฉพาะระเบียนทั่วไปของทั้งสองตาราง

OUTER JOIN เนื้อหาทั้งหมดของตารางทั้งสองถูกรวมเข้าด้วยกันไม่ว่าจะตรงกันหรือไม่ก็ตาม

LEFT JOINเหมือนกับLEFT OUTER JOIN- (เลือกระเบียนจากตารางแรก (ซ้ายสุด) ที่มีระเบียนตารางที่ตรงกันที่ตรงกัน)

RIGHT JOINเหมือนกับRIGHT OUTER JOIN- (เลือกระเบียนจากตารางที่สอง (ขวาสุด) ที่มีระเบียนตรงกันกับตารางด้านซ้าย)

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


มีวิธีที่ถูกต้องและเกี่ยวข้องในการติดป้ายวงกลมไดอะแกรมของ Venn แต่นี่ไม่ใช่วิธีนี้ วงกลมไม่ใช่ตารางป้อนข้อมูล และแถวผลลัพธ์ไม่ใช่แถวป้อนข้อมูลดังนั้นคำอธิบายของคุณจึงไม่ถูกต้อง สิ่งนี้ไม่ชัดเจน - คุณไม่ต้องอธิบายว่า "ใช้ร่วมกันทั้งคู่", "จับคู่", "ผสาน"
philipxy

9

ตรวจสอบการเข้าร่วม (SQL) บน Wikipedia

  • การรวมภายใน - กำหนดสองตารางการเข้าร่วมภายในส่งคืนแถวทั้งหมดที่มีอยู่ในทั้งสองตาราง
  • การเข้าร่วมด้านซ้าย / ขวา (ด้านนอก) - ให้สองตารางคืนแถวทั้งหมดที่มีอยู่ในตารางด้านซ้ายหรือขวาของการเข้าร่วมของคุณรวมทั้งแถวจากอีกด้านหนึ่งจะถูกส่งกลับเมื่อเข้าร่วมประโยคเป็นการจับคู่หรือ null จะถูกส่งกลับ คอลัมน์เหล่านั้น

  • เต็มภายนอก - รับสองตารางส่งคืนแถวทั้งหมดและจะคืนค่า null เมื่อคอลัมน์ด้านซ้ายหรือขวาไม่อยู่ที่นั่น

  • Cross Joins - การเข้าร่วมคาร์ทีเซียนและอาจเป็นอันตรายหากไม่ได้ใช้อย่างระมัดระวัง


6

การทำให้มองเห็นได้ชัดเจนขึ้นอาจช่วยได้ ตัวอย่างหนึ่ง:

ตารางที่ 1:

ID_STUDENT STUDENT_NAME

1               Raony
2               Diogo
3               Eduardo
4               Luiz

ตารางที่ 2:

ID_STUDENT LOCKER

3               l1
4               l2
5               l3

สิ่งที่ฉันได้รับเมื่อฉัน:

-Inner join of Table 1 and Table 2: 

    - Inner join returns both tables merged only when the key 
      (ID_STUDENT) exists in both tables

    ID_STUDENT       STUDENT_NAME      LOCKER   

        3               Eduardo          l1
        4               Luiz             l2

-Left join of Table 1 and Table 2:

    - Left join merges both tables with all records form table 1, in 
      other words, there might be non-populated fields from table 2

    ID_ESTUDANTE    NOME_ESTUDANTE     LOCKER   

        1               Raony            -
        2               Diogo            -
        3               Eduardo          l1
        4               Luiz             l2

-Right join of table 1 and table 2:

    - Right join merges both tables with all records from table 2, in 
      other words, there might be non-populated fields from table 1

    ID_STUDENT        STUDENT_NAME     LOCKER   

        3               Eduardo          l1
        4               Luiz             l2
        5               -                l3

-Outter join of table 1 and table 2:

    - Returns all records from both tables, in other words, there
      might be non-populated fields either from table 1 or 2.

    ID_STUDENT        STUDENT_NAME     LOCKER   
        1               Raony            -
        2               Diogo            -
        3               Eduardo          l1
        4               Luiz             l2
        5               -                l3

4

LEFT JOINและRIGHT JOINเป็นประเภทของOUTER JOINs

INNER JOIN เป็นค่าเริ่มต้น - แถวจากตารางทั้งสองจะต้องตรงกับเงื่อนไขการเข้าร่วม


5
ฉันไม่อยากจะเชื่อเลยว่าคำตอบนี้มี upvotes มากมายและในเวลาเดียวกันมันก็ไม่สมบูรณ์
nbro

ฉันคิดว่ามันเป็นคำตอบที่ดีกว่าสำหรับคำถามเดิม
RussellH

3

Inner join : แสดงเฉพาะแถวเมื่อมีข้อมูลจากทั้งสองตาราง

ด้านนอกเข้าร่วม : (ซ้าย / ขวา) : แสดงผลทั้งหมดจากซ้าย / ขวาตารางที่มีแถวจับคู่ ( s ) ถ้ามันมีอยู่หรือไม่


2

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

ให้บอกว่า tableA มีสองคอลัมน์ A และ B และ tableB มีสามคอลัมน์ C และ D หากเราใช้ cross join มันจะสร้างแถวที่ไม่มีความหมายมาก จากนั้นเราต้องจับคู่โดยใช้คีย์หลักเพื่อรับข้อมูลจริง

ซ้าย:มันจะส่งคืนระเบียนทั้งหมดจากตารางด้านซ้ายและระเบียนที่ตรงกันจากตารางด้านขวา

ขวา:มันจะกลับมาตรงกันข้ามกับ Left join มันจะส่งกลับระเบียนทั้งหมดจากตารางด้านขวาและระเบียนที่ตรงกันจากตารางด้านซ้าย

Inner:มันเหมือนกับสี่แยก มันจะส่งกลับเฉพาะระเบียนที่ตรงกันจากทั้งสองตาราง

ด้านนอก:และนี่เป็นเหมือนสหภาพ มันจะส่งคืนระเบียนที่มีอยู่ทั้งหมดจากทั้งสองตาราง

บางครั้งเราไม่ต้องการข้อมูลทั้งหมดและเราควรต้องการข้อมูลหรือบันทึกทั่วไปเท่านั้น เราสามารถรับได้โดยใช้วิธีการเข้าร่วมเหล่านี้ โปรดจำไว้ว่าการเข้าร่วมทางซ้ายและขวาเป็นการเข้าร่วมด้านนอกด้วย

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

ขอบคุณ

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