อะไรคือความแตกต่างระหว่าง INNER JOIN และ OUTER JOIN


35

ฉันยังใหม่กับ SQL และต้องการทราบว่าอะไรคือความแตกต่างระหว่างสองJOINประเภทนี้?

SELECT * 
FROM user u
INNER JOIN telephone t ON t.user_id = u.id

SELECT * 
FROM user u
LEFT OUTER JOIN telephone t ON t.user_id = u.id

เมื่อใดที่ฉันควรใช้รายการใดรายการหนึ่ง


6
สิ่งนี้เหมาะกับคำถาม DBA หรือไม่ นี่ดูเหมือนคำถามที่เข้ารหัสได้มากกว่าสำหรับฉัน
BlackICE

1
@ ปิดความคิดของคุณเกี่ยวกับMeta
Sathyajith Bhat

@David จากนั้น VtC หากคุณคิดว่ามันผิดสำหรับเว็บไซต์ เราสามารถเปิดใหม่ได้ตลอดเวลา
jcolebrand

3
ฉันคิดว่านี่เป็นคำถามที่ดีมากและเหมาะสมมากสำหรับไซต์
datagod

ความต้องการนี้จะถูกย้ายออกจาก DBA ยกเว้น noob แขน DBA ขึ้นเพื่อปรับแต่งประสิทธิภาพ DB: P
AmDB

คำตอบ:


32
  • การรวมภายในจะเลือกเฉพาะระเบียนที่คีย์การเข้าร่วมอยู่ในทั้งสองตารางที่ระบุ
  • การรวมภายนอกด้านซ้ายจะเลือกระเบียนทั้งหมดจากตารางแรกและระเบียนใด ๆ ในตารางที่สองที่ตรงกับคีย์ที่เข้าร่วม
  • การรวมภายนอกด้านขวาจะเลือกระเบียนทั้งหมดจากตารางที่สองและระเบียนใด ๆ ในตารางแรกที่ตรงกับคีย์ที่เข้าร่วม

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

ในตัวอย่างที่สองของคุณคุณจะส่งคืนรายชื่อผู้ใช้ทั้งหมดรวมทั้งบันทึกโทรศัพท์หากมี (ถ้าไม่มีให้คุณจะได้รับNULLค่าโทรศัพท์)


13

ทุกครั้งที่มีคนถามคำถามนี้มีคำตอบคือ: http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html

หวังว่ามันจะช่วยให้คุณเข้าใจ


3
ฉันทำงานร่วมกับ 20 ปีและไดอะแกรมเหล่านั้นดูเหมือนจะทำให้ฉันสับสน
โฮแกน

3
ฉันกับ @Hogan - แผนผังไดอะแกรมไม่ใช่คำอธิบายที่ดีที่สุดสำหรับสิ่งนี้ .. ตารางที่แสดงว่าชุดค่าผสมใดที่จะถูกส่งคืนอาจจะดีกว่า
Joe

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

@jamesryan ที่ไม่เป็นความจริงพวกเขาไม่สัมพันธ์กันอย่างสมบูรณ์แบบการเข้าร่วมนั้นคล้ายกับชุดของคาร์ทีเซียนไม่ใช่ทางแยกและรวมกันแผนภาพ venn อะนาล็อกจะทำงานได้ก็ต่อเมื่อคุณเข้าร่วมคีย์ที่ไม่ซ้ำกัน ด้านผลิตภัณฑ์คาร์ทีเซียน
จะ

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

8

การรวมภายในจะส่งคืนแถวที่สามารถรวมกันตามเกณฑ์การเข้าร่วม
การรวมภายนอกจะส่งกลับแถวเหล่านี้และทั้งหมด ...
   ... จากตารางแรกสำหรับการเข้าร่วมด้านซ้าย
   ... จากตารางที่สองสำหรับการเข้าร่วมที่ถูกต้อง
   ... จากทั้งสองตารางสำหรับการเข้าร่วมเต็มรูปแบบ

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

สำหรับข้อมูลเพิ่มเติมโปรดดูที่คำถามนี้ใน StackOverflow


7

หากคุณมี 2 ตารางเหมือนด้านล่าง:

Table1 :   A1    B1          Table2  :    B2     C2 
           -     -                        -      -
           1     2                        1      1
           2     4                        2      4
           3     5                        5      2

ถ้าคุณใช้ Inner Join คุณจะได้รับ:

 A1     B1     B2      C2  
 -      -      -       -
 1      2      2       4
 3      5      5       2

ถ้าคุณใช้ Full Outer Join คุณจะได้รับ:

 A1     B1     B2      C2  
 -      -      -       -
 1      2      2       4
 3      5      5       2
 2      4    NULL     NULL
NULL   NULL    1       1

หากคุณใช้ Left Outer Join คุณจะได้รับ:

 A1     B1     B2      C2  
 -      -      -       -
 1      2      2       4
 3      5      5       2
 2      4    NULL     NULL

6

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

SELECT SNO , PNO 
FROM   SP 
UNION  
SELECT SNO , 'nil' AS PNO 
FROM   S 
WHERE  SNO NOT IN ( SELECT SNO FROM SP )

อีกวิธีหนึ่งสามารถรับผลลัพธ์เดียวกันได้โดยใช้ตัวดำเนินการรวมภายนอกของ SQL ร่วมกับCOALESCEที่นี่:

SELECT SNO , COALESCE ( PNO , 'nil' ) AS PNO 
FROM ( S NATURAL LEFT OUTER JOIN SP ) AS TEMP

หมายเหตุเกี่ยวกับ Outer Join (4.6) ใน "SQL และทฤษฎีเชิงสัมพันธ์: วิธีการเขียนรหัส SQL ที่ถูกต้อง" โดย CJ Date


5

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

สมมติว่า table1 มีคีย์หลักและคู่ข้อมูลต่อไปนี้: (1, a), (2, b), (3, c)

สมมติว่า table2 มีคีย์หลักและคู่ข้อมูลต่อไปนี้: (1, สนุก), (3, สามารถ), (4, เกิดขึ้น)

ดังนั้นการรวมภายในของ table1 ถึง table2 บนคีย์หลักจะให้ผลลัพธ์สามเท่าดังนี้ (โดยใช้คีย์หลักแรกก่อนรายการแรกของตารางที่สองที่สองและที่สองของตารางที่สองรายการที่สอง): (1, a, fun), ( 3, c, สามารถ)

การเข้าร่วมด้านนอกด้านซ้ายของ table1 ถึง table2 บนคีย์หลักจะให้ผลลัพธ์สามเท่าดังนี้ (รูปแบบเดียวกับด้านบน): (1, a, สนุก), (2, b, NULL), (3, c, can)

การรวมด้านนอกขวาของ table1 ถึง table2 บนคีย์หลักจะให้ผลลัพธ์สามเท่าดังนี้ (รูปแบบเดียวกับด้านบน): (1, a, สนุก), (3, c, can), (4, NULL, เกิดขึ้น)

ฉันหวังว่านี่จะอธิบายแนวคิดได้ดี


4

ให้ฉันพยายามอธิบายให้เข้าใจง่ายขึ้นอีกหน่อย

การรวมภายในแสดงผู้ใช้ที่มีโทรศัพท์อย่างน้อยหนึ่งรายการพร้อมกับหมายเลขโทรศัพท์

ด้านนอกซ้ายเข้าร่วมแสดงรายการ 'ผู้ใช้' เหล่านั้นซึ่งไม่มีโทรศัพท์


4

เมื่อคุณถามว่าจะใช้เมื่อไรนี่คือสถานการณ์ที่มีคิวรี - เลือกว่าจะใช้อะไรขึ้นอยู่กับข้อกำหนด

ข้อมูล:

ผู้ใช้งานตารางมี 10 รายการ Table Phoneno มี 6 บันทึก (ด้วยความสัมพันธ์แบบ 1: 1 หมายถึงรายการใน PhoneNo จะอ้างอิงเพียงหนึ่งรายการในผู้ใช้และมีเพียงหนึ่งรายการใน PhoneNo สามารถอ้างอิงรายการที่กำหนดในผู้ใช้)

ข้อกำหนดที่ 1: แสดงหมายเลขโทรศัพท์ของผู้ใช้ทั้งหมด ไม่ต้องสนใจผู้ใช้ที่ไม่มีหมายเลขโทรศัพท์

ค้นหา:

SELECT u.uid, u.name, p.phonno 
  FROM user u 
INNER JOIN phones p ON p.uid = u.uid

ผลลัพธ์: แสดงผู้ใช้ 6 คนที่มีหมายเลขโทรศัพท์

ข้อกำหนดที่ 2: แสดงหมายเลขโทรศัพท์ของผู้ใช้ทั้งหมด หากผู้ใช้ไม่มีหน้าจอโทรศัพท์ 'N / A' (ไม่พร้อมใช้งาน)

ค้นหา:

SELECT u.uid, u.name, ifnull(p.phonno,'N/A') 
  FROM user u 
LEFT OUTER JOIN phones p ON p.uid = u.uid

ผล:

แสดงระเบียนทั้งหมด 10 รายการ

หมายเหตุ: ifnull เป็นไวยากรณ์ MySql เพื่อแปลงค่า Null ฉันใช้ฟังก์ชั่นนี้เพื่อทำให้ db engine แสดง 'N / A' เมื่อโทรศัพท์ไม่มีค่า ค้นหาฟังก์ชั่นที่เหมาะสมหากคุณใช้ DBMS อื่น ๆ ใน SQL Server คุณต้องใช้CASEคำสั่ง

ฉันหวังว่านี่จะช่วยได้.

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