อะไรคือความแตกต่างระหว่าง“ เข้าร่วมภายใน” และ“ เข้าร่วมนอก”?


4671

นอกจากนี้ยังทำอย่างไรLEFT JOIN, RIGHT JOINและFULL JOINพอดีมีอะไรบ้าง?


63
จากคำตอบและความคิดเห็นและการอ้างอิงของพวกเขาด้านล่างเพียงคนเดียวเท่านั้นที่อธิบายถึงวิธีการที่ Venn diagrams แสดงตัวดำเนินการ: พื้นที่จุดตัดวงกลมแสดงชุดของแถวใน A JOIN B พื้นที่ที่ไม่ซ้ำกันของแต่ละวงกลมแสดงถึงชุดของแถวที่คุณได้รับ แถวของตารางที่ไม่ได้มีส่วนร่วมใน A เข้าร่วม B และเพิ่มคอลัมน์ที่ไม่ซ้ำกันในตารางอื่นทั้งหมดตั้งค่าเป็น NULL (และส่วนใหญ่ให้การติดต่อปลอมที่คลุมเครือของวงกลมกับ A และ B. )
philipxy

1
กระโดดจากคำตอบตามทฤษฎีด้านล่างเพื่อการใช้งานในโลกแห่งความเป็นจริง: ฉันมักจะทำงานกับข้อมูลการทดลองใช้มาตรฐานในการออกแบบโปรเซสเซอร์ บ่อยครั้งที่ฉันต้องการเปรียบเทียบผลลัพธ์ระหว่างตัวเลือกฮาร์ดแวร์ 2 ตัวหรือมากกว่า เข้าร่วมภายในหมายความว่าฉันเห็นเฉพาะมาตรฐานที่ทำงานได้สำเร็จในการทดลองทั้งหมด OUTER JOIN หมายความว่าฉันสามารถดูการทดลองทั้งหมดรวมถึงการทดสอบที่ล้มเหลวในการกำหนดค่าบางอย่าง มันเป็นสิ่งสำคัญที่จะเห็นความล้มเหลวในการทดลองเช่นนี้เช่นเดียวกับความสำเร็จ พอสิ่งสำคัญที่ผมเขียน PerlSQL ที่จะได้รับ OUTER JOIN เมื่อ RDBMSes หลายขาดมัน
Krazy Glew

4
มีคำตอบมากมายอยู่แล้ว แต่ฉันไม่ได้เห็นการสอนนี้ที่กล่าวถึง ถ้าคุณรู้ว่า Venn diagrams, นี่เป็นแบบฝึกหัดที่ยอดเยี่ยม: blog.codinghorror.com/a-visual-explanation-of-sql-joins สำหรับฉันมันกระชับพอที่จะอ่านได้อย่างรวดเร็ว แต่ยังเข้าใจแนวคิดทั้งหมดและใช้งานได้ทั้งหมด กรณีดีมาก หากคุณไม่ทราบว่า Venn diagrams คืออะไร - เรียนรู้พวกเขาใช้เวลา 5-10 นาทีในการทำเช่นนั้นและจะช่วยเหลือเมื่อใดก็ตามที่คุณต้องการเห็นภาพการทำงานกับชุดและการจัดการการดำเนินงานในชุด
DanteTheSmith

14
@DanteTheSmith ไม่นั่นเป็นปัญหาจากไดอะแกรมที่นี่ ดูความคิดเห็นของฉันด้านบนอีกคำถาม & ด้านล่างว่าโพสต์บล็อกมาก: "เจฟฟ์ repudiates บล็อกของเขาในไม่กี่หน้าลงความคิดเห็น" เวนไดอะแกรมแสดงองค์ประกอบเป็นชุด เพียงแค่พยายามระบุให้แน่ชัดว่าเซตคืออะไรและองค์ประกอบใดบ้างในไดอะแกรมเหล่านี้ ชุดไม่ใช่ตารางและองค์ประกอบไม่ใช่แถวของพวกเขา นอกจากนี้ยังมีสองตารางใด ๆ ที่สามารถเข้าร่วมได้ดังนั้น PKs & FKs จึงไม่เกี่ยวข้อง ปลอมทั้งหมด คุณกำลังทำในสิ่งที่คนอื่น ๆ หลายพันคนทำ - ได้รับความประทับใจที่คลุมเครือคุณ (ผิด) สมมติว่าเหมาะสม
philipxy

3
Chris ฉันขอแนะนำให้คุณอ่านบทความนี้: forwarddatascience.com/ ...... และลองเปลี่ยนคำตอบที่คุณยอมรับ (อาจจะเป็นแบบที่มีค่าหัว) เป็นคำตอบที่ไม่ได้ใช้ Venn diagrams คำตอบที่ได้รับการยอมรับในปัจจุบันนั้นทำให้ผู้คนเข้าใจผิดมากเกินไป ฉันขอให้คุณทำเช่นนี้เพื่อประโยชน์ของชุมชนของเราและคุณภาพของฐานความรู้ของเรา
Colm Bhandal

คำตอบ:


6113

สมมติว่าคุณกำลังเข้าร่วมในคอลัมน์ที่ไม่มีรายการซ้ำซึ่งเป็นกรณีที่พบบ่อยมาก:

  • การรวมภายในของ A และ B ให้ผลลัพธ์ของ A intersect B นั่นคือส่วนด้านในของจุดตัดVenn diagram

  • การรวมภายนอกของ A และ B ให้ผลลัพธ์ของ A union B เช่นส่วนนอกของสหภาพ Venn diagram

ตัวอย่าง

สมมติว่าคุณมีสองตารางโดยแต่ละคอลัมน์จะมีหนึ่งคอลัมน์และข้อมูลดังต่อไปนี้:

A    B
-    -
1    3
2    4
3    5
4    6

โปรดทราบว่า (1,2) เป็นเอกลักษณ์ของ A, (3,4) เป็นเรื่องธรรมดาและ (5,6) เป็นเอกลักษณ์ของ B

เข้าร่วมภายใน

การรวมภายในโดยใช้แบบสอบถามที่เทียบเท่าอย่างใดอย่างหนึ่งจะให้จุดตัดของตารางสองตารางนั่นคือแถวสองแถวที่พวกเขามีเหมือนกัน

select * from a INNER JOIN b on a.a = b.b;
select a.*, b.*  from a,b where a.a = b.b;

a | b
--+--
3 | 3
4 | 4

ด้านนอกซ้ายเข้าร่วม

การรวมภายนอกด้านซ้ายจะให้แถวทั้งหมดใน A บวกกับแถวทั่วไปใน B

select * from a LEFT OUTER JOIN b on a.a = b.b;
select a.*, b.*  from a,b where a.a = b.b(+);

a |  b
--+-----
1 | null
2 | null
3 |    3
4 |    4

เข้าร่วมด้านนอกขวา

การรวมภายนอกด้านขวาจะให้แถวทั้งหมดใน B บวกกับแถวทั่วไปใน A

select * from a RIGHT OUTER JOIN b on a.a = b.b;
select a.*, b.*  from a,b where a.a(+) = b.b;

a    |  b
-----+----
3    |  3
4    |  4
null |  5
null |  6

การรวมภายนอกเต็มรูปแบบ

การเข้าร่วมด้านนอกเต็มรูปแบบจะให้การรวม A และ B แก่คุณเช่นแถวทั้งหมดใน A และแถวทั้งหมดใน B หากบางสิ่งใน A ไม่มีตัวเลขที่สอดคล้องกันใน B ดังนั้น B ส่วนนั้นจะเป็นโมฆะ ในทางกลับกัน

select * from a FULL OUTER JOIN b on a.a = b.b;

 a   |  b
-----+-----
   1 | null
   2 | null
   3 |    3
   4 |    4
null |    6
null |    5

41
มันเป็นการดีที่จะเพิ่มตัวอย่างโดยเพิ่มแถวอื่นในตาราง B ด้วยค่า 4 ซึ่งจะแสดงว่าการรวมภายในไม่จำเป็นต้องเท่ากับจำนวนแถว
softveda

472
คำอธิบายที่ดีเยี่ยมอย่างไรก็ตามข้อความนี้: การรวมภายนอกของ A และ B ให้ผลลัพธ์ของ A union B นั่นคือส่วนนอกของสหภาพแผนภาพเวนน์ ไม่ได้ใช้ถ้อยคำอย่างถูกต้อง การเข้าร่วมด้านนอกจะให้ผลลัพธ์ของ A intersect B นอกเหนือจากอย่างใดอย่างหนึ่งต่อไปนี้: ทั้งหมดของ A (การรวมซ้าย), ทั้งหมด B (การรวมขวา) หรือ A และทั้งหมดของ B และการรวมทั้งหมด (เต็มการเข้าร่วม) เฉพาะสถานการณ์สุดท้ายนี้เท่านั้นจริงๆสหภาพแรงงานบียังเป็นคำอธิบายที่เป็นลายลักษณ์อักษรอย่างดี
โทมัส

11
ฉันถูกต้องหรือไม่ที่การเข้าร่วมเต็มรูปแบบเป็นนามแฝงของการเข้าร่วมเต็มด้านนอกและการเข้าร่วมด้านซ้ายเป็นนามแฝงของการเข้าร่วมด้านนอกด้านซ้าย?
Damian

3
ใช่คำอธิบายที่ดีและยอดเยี่ยม แต่ทำไมในคอลัมน์ b ค่าจึงไม่เป็นไปตามลำดับ นั่นคือ 6,5 ไม่ใช่ 5,6
Ameer

7
@Ameer ขอบคุณ เข้าร่วมไม่รับประกันการสั่งซื้อคุณจะต้องเพิ่มคำสั่ง ORDER BY
Mark Harrison

733

แผนภาพเวนน์ไม่ได้ทำเพื่อฉันจริงๆ

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

ไม่มีสิ่งใดมาทดแทนความเข้าใจการประมวลผลเชิงตรรกะและมันค่อนข้างตรงไปตรงมาที่จะเข้าใจต่อไป

  1. ลองนึกภาพการเข้าร่วมข้าม
  2. ประเมินonอนุประโยคกับแถวทั้งหมดจากขั้นตอนที่ 1 รักษาตำแหน่งที่เพรดิเคตประเมินไปtrue
  3. (สำหรับการรวมภายนอกเท่านั้น) เพิ่มกลับในแถวด้านนอกใด ๆ ที่หายไปในขั้นตอนที่ 2

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

ฉันจะเริ่มต้นด้วยรุ่นเคลื่อนไหวของด้านนอกเต็มรูปแบบเข้าร่วม คำอธิบายเพิ่มเติมดังนี้

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


คำอธิบาย

ตารางที่มา

ป้อนคำอธิบายลิงก์ที่นี่

เริ่มแรกด้วยCROSS JOIN(ผลิตภัณฑ์คาร์ทีเซียน AKA) สิ่งนี้ไม่มีส่วนONคำสั่งและจะคืนค่าทุกชุดของแถวจากทั้งสองตาราง

เลือก A.Colour, B.Colour จาก A ข้ามเข้าร่วม

ป้อนคำอธิบายลิงก์ที่นี่

การรวมภายในและภายนอกมีส่วนคำสั่ง "ON"

  • เข้าร่วม Inner. ประเมินเงื่อนไขในส่วนคำสั่ง "ON" สำหรับทุกแถวในผลการเข้าร่วมไขว้ ถ้า true ส่งคืนแถวที่เข้าร่วม ไม่เช่นนั้นก็ทิ้งไป
  • เข้าร่วม Outer Left เหมือนกับการรวมภายในแล้วสำหรับแถวใด ๆ ในตารางด้านซ้ายที่ไม่ตรงกับผลลัพธ์ใด ๆ ที่มีค่า NULL สำหรับคอลัมน์ตารางด้านขวา
  • เข้าร่วม Outer ขวา เช่นเดียวกับการรวมภายในแล้วสำหรับแถวใด ๆ ในตารางด้านขวาที่ไม่ตรงกับผลลัพธ์ใด ๆ ที่มีค่า NULL สำหรับคอลัมน์ตารางด้านซ้าย
  • เต็มนอกเข้าร่วม เช่นเดียวกับการรวมด้านในจากนั้นเก็บรักษาแถวที่ไม่ได้จับคู่ซ้ายไว้เช่นเดียวกับการเข้าร่วมด้านนอกด้านซ้ายและแถวที่ไม่ได้รับการจับคู่ด้านขวาตามการรวมภายนอกด้านขวา

ตัวอย่างบางส่วน

เลือก A.Colour, B.Colour จากภายในเข้าร่วม B บน A.Colour = B.Colour

ข้างต้นคือการเข้าร่วม equi คลาสสิก

เข้าร่วม Inner

เวอร์ชันภาพเคลื่อนไหว

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

เลือก A.Colour, B.Colour จากภายในเข้าร่วม B บน A.Colour NOT IN ('Green', 'Blue')

เงื่อนไขการรวมภายในไม่จำเป็นต้องเป็นเงื่อนไขความเสมอภาคและไม่จำเป็นต้องอ้างอิงคอลัมน์จากทั้งสอง (หรือแม้แต่) ของตาราง การประเมินผลA.Colour NOT IN ('Green','Blue')ตอบแทนจากการเข้าร่วม cross แต่ละแถว

ด้านใน 2

เลือก A.Colour, B.Colour จากภายในเข้าร่วม B ใน 1 = 1

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

เลือก A.Colour, B.Colour จากด้านนอกซ้ายเข้าร่วม B บน A.Colour = B.Colour

Outer Joins จะถูกประเมินอย่างมีเหตุผลในลักษณะเดียวกับ Inner joins ยกเว้นว่าถ้าแถวจากตารางด้านซ้าย (สำหรับการรวมด้านซ้าย) ไม่ได้เข้าร่วมกับแถวใด ๆ จากตารางด้านขวาเลยจะถูกเก็บไว้ในผลลัพธ์ด้วยNULLค่าสำหรับ คอลัมน์ทางขวามือ

LOJ

เลือก A.Colour, B.Colour จากด้านซ้ายด้านนอกเข้าร่วม B บน A.Colour = B.Colour ที่ B.Colour ว่างเปล่า

นี้ก็จะ จำกัด B.Colour IS NULLผลก่อนหน้านี้เพียงกลับแถวที่ Bในกรณีนี้โดยเฉพาะอย่างยิ่งเหล่านี้จะเป็นแถวที่ถูกเก็บรักษาไว้เป็นพวกเขาไม่มีการแข่งขันในตารางด้านขวามือและแบบสอบถามส่งกลับแถวสีแดงเดียวไม่ตรงกับในตาราง สิ่งนี้เรียกว่าการต่อต้านกึ่งเข้าร่วม

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

loj เป็นโมฆะ

เลือก A.Colour, B.Colour จากขวานอกเข้าร่วม B ใน A.Colour = B.Colour

การรวมด้านนอกด้านขวาทำหน้าที่คล้ายกับการรวมด้านนอกด้านซ้ายยกเว้นพวกเขารักษาแถวที่ไม่ตรงกันจากตารางด้านขวาและ null จะขยายคอลัมน์ซ้ายมือ

Roj

เลือก A.Colour, B.Colour จากทั้งหมดนอกเข้าร่วม B ใน A.Colour = B.Colour

การรวมภายนอกเต็มรูปแบบเป็นการรวมการทำงานของการรวมซ้ายและขวาและรักษาแถวที่ไม่ตรงกันจากทั้งซ้ายและตารางขวา

FOJ

เลือก A.Colour, B.Colour จากทั้งหมดนอกเข้าร่วม B บน 1 = 0

ไม่มีแถวในการเข้าร่วมไขว้ตรงกับเพ1=0รดิเคต แถวทั้งหมดจากทั้งสองด้านได้รับการเก็บรักษาไว้โดยใช้กฎการเข้าร่วมด้านนอกปกติด้วย NULL ในคอลัมน์จากตารางที่อยู่อีกด้านหนึ่ง

FOJ 2

เลือก COALESCE (A.Colour, B.Colour) เป็นสีจากทั้งหมดเข้าร่วม B บน 1 = 0

ด้วยการแก้ไขเล็กน้อยในแบบสอบถามก่อนหน้านี้หนึ่งสามารถจำลองหนึ่งUNION ALLในสองตาราง

ยูเนี่ยนทั้งหมด

เลือก A.Colour, B.Colour จากด้านนอกซ้ายเข้าร่วม B บน A.Colour = B.Colour ที่ B.Colour = 'Green'

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

LOJ

... จากนั้นประโยค "Where" จะทำงาน NULL= 'Green'ไม่ได้ประเมินว่าเป็นจริงดังนั้นแถวที่เก็บรักษาไว้โดยการรวมภายนอกจะถูกยกเลิก (พร้อมด้วยสีน้ำเงิน) การแปลงการเข้าร่วมกลับเป็นแบบภายในได้อย่างมีประสิทธิภาพ

LOJtoInner

หากความตั้งใจที่จะรวมเฉพาะแถวจาก B ที่สีเป็นสีเขียวและแถวทั้งหมดจาก A โดยไม่คำนึงถึงไวยากรณ์ที่ถูกต้องจะเป็น

เลือก A.Colour, B.Colour จากด้านนอกซ้ายเข้าร่วม B บน A.Colour = B.Colour และ B.Colour = 'Green'

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

ซอ Fiddle

ดูตัวอย่างเหล่านี้ทำงานอยู่ที่ SQLFiddle.com


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

22
@OldPro แผนภาพ Venn นั้นใช้ได้ตราบใดที่ฉันไป แต่พวกเขาก็นิ่งเงียบว่าจะเป็นตัวแทนของ cross cross หรือแยกความแตกต่างของการเข้าร่วม predicate เช่น equi join จากอีกรูปแบบหนึ่ง แบบจำลองทางจิตของการประเมินภาคแสดงการเข้าร่วมในแต่ละแถวของผลการเข้าร่วมไขว้แล้วเพิ่มกลับในแถวที่ไม่มีใครเทียบถ้าการรวมภายนอกและสุดท้ายประเมินว่าที่ไหนดีกว่าสำหรับฉัน
Martin Smith

18
แผนภาพเวนน์นั้นดีสำหรับการเป็นตัวแทนของสหภาพแรงงานและทางแยกและความแตกต่าง แต่ไม่รวม พวกเขามีค่าการศึกษาเล็กน้อยสำหรับการเข้าร่วมที่ง่ายมากเช่นการรวมที่เงื่อนไขการเข้าร่วมอยู่ในคอลัมน์ที่ไม่ซ้ำกัน
ypercubeᵀᴹ

12
@Arth - ไม่ผิดหรอก SQL Fiddle sqlfiddle.com/#!3/9eecb7db59d16c80417c72d1/5155นี่เป็นสิ่งที่แผนภาพ Venn ไม่สามารถอธิบายได้
Martin Smith

7
@ มาร์ตินด้วยว้าวฉันเห็นด้วยฉันผิดทั้งหมด! คุ้นเคยกับการทำงานแบบหนึ่งต่อหลายคน .. ขอบคุณสำหรับการแก้ไข
Arth

188

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

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

Inner Join: - Inner join สร้างตารางผลลัพธ์ใหม่โดยรวมค่าคอลัมน์ของสองตาราง (พนักงานและตำแหน่ง ) ตามการเข้าร่วมของภาคแสดง เคียวรีจะเปรียบเทียบแต่ละแถวของพนักงานกับแต่ละตำแหน่งของแถวเพื่อค้นหาคู่ของแถวทั้งหมดที่ตรงตามข้อกำหนดการเข้าร่วม เมื่อเพรดิเคตเข้าร่วมเป็นที่พอใจโดยการจับคู่ค่าที่ไม่ใช่ค่า NULL ค่าคอลัมน์สำหรับแต่ละคู่ของแถวพนักงานและตำแหน่งที่ตรงกันจะรวมกันเป็นแถวผลลัพธ์ นี่คือลักษณะที่ SQL สำหรับการเข้าร่วมภายใน:

select  * from employee inner join location on employee.empID = location.empID
OR
select  * from employee, location where employee.empID = location.empID

ตอนนี้นี่คือผลลัพธ์ของการรัน SQL ที่มีลักษณะดังนี้: ป้อนคำอธิบายรูปภาพที่นี่

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

การเข้าร่วมด้านนอกด้านซ้าย: - ผลลัพธ์ของการเข้าร่วมด้านนอกด้านซ้าย (หรือเพียงแค่การเข้าร่วมด้านซ้าย) สำหรับตารางพนักงานและตำแหน่งจะมีระเบียนทั้งหมดของตาราง "ซ้าย" (พนักงาน ) เสมอแม้ว่าเงื่อนไขการเข้าร่วมจะไม่พบระเบียนที่ตรงกัน ตาราง "ถูกต้อง" (ที่อยู่ ) นี่คือลักษณะที่ SQL สำหรับการรวมภายนอกด้านซ้ายจะมีลักษณะโดยใช้ตารางด้านบน:

select  * from employee left outer join location on employee.empID = location.empID;
//Use of outer keyword is optional

ตอนนี้นี่คือผลลัพธ์ของการรัน SQL นี้ที่มีลักษณะดังนี้: ป้อนคำอธิบายรูปภาพที่นี่

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

select * from employee right outer join location  on employee.empID = location.empID;
//Use of outer keyword is optional

เมื่อใช้ตารางด้านบนเราสามารถแสดงให้เห็นว่าชุดผลลัพธ์ของการรวมภายนอกด้านขวามีลักษณะอย่างไร:

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

Full Outer Joins: - Full Outer Join หรือ Full Join คือการเก็บข้อมูลที่ไม่เข้าคู่กันโดยการรวมแถวที่ไม่มีการจับคู่ในผลลัพธ์ของการเข้าร่วมให้ใช้การรวมภายนอกเต็มรูปแบบ มันรวมแถวทั้งหมดจากตารางทั้งสองโดยไม่คำนึงว่าตารางอื่นมีค่าที่ตรงกันหรือไม่

แหล่งที่มาของภาพ

คู่มืออ้างอิง MySQL 8.0 - เข้าร่วมไวยากรณ์

การดำเนินงานของ Oracle เข้าร่วม


3
คำตอบที่ดีที่สุดจนถึงตอนนี้ไวยากรณ์ทางเลือก - นั่นคือสิ่งที่ฉันกำลังมองหาขอบคุณ!
Joey

1
ไดอะแกรมของ Venn นั้นมี mislabelled ดูความคิดเห็นของฉันเกี่ยวกับคำถาม & คำตอบอื่น ๆ ภาษานี้ส่วนใหญ่ไม่ดี ตัวอย่างเช่น: "เมื่อสมการเข้าร่วมเป็นที่พอใจโดยการจับคู่ค่าที่ไม่ใช่ค่า NULL ค่าคอลัมน์สำหรับแต่ละคู่ของแถวของพนักงานและตำแหน่งที่ตรงกันจะรวมกันเป็นแถวผลลัพธ์" ไม่ไม่ใช่ "เมื่อสมการเข้าร่วมเป็นที่พอใจโดยการจับคู่ค่าที่ไม่ใช่ NULL" ค่าในแถวไม่สำคัญนอกเหนือจากว่าเงื่อนไขโดยรวมเป็นจริงหรือเท็จ ค่าบางค่าอาจเป็นค่า NULL สำหรับเงื่อนไขจริง
philipxy

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

@ColmBhandal: ลบ Venn diagrams
ajitksharma

กรุณาใช้ข้อความที่ไม่ images / การเชื่อมโยงสำหรับข้อความ - รวมทั้งตารางและ ERDs ใช้รูปภาพสำหรับสิ่งที่ไม่สามารถแสดงเป็นข้อความหรือเพื่อเพิ่มข้อความได้ ไม่สามารถค้นหาหรือตัดและวางภาพ รวมคำอธิบาย / แป้น & คำอธิบายพร้อมรูปภาพ
philipxy

133

เข้าร่วม Inner

ดึงแถวที่ตรงกันเท่านั้นนั่นคือ, A intersect B.

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

SELECT *
FROM dbo.Students S
INNER JOIN dbo.Advisors A
    ON S.Advisor_ID = A.Advisor_ID

เข้าร่วม Outer Left

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

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

SELECT *
FROM dbo.Students S
LEFT JOIN dbo.Advisors A
    ON S.Advisor_ID = A.Advisor_ID

เต็มนอกเข้าร่วม

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

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

SELECT *
FROM dbo.Students S
FULL JOIN dbo.Advisors A
    ON S.Advisor_ID = A.Advisor_ID

อ้างอิง


14
ชื่อเครื่องมือคืออะไร? ฉันคิดว่ามันน่าสนใจเพราะมันแสดงจำนวนแถวและเวนน์ไดอะแกรม
Grijesh Chauhan

2
@GrijeshChauhan ใช่ แต่คุณสามารถพยายามที่จะเรียกมันใช้ไวน์
Tushar Gupta - curioustushar

2
Ohh! ใช่ฉัน .. ฉันใช้ SQLyog กำลังใช้ไวน์ .. นอกจากนี้ยังมีPlayOnLinux ด้วย
Grijesh Chauhan

1
ข้อความของคุณไม่ชัดเจน & ผิด "การจับคู่แถวเท่านั้น" คือแถวจากการรวมข้ามของ A & B & สิ่งที่ดึงมา (การรวมภายใน B) ไม่ใช่การตัด B แต่ (การรวม B ซ้าย) การตัดกัน (การรวม B ขวา) แถว "ที่เลือก" ไม่ได้มาจาก A & B พวกเขามาจาก A cross join B & จากค่าที่ขยายเป็นศูนย์จาก A & B
philipxy

@ TusharGupta-curioustushar คุณควรรวม "ตารางที่ใช้สำหรับตัวอย่าง SQL"
Manuel Jordan

112

ในคำง่าย ๆ :

การรวมภายในดึงข้อมูลแถวที่ตรงกันเท่านั้น

ในขณะที่การรวมภายนอกดึงแถวที่ตรงกันจากตารางหนึ่งและแถวทั้งหมดในตารางอื่น .... ผลลัพธ์ขึ้นอยู่กับว่าคุณกำลังใช้อะไรอยู่:

  • ซ้าย : แถวที่ตรงกันในตารางด้านขวาและแถวทั้งหมดในตารางด้านซ้าย

  • ขวา : แถวที่ตรงกันในตารางด้านซ้ายและแถวทั้งหมดในตารางด้านขวาหรือ

  • เต็ม : แถวทั้งหมดในตารางทั้งหมด มันไม่สำคัญว่าจะมีการแข่งขันหรือไม่


1
@ ไม่ใช่ไม่ใช่คำตอบนี้ตอบ แต่ INNER JOIN เป็นจุดตัดและ FULL OUTER JOIN เป็น UNION ที่สอดคล้องกันหากชุดซ้าย / ขวา / วงกลมประกอบด้วยแถวของ (ตามลำดับ) เข้าร่วมซ้ายและขวา PS คำตอบนี้ไม่ชัดเจนเกี่ยวกับแถวในอินพุตและเอาต์พุต มันสับสน "ในตารางซ้าย / ขวา" กับ "มีส่วนซ้าย / ขวาในซ้าย / ขวา" และใช้ "จับคู่แถว" กับ "ทั้งหมด" เพื่อหมายถึงแถวที่ขยายโดยแถวจากตารางอื่นเทียบกับ null
philipxy

104

การรวมภายในแสดงเฉพาะแถวหากมีระเบียนที่ตรงกันในอีกด้าน (ขวา) ของการเข้าร่วม

การรวมภายนอก (ซ้าย) แสดงแถวสำหรับแต่ละเร็กคอร์ดทางด้านซ้ายแม้ว่าจะไม่มีแถวที่ตรงกันในอีกด้าน (ขวา) ของการเข้าร่วม หากไม่มีแถวที่ตรงกันคอลัมน์สำหรับด้านอื่น ๆ (ขวา) จะแสดงค่า NULL


82

Inner joins จำเป็นต้องมีระเบียนที่มี ID ที่เกี่ยวข้องอยู่ในตารางที่เข้าร่วม

การรวมภายนอกจะส่งคืนระเบียนทางด้านซ้ายแม้ว่าจะไม่มีสิ่งใดอยู่ทางด้านขวา

ตัวอย่างเช่นคุณมีคำสั่งซื้อและตาราง OrderDetails พวกเขาเกี่ยวข้องโดย "OrderID"

สั่งซื้อ

  • OrderID
  • ชื่อลูกค้า

OrderDetails

  • OrderDetailID
  • OrderID
  • ชื่อผลิตภัณฑ์
  • จำนวน
  • ราคา

การร้องขอ

SELECT Orders.OrderID, Orders.CustomerName
  FROM Orders 
 INNER JOIN OrderDetails
    ON Orders.OrderID = OrderDetails.OrderID

จะส่งคืนคำสั่งซื้อที่มีบางสิ่งบางอย่างในตาราง OrderDetails เท่านั้น

หากคุณเปลี่ยนเป็น OUTER LEFT JOIN

SELECT Orders.OrderID, Orders.CustomerName
  FROM Orders 
  LEFT JOIN OrderDetails
    ON Orders.OrderID = OrderDetails.OrderID

จากนั้นจะส่งคืนระเบียนจากตารางคำสั่งซื้อแม้ว่าจะไม่มีระเบียน OrderDetails ก็ตาม

คุณสามารถใช้นี้เพื่อหาคำสั่งซื้อที่ไม่ได้มี OrderDetails ใด ๆ WHERE OrderDetails.OrderID IS NULLที่แสดงให้เห็นคำสั่งกำพร้าที่เป็นไปได้โดยการเพิ่มข้อที่เหมือน


1
ฉันขอขอบคุณตัวอย่างที่เรียบง่ายและสมจริง ผมเปลี่ยนการร้องขอเช่นSELECT c.id, c.status, cd.name, c.parent_id, cd.description, c.image FROM categories c, categories_description cd WHERE c.id = cd.categories_id AND c.status = 1 AND cd.language_id = 2 ORDER BY c.parent_id ASCการSELECT c.id, c.status, cd.name, c.parent_id, cd.description, c.image FROM categories c INNER JOIN categories_description cd ON c.id = cd.categories_id WHERE c.status = 1 AND cd.language_id = 2 ORDER BY c.parent_id ASC(MySQL) กับความสำเร็จ ผมไม่แน่ใจว่าเกี่ยวกับเงื่อนไขเพิ่มเติมพวกเขาผสมกัน ...
PhiLho

68

ในคำง่าย ๆ :

การเข้าร่วมภายใน -> รับเฉพาะระเบียนทั่วไปจากตารางหลักและตารางลูกซึ่งคีย์หลักของตารางหลักตรงกับรหัสหลักในตารางย่อย

เข้าร่วมซ้าย ->

รหัสเทียม

1.Take All records from left Table
2.for(each record in right table,) {
    if(Records from left & right table matching on primary & foreign key){
       use their values as it is as result of join at the right side for 2nd table.
    } else {
       put value NULL values in that particular record as result of join at the right side for 2nd table.
    }
  }

เข้าร่วมขวา : ตรงข้ามกับซ้ายเข้าร่วม ใส่ชื่อของตารางใน LEFT JOIN ทางด้านขวาใน Right join คุณจะได้ผลลัพธ์เช่นเดียวกับ LEFT JOIN

ด้านนอกเข้าร่วม : No matter whatแสดงระเบียนทั้งหมดในตารางทั้งสอง ถ้าระเบียนในตารางด้านซ้ายไม่ตรงกับตารางด้านขวาตามคีย์หลักต่างประเทศให้ใช้ค่า NULL เนื่องจากการเข้าร่วม

ตัวอย่าง:

ตัวอย่าง

ให้สมมติว่าตอนนี้สำหรับ 2 ตาราง

1.employees , 2.phone_numbers_employees

employees : id , name 

phone_numbers_employees : id , phone_num , emp_id   

ที่นี่ตารางพนักงานคือตารางหลัก phone_numbers_employees เป็นตารางลูก (มีemp_idคีย์ต่างประเทศที่เชื่อมต่อemployee.idกับตารางลูก)

เข้าร่วมชั้นใน

ใช้บันทึก 2 ตารางเท่านั้นถ้าคีย์หลักของตารางพนักงาน (ID) ที่ตรงกับคีย์ต่างประเทศของ phone_numbers_employees ตารางเด็ก (emp_id)

ดังนั้นแบบสอบถามจะเป็น:

SELECT e.id , e.name , p.phone_num FROM employees AS e INNER JOIN phone_numbers_employees AS p ON e.id = p.emp_id;

ที่นี่ใช้เฉพาะแถวที่จับคู่บนคีย์หลัก = foreign key ตามที่อธิบายไว้ข้างต้นนี่ไม่ใช่แถวที่ตรงกันในคีย์หลัก = foreign key จะถูกข้ามไปเนื่องจากการเข้าร่วม

เข้าร่วมซ้าย :

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

SELECT e.id , e.name , p.phone_num FROM employees AS e LEFT JOIN phone_numbers_employees AS p ON e.id = p.emp_id;

การรวมภายนอก :

SELECT e.id , e.name , p.phone_num FROM employees AS e OUTER JOIN phone_numbers_employees AS p ON e.id = p.emp_id;

ตามลำดับดูเหมือนว่า:

แผนภาพ


4
ผลลัพธ์ไม่มีอะไรต้องทำ (ทำต่อกัน) ด้วยคีย์หลัก / เฉพาะ / ตัวเลือกและคีย์ต่างประเทศ baviour สามารถและควรจะอธิบายโดยไม่ต้องอ้างอิงถึงพวกเขา คำนวณการเข้าร่วมไขว้จากนั้นแถวที่ไม่ตรงกับเงื่อนไข ON จะถูกกรองออก นอกจากนี้สำหรับการรวมแถวนอกตัวกรอง / แถวที่ไม่ตรงกันจะถูกขยายโดย NULLs (ต่อซ้าย / ขวา / เต็มและรวมอยู่ด้วย
philipxy

สมมติฐานที่ว่าการเชื่อม SQL เข้าด้วยกันมักจะตรงกับคีย์หลัก / ต่างประเทศนำไปสู่การใช้ Venn diagrams ในทางที่ผิด โปรดแก้ไขคำตอบของคุณ
Colm Bhandal

58

คุณใช้INNER JOINเพื่อกลับแถวทั้งหมดจากตารางทั้งสองที่มีการแข่งขัน เช่นในตารางผลลัพธ์แถวและคอลัมน์ทั้งหมดจะมีค่า

ในOUTER JOINตารางผลลัพธ์อาจมีคอลัมน์ว่าง ด้านนอกเข้าร่วมอาจจะเป็นอย่างใดอย่างหนึ่งหรือLEFTRIGHT

LEFT OUTER JOIN ส่งกลับแถวทั้งหมดจากตารางแรกแม้ว่าจะไม่มีการจับคู่ในตารางที่สอง

RIGHT OUTER JOIN ส่งกลับแถวทั้งหมดจากตารางที่สองแม้ว่าจะไม่มีการจับคู่ในตารางแรก


56

นี่เป็นคำอธิบายที่ดีสำหรับการเข้าร่วม

นี่เป็นคำอธิบายไดอะแกรมที่ดีสำหรับการรวมทุกชนิด

แหล่งที่มา: http://ssiddique.info/understanding-sql-joins-in-easy-way.html


1
โพสต์นี้ไม่ได้อธิบายอย่างชัดเจนถึงวิธีการตีความแผนภาพนี้ ดูความคิดเห็นแรกในคำถาม & ความคิดเห็นอื่น ๆ ของฉันในหน้านี้
philipxy

54

INNER JOINต้องมีอย่างน้อยการแข่งขันในการเปรียบเทียบทั้งสองตาราง ตัวอย่างเช่นตาราง A และตาราง B ซึ่งแสดงถึง A ٨ B (A intersection B)

LEFT OUTER JOINและLEFT JOINเหมือนกัน มันให้ระเบียนทั้งหมดที่ตรงกันในทั้งตารางและความเป็นไปได้ทั้งหมดของตารางด้านซ้าย

ในทำนองเดียวกันRIGHT OUTER JOINและRIGHT JOINเหมือนกัน มันให้ระเบียนทั้งหมดที่ตรงกันในทั้งตารางและความเป็นไปได้ทั้งหมดของตารางด้านขวา

FULL JOINเป็นการรวมกันของLEFT OUTER JOINและRIGHT OUTER JOINไม่ซ้ำซ้อน


43

คำตอบคือในความหมายของแต่ละคนดังนั้นในผลลัพธ์

หมายเหตุ:
ในSQLiteไม่มีหรือRIGHT OUTER JOIN และยังอยู่ในไม่มีFULL OUTER JOIN
MySQLFULL OUTER JOIN

คำตอบของฉันอยู่บนพื้นฐานดังกล่าวข้างต้นหมายเหตุ

เมื่อคุณมีสองตารางดังนี้:

--[table1]               --[table2]
id | name                id | name
---+-------              ---+-------
1  | a1                  1  | a2
2  | b1                  3  | b2

CROSS JOIN / OUTER JOIN:
คุณสามารถมีข้อมูลในตารางทั้งหมดด้วยCROSS JOINหรือแค่,ดังนี้

SELECT * FROM table1, table2
--[OR]
SELECT * FROM table1 CROSS JOIN table2

--[Results:]
id | name | id | name 
---+------+----+------
1  | a1   | 1  | a2
1  | a1   | 3  | b2
2  | b1   | 1  | a2
2  | b1   | 3  | b2

เข้าร่วมภายใน:
เมื่อคุณต้องการเพิ่มตัวกรองไปยังผลลัพธ์ด้านบนตามความสัมพันธ์แบบที่table1.id = table2.idคุณสามารถใช้INNER JOIN:

SELECT * FROM table1, table2 WHERE table1.id = table2.id
--[OR]
SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.id

--[Results:]
id | name | id | name 
---+------+----+------
1  | a1   | 1  | a2

LEFT [OUTER] JOIN:
เมื่อคุณต้องการให้มีแถวทั้งหมดของหนึ่งตารางในผลลัพธ์ข้างต้น - ด้วยความสัมพันธ์เดียวกัน - คุณสามารถใช้LEFT JOIN:
(สำหรับRIGHT JOINเพียงเปลี่ยนสถานที่ของตาราง)

SELECT * FROM table1, table2 WHERE table1.id = table2.id 
UNION ALL
SELECT *, Null, Null FROM table1 WHERE Not table1.id In (SELECT id FROM table2)
--[OR]
SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id

--[Results:]
id | name | id   | name 
---+------+------+------
1  | a1   | 1    | a2
2  | b1   | Null | Null

เข้าร่วมเต็มรูปแบบ:
เมื่อคุณต้องการมีแถวทั้งหมดของตารางอื่น ๆ ในผลลัพธ์ของคุณคุณสามารถใช้FULL OUTER JOIN:

SELECT * FROM table1, table2 WHERE table1.id = table2.id
UNION ALL
SELECT *, Null, Null FROM table1 WHERE Not table1.id In (SELECT id FROM table2)
UNION ALL
SELECT Null, Null, * FROM table2 WHERE Not table2.id In (SELECT id FROM table1)
--[OR] (recommended for SQLite)
SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id
UNION ALL
SELECT * FROM table2 LEFT JOIN table1 ON table2.id = table1.id
WHERE table1.id IS NULL
--[OR]
SELECT * FROM table1 FULL OUTER JOIN table2 On table1.id = table2.id

--[Results:]
id   | name | id   | name 
-----+------+------+------
1    | a1   | 1    | a2
2    | b1   | Null | Null
Null | Null | 3    | b2

ดีตามความต้องการของคุณคุณเลือกแต่ละคนที่ครอบคลุมความต้องการของคุณ;)


คุณสามารถเพิ่มบันทึกย่อของคุณได้ว่าไม่มีfull outer joinใน MySQL เช่นกัน
potashin

35

เข้าร่วมภายใน

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

เข้าร่วม Outer

การเข้าร่วมด้านซ้ายพยายามค้นหาการจับคู่แถวจากตารางแรกไปยังแถวในตารางที่สอง หากไม่พบการจับคู่มันจะส่งคืนคอลัมน์จากตารางแรกและปล่อยให้คอลัมน์นั้นว่างจากตารางที่สอง (null)


28

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

  • INNER JOINเข้าร่วมโดยทั่วไปมากที่สุดสำหรับสองตารางหรือมากกว่า ส่งคืนข้อมูลที่ตรงกันทั้งบนตารางบนคีย์หลักและ forignkey ความสัมพันธ์
  • OUTER JOINเหมือนกันINNER JOINแต่มันยังรวมถึงNULLข้อมูลบน ResultSet
    • LEFT JOIN= INNER JOIN+ ข้อมูลที่ไม่ตรงกันของตารางด้านซ้ายที่Nullตรงกับตารางด้านขวา
    • RIGHT JOIN= INNER JOIN+ ข้อมูลที่ไม่ตรงกันของตารางด้านขวามีข้อมูลNullตรงกันบนตารางด้านซ้าย
    • FULL JOIN= INNER JOIN+ ข้อมูลที่ไม่ตรงกันในทั้งด้านขวาและซ้ายของตารางด้วยการNullจับคู่
  • Self join ไม่ใช่คำสำคัญใน SQL เมื่อตารางอ้างอิงข้อมูลในตัวเองรู้ว่าตนเองเข้าร่วม การใช้INNER JOINและOUTER JOINเราสามารถเขียนแบบสอบถามเข้าร่วมด้วยตนเอง

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

SELECT * 
FROM   tablea a 
       INNER JOIN tableb b 
               ON a.primary_key = b.foreign_key 
       INNER JOIN tablec c 
               ON b.primary_key = c.foreign_key 

27

ฉันไม่เห็นรายละเอียดมากนักเกี่ยวกับประสิทธิภาพและเครื่องมือเพิ่มประสิทธิภาพในคำตอบอื่น ๆ

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

โดยทั่วไปแล้วเป็นวิธีปฏิบัติที่ดีในการพยายามใช้INNER JOINแทนที่จะเข้าร่วมประเภทอื่น (แน่นอนถ้าเป็นไปได้ให้พิจารณาชุดผลลัพธ์ที่คาดไว้)

มีตัวอย่างและคำอธิบายที่ดีเกี่ยวกับพฤติกรรมการเชื่อมโยงที่แปลกประหลาดนี้:


4
เป็นไปไม่ได้ที่จะเป็น "แนวปฏิบัติที่ดี" ในการใช้การเข้าร่วมประเภทหนึ่ง การเข้าร่วมใดที่คุณใช้กำหนดข้อมูลที่คุณต้องการ ถ้าคุณใช้อันอื่นคุณไม่ถูกต้อง นอกจากนี้ใน Oracle อย่างน้อยคำตอบนี้ผิดอย่างสมบูรณ์ มันฟังดูผิดทุกอย่างและคุณก็ไม่มีข้อพิสูจน์ คุณมีหลักฐานหรือไม่
เบ็น

1. ฉันหมายถึงลองใช้ ฉันเห็นผู้คนจำนวนมากที่ใช้ LEFT OUTER เข้าร่วมทุกที่โดยไม่มีเหตุผลที่ดี (คอลัมน์ที่เข้าร่วมนั้น 'ไม่เป็นโมฆะ') ในกรณีเหล่านั้นจะเป็นการดีกว่าที่จะใช้การรวมภายใน 2. ฉันได้เพิ่มลิงก์ที่อธิบายพฤติกรรมที่ไม่ใช่การเชื่อมโยงดีกว่าที่ฉันสามารถทำได้
Lajos Veres

อย่างที่ฉันรู้ว่าINNER JOINช้ากว่าLEFT JOINในหลายครั้งและผู้คนสามารถใช้LEFT JOINแทนได้INNER JOINโดยการเพิ่มการWHEREลบNULLผลลัพธ์ที่ไม่คาดคิด;)
shA.t

ความคิดเห็นเหล่านี้ทำให้ฉันไม่แน่ใจ ทำไมคุณคิดว่าINNERช้าลง
Lajos Veres

ขึ้นอยู่กับเครื่องยนต์ gnu join, joinkeys, DB2, MySQL กับดักประสิทธิภาพมากเช่นการพิมพ์ที่หลวมหรือการส่งที่ชัดเจน
mckenzm

26

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

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

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

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


2
คำถามกำลังถามถึงความแตกต่างระหว่าง INNER และ OUTER เข้าร่วมแม้ว่าไม่จำเป็นต้องออกจากการเข้าร่วมด้านนอก
LearnByReading

@LearnByReading: ภาพของฉันที่อยู่ด้านขวาเป็นด้านนอกขวาเข้าร่วมเช่นแทนที่TableA a LEFT OUTER JOIN TableB bด้วยTableB B RIGHT OUTER JOIN TableA a
onedaywhen

26

อัลกอริทึมที่แม่นยำสำหรับINNER JOIN, LEFT/RIGHT OUTER JOINดังต่อไปนี้:

  1. รับแต่ละแถวจากตารางแรก: a
  2. พิจารณาแถวทั้งหมดจากตารางที่สองข้าง: (a, b[i])
  3. ประเมินON ...ข้อกับแต่ละคู่:ON( a, b[i] ) = true/false?
    • เมื่อเงื่อนไขในการประเมินผลตอบแทนที่แถวรวมtrue (a, b[i])
    • เมื่อถึงจุดสิ้นสุดของตารางที่สองโดยไม่มีการจับคู่ใด ๆ และนี่คือการOuter Joinส่งคืนคู่(เสมือน) ที่ใช้Nullสำหรับคอลัมน์ทั้งหมดของตารางอื่น: (a, Null)สำหรับการเข้าร่วมด้านนอกด้านซ้ายหรือ(Null, b)การเข้าร่วมด้านนอกขวา นี่คือเพื่อให้แน่ใจว่าแถวทั้งหมดของตารางแรกมีอยู่ในผลลัพธ์สุดท้าย

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

เข้าร่วม Inner กับ


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

หมายเหตุ:เข้าร่วมซ้าย = เข้าร่วมด้านนอกด้านซ้ายเข้าร่วมขวา = เข้าร่วมด้านนอกขวา


20

คำจำกัดความที่ง่ายที่สุด

Inner Join: ส่งกลับระเบียนที่ตรงกันจากทั้งสองตาราง

Full Outer Join: ส่งคืนระเบียนที่ตรงกันและไม่ตรงกันจากทั้งสองตารางด้วยค่า Null สำหรับระเบียนที่ไม่ตรงกันจากทั้งสองตารางตารางทั้งสอง

Left Outer Join: ส่งคืนระเบียนที่ตรงกันและไม่ตรงกันจากตารางทางด้านซ้ายเท่านั้นเท่านั้น

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

ในระยะสั้น

จับคู่ + ซ้ายตรงกันตรงกัน + ขวาตรงกัน = เต็มภายนอกเข้าร่วม

จับคู่ + ซ้ายไม่ตรงกัน = ซ้ายเข้าร่วมด้านนอก

จับคู่ + ขวาไม่ตรงกัน = นอกเข้าร่วม

จับคู่ = Inner Join


1
สิ่งนี้ยอดเยี่ยมมากและอธิบายว่าทำไมการเข้าร่วมไม่ทำงานอย่างที่คาดไว้สำหรับดัชนี Time Series การประทับเวลาแยกจากกันหนึ่งวินาทีไม่ตรงกัน
yeliabsalohcin

1
@yeliabsalohcin คุณไม่ได้อธิบาย "ตามที่คาดหวัง" ที่นี่หรือ "งาน" ในความคิดเห็นของคุณสำหรับคำถาม มันเป็นเพียงความเข้าใจผิดส่วนบุคคลที่ไม่สามารถอธิบายได้ที่คุณคาดหวังอย่างอื่น หากคุณปฏิบัติต่อคำพูดอย่างไม่สุภาพเมื่อคุณอ่าน - ตีความการเขียนที่ชัดเจนและ / หรือการยอมรับการเขียนที่ไม่ชัดเจน - เช่นเมื่อคุณกำลังเขียนที่นี่คุณสามารถคาดหวังว่าจะมีความเข้าใจผิด ในความเป็นจริงคำตอบเช่นนี้ส่วนใหญ่ที่นี่ไม่ชัดเจนและผิด "Inner Join: ส่งคืนระเบียนที่ตรงกันจากทั้งสองตาราง" ผิดเมื่อชุดคอลัมน์อินพุตแตกต่างกัน ก็พยายามที่จะพูดบางสิ่งบางอย่างบางอย่าง แต่มันไม่ได้เป็น (ดูคำตอบของฉัน.)
philipxy

9

ในเงื่อนไขง่าย ๆ

1 INNER JOIN หรือ EQUI JOIN:คืนค่าผลลัพธ์ที่ตรงกับเงื่อนไขเฉพาะในตารางทั้งสอง

2 OUTER JOIN:ส่งคืน resultset ของค่าทั้งหมดจากทั้งสองตารางแม้ว่าจะมีเงื่อนไขตรงกันหรือไม่ก็ตาม

3 LEFT JOIN:ส่งคืน resultset ของค่าทั้งหมดจากตารางด้านซ้ายและเฉพาะแถวที่ตรงกับเงื่อนไขในตารางด้านขวา

4 RIGHT JOIN:ส่งคืน resultset ของค่าทั้งหมดจากตารางด้านขวาและเฉพาะแถวที่ตรงกับเงื่อนไขในตารางด้านซ้าย

5. FULL JOIN:เข้าร่วมเต็มรูปแบบและเข้าร่วมเต็มรูปแบบด้านนอกเหมือนกัน


5

การเข้าร่วมหลักมี 2 ประเภทหลักใน SQL: [INNER และ OUTER]


ตัวอย่าง

สมมติว่าคุณมีสองตารางโดยแต่ละคอลัมน์จะมีหนึ่งคอลัมน์และข้อมูลดังต่อไปนี้:

A    B
-    -
1    3
2    4
3    5
4    6
7
8

โปรดทราบว่า (1,2,7,8) เป็นเอกลักษณ์ของ A, (3,4) เป็นเรื่องธรรมดาและ (5,6) เป็นเอกลักษณ์ของ B



  • (ภายใน) เข้าร่วม :

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

เข้าร่วมภายใน

select * from a INNER JOIN b on a.a = b.b;
select a.*, b.*  from a,b where a.a = b.b;

ผลลัพธ์:

a | b
--+--
3 | 3
4 | 4


  • เข้าร่วมด้านซ้าย (ด้านนอก) :

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

ซ้ายเข้าร่วม / ซ้ายด้านนอกเข้าร่วม

select * from a LEFT OUTER JOIN b on a.a = b.b;
select a.*, b.*  from a,b where a.a = b.b(+);

ผลลัพธ์:

a |  b
--+-----
1 | null
2 | null
3 |    3
4 |    4
7 | null
8 | null


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

เข้าร่วมขวา / ออกด้านนอกเข้าร่วม

select * from a RIGHT OUTER JOIN b on a.a = b.b;
select a.*, b.*  from a,b where a.a(+) = b.b;

ผลลัพธ์:

a    |  b
-----+----
3    |  3
4    |  4
null |  5
null |  6


  • เข้าร่วมเต็มรูปแบบ (นอก) :

    FULL JOIN สร้างชุดผลลัพธ์โดยรวมผลลัพธ์ของ LEFT JOIN และ RIGHT JOIN ชุดผลลัพธ์จะมีแถวทั้งหมดจากทั้งสองตาราง แถวที่ไม่มีการจับคู่ชุดผลลัพธ์จะมีค่าเป็นศูนย์

เข้าร่วมเต็ม / ออกเต็มเข้าร่วม

select * from a FULL OUTER JOIN b on a.a = b.b;

ผลลัพธ์:

 a   |  b
-----+-----
   1 | null
   2 | null
   3 |    3
   4 |    4
null |    6
null |    5
   7 | null
   8 | null

1
เวนไดอะแกรมไม่เพียงพอที่จะอธิบายการเชื่อม SQL ในกรณีทั่วไป การรวม SQL ไม่จำเป็นต้องจับคู่แถวระหว่างตารางแบบหนึ่งต่อหนึ่ง, เช่นการใช้ foreign key กับคีย์หลัก.
Colm Bhandal

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

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

ไม่จำเป็นต้องมี FK เพื่อเข้าร่วมหรือสอบถาม ตาราง 2 ตารางใด ๆ สามารถเข้าร่วมได้กับเงื่อนไขใด ๆ ที่เกี่ยวข้องกับคอลัมน์ & โดยไม่คำนึงถึงข้อ จำกัด ทริกเกอร์หรือการยืนยันใด ๆ
philipxy

3
  • การรวมภายใน - การรวมภายในโดยใช้แบบสอบถามที่เท่ากันอย่างใดอย่างหนึ่งจะให้จุดตัดของทั้งสองตารางคือสองแถวที่พวกเขามีร่วมกัน

  • การเข้าร่วมด้านนอกด้านซ้าย - การเข้าร่วมด้านนอกด้านซ้ายจะให้ทุกแถวใน A รวมถึงแถวทั่วไปใน B

  • การรวมภายนอกเต็มรูปแบบ - การรวมภายนอกเต็มรูปแบบจะทำให้คุณมีการรวมกันของ A และ B เช่นแถวทั้งหมดใน A และแถวทั้งหมดใน B หากบางสิ่งใน A ไม่มีตัวเลขที่สอดคล้องกันใน B ส่วน B คือ เป็นโมฆะและในทางกลับกัน


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

@philipxy: ไม่เห็นด้วยกับJoin is not an intersection unless the tables have the same columnsหมายเลขบัญชีของคุณคุณสามารถเข้าร่วมคอลัมน์ใด ๆ ที่คุณต้องการและหากการจับคู่ค่าพวกเขาจะเข้าร่วมด้วยกัน
SuicideSheep

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

สิ่งที่ฉันหมายถึงคือการเข้าร่วมเป็นเพียงจุดตัดของอินพุตเมื่อเป็นการรวมเข้าภายในตามธรรมชาติของอินพุตด้วยคอลัมน์เดียวกัน คุณกำลังใช้คำว่า "ทางแยก" & "สหภาพ" ผิด
philipxy

3

1. Inner Join:เรียกอีกอย่างว่าเข้าร่วม ส่งคืนแถวที่ปรากฏในทั้งตารางซ้ายและตารางด้านขวาเฉพาะในกรณีที่มีการแข่งขันถ้ามีการแข่งขันมิฉะนั้นจะส่งคืนระเบียนศูนย์

ตัวอย่าง:

SELECT
  e1.emp_name,
  e2.emp_salary    
FROM emp1 e1
INNER JOIN emp2 e2
  ON e1.emp_id = e2.emp_id

Output1

2. Full Outer Join:เรียกอีกอย่างว่า Full Join มันจะส่งคืนแถวทั้งหมดอยู่ในทั้งตารางซ้ายและตารางด้านขวา

ตัวอย่าง:

SELECT
  e1.emp_name,
  e2.emp_salary    
FROM emp1 e1
FULL OUTER JOIN emp2 e2
  ON e1.emp_id = e2.emp_id

output2

3. ซ้ายเข้าร่วมภายนอก:หรือเรียกง่ายๆว่า Left Join ส่งคืนแถวทั้งหมดที่มีในตารางด้านซ้ายและแถวที่ตรงกันจากตารางด้านขวา (ถ้ามี)

4. Right Outer Join:เรียกอีกอย่างว่า Right Join มันส่งกลับแถวที่ตรงกันจากตารางด้านซ้าย (ถ้ามี) และแถวทั้งหมดที่มีอยู่ในตารางด้านขวา

ร่วม

ข้อดีของการเข้าร่วม

  1. ดำเนินการได้เร็วขึ้น

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

2

พิจารณาตารางด้านล่าง 2:

EMP

empid   name    dept_id salary
1       Rob     1       100
2       Mark    1       300
3       John    2       100
4       Mary    2       300
5       Bill    3       700
6       Jose    6       400

สาขา

deptid  name
1       IT
2       Accounts
3       Security
4       HR
5       R&D

เข้าร่วมภายใน:

ส่วนใหญ่เขียนเป็นเพียงเข้าร่วมในแบบสอบถาม SQL มันจะส่งกลับเฉพาะระเบียนที่ตรงกันระหว่างตาราง

ค้นหาพนักงานทั้งหมดและชื่อแผนก:

Select a.empid, a.name, b.name as dept_name
FROM emp a
JOIN department b
ON a.dept_id = b.deptid
;

empid   name    dept_name
1       Rob     IT
2       Mark    IT
3       John    Accounts
4       Mary    Accounts
5       Bill    Security

ดังที่คุณเห็นด้านบนJoseจะไม่ถูกพิมพ์จากEMPในเอาต์พุตเนื่องจาก dept_id 6ไม่พบข้อมูลที่ตรงกันในตารางแผนก ในทำนองเดียวกันHRและR&Dแถวจะไม่ถูกพิมพ์จากตารางแผนกเนื่องจากไม่พบข้อมูลที่ตรงกันในตาราง Emp

ดังนั้นเข้าร่วมภายในหรือเพียงเข้าร่วมส่งคืนแถวที่ตรงกันเท่านั้น

เข้าร่วมซ้าย:

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

Select a.empid, a.name, b.name as dept_name
FROM emp a
LEFT JOIN department b
ON a.dept_id = b.deptid
;

empid   name    dept_name
1       Rob     IT
2       Mark    IT
3       John    Accounts
4       Mary    Accounts
5       Bill    Security
6       Jose    

ดังนั้นหากคุณสังเกตเห็นผลลัพธ์ข้างต้นระเบียนทั้งหมดจากตารางซ้าย (Emp) จะถูกพิมพ์ด้วยการจับคู่ระเบียนจากตาราง RIGHT

HRและR&Dแถวจะไม่ถูกพิมพ์จากตารางแผนกเนื่องจากไม่พบข้อมูลที่ตรงกันในตาราง Emp ที่ dept_id

ดังนั้น LEFT JOIN ส่งคืนแถวทั้งหมดจากตารางด้านซ้ายและเฉพาะแถวที่ตรงกันจากตาราง RIGHT

นอกจากนี้ยังสามารถตรวจสอบ DEMO ที่นี่


2

ความคิดทั่วไป

โปรดดูคำตอบโดยมาร์ตินสมิ ธสำหรับ illustations ที่ดีกว่าและคำอธิบายที่แตกต่างกันเข้าร่วมรวมทั้งและโดยเฉพาะอย่างยิ่งความแตกต่างระหว่างFULL OUTER JOIN, และRIGHT OUTER JOINLEFT OUTER JOIN

ตารางทั้งสองนี้เป็นพื้นฐานสำหรับการเป็นตัวแทนของJOINs ด้านล่าง:

รากฐาน

ข้ามเข้าร่วม

CROSSJOIN

SELECT *
  FROM citizen
 CROSS JOIN postalcode

ผลลัพธ์จะเป็นผลิตภัณฑ์คาร์ทีเซียนของชุดค่าผสมทั้งหมด ไม่JOINต้องการเงื่อนไข:

CrossJoinResult

เข้าร่วมภายใน

INNER JOIN เหมือนกันเพียง: JOIN

InnerJoin

SELECT *
  FROM citizen    c
  JOIN postalcode p ON c.postal = p.postal

ผลลัพธ์จะเป็นชุดค่าผสมที่ตรงตามJOINเงื่อนไขที่ต้องการ:

InnerJoinResult

ซ้ายเข้าร่วม

LEFT OUTER JOIN เป็นเช่นเดียวกับ LEFT JOIN

LeftJoin

SELECT *
  FROM citizen         c
  LEFT JOIN postalcode p ON c.postal = p.postal

ผลลัพธ์จะเป็นทุกอย่างcitizenแม้ว่าจะไม่มีการแข่งขันpostalcodeก็ตาม ต้องมีJOINเงื่อนไขอีกครั้ง:

LeftJoinResult

ข้อมูลสำหรับการเล่น

ตัวอย่างทั้งหมดถูกรันบน Oracle 18c มีวางจำหน่ายแล้วที่dbfiddle.ukซึ่งเป็นที่จับภาพหน้าจอของตาราง

CREATE TABLE citizen (id      NUMBER,
                      name    VARCHAR2(20),
                      postal  NUMBER,  -- <-- could do with a redesign to postalcode.id instead.
                      leader  NUMBER);

CREATE TABLE postalcode (id      NUMBER,
                         postal  NUMBER,
                         city    VARCHAR2(20),
                         area    VARCHAR2(20));

INSERT INTO citizen (id, name, postal, leader)
              SELECT 1, 'Smith', 2200,  null FROM DUAL
        UNION SELECT 2, 'Green', 31006, 1    FROM DUAL
        UNION SELECT 3, 'Jensen', 623,  1    FROM DUAL;

INSERT INTO postalcode (id, postal, city, area)
                 SELECT 1, 2200,     'BigCity',         'Geancy'  FROM DUAL
           UNION SELECT 2, 31006,    'SmallTown',       'Snizkim' FROM DUAL
           UNION SELECT 3, 31006,    'Settlement',      'Moon'    FROM DUAL  -- <-- Uuh-uhh.
           UNION SELECT 4, 78567390, 'LookoutTowerX89', 'Space'   FROM DUAL;

ขอบเขตพร่ามัวเมื่อเล่นกับJOINและWHERE

ข้ามเข้าร่วม

CROSS JOINส่งผลให้แถวเป็นแนวคิดทั่วไป / INNER JOIN:

SELECT *
  FROM citizen          c
  CROSS JOIN postalcode p
 WHERE c.postal = p.postal -- < -- The WHERE condition is limiting the resulting rows

การใช้CROSS JOINเพื่อให้ได้ผลลัพธ์ของLEFT OUTER JOINกลวิธีที่ต้องการเพิ่มในNULLแถว มันถูกละไว้

เข้าร่วมภายใน

INNER JOINกลายเป็นผลิตภัณฑ์คาร์ทีเซียน มันเหมือนกับแนวคิดทั่วไป / CROSS JOIN:

SELECT *
  FROM citizen    c
  JOIN postalcode p ON 1 = 1  -- < -- The ON condition makes it a CROSS JOIN

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

ใช้INNER JOINเพื่อให้ได้ผลลัพธ์ของการLEFT OUTER JOINยังต้องใช้เทคนิค มันถูกละไว้

ซ้ายเข้าร่วม

LEFT JOINผลลัพธ์เป็นแถวตามแนวคิดทั่วไป / CROSS JOIN:

SELECT *
  FROM citizen         c
  LEFT JOIN postalcode p ON 1 = 1 -- < -- The ON condition makes it a CROSS JOIN

LEFT JOINผลลัพธ์เป็นแถวตามแนวคิดทั่วไป / INNER JOIN:

SELECT *
  FROM citizen         c
  LEFT JOIN postalcode p ON c.postal = p.postal
 WHERE p.postal IS NOT NULL -- < -- removed the row where there's no mathcing result from postalcode

ปัญหาเกี่ยวกับแผนภาพ Venn

การค้นหารูปภาพทางอินเทอร์เน็ตที่ "sql join cross outer outer outer" จะแสดงไดอะแกรมของ Venn มากมาย ฉันเคยมีสำเนาที่พิมพ์บนโต๊ะของฉัน แต่มีปัญหาเกี่ยวกับการเป็นตัวแทน

ไดอะแกรมเวนน์นั้นยอดเยี่ยมสำหรับทฤษฎีเซตซึ่งองค์ประกอบสามารถอยู่ในเซตเดียวหรือทั้งคู่ก็ได้ แต่สำหรับฐานข้อมูลแล้วองค์ประกอบใน "set" ดูเหมือนจะเป็นแถวในตารางและดังนั้นจึงไม่ปรากฏในตารางอื่น ๆ ไม่มีสิ่งใดเหมือนแถวหนึ่งที่ปรากฏในหลายตาราง แถวเป็นตารางเฉพาะ

การรวมตัวเองเป็นกรณีมุมที่แต่ละองค์ประกอบมีความเหมือนกันในทั้งสองชุด แต่ก็ยังไม่มีปัญหาใด ๆ ด้านล่าง

ชุดAหมายถึงชุดทางด้านซ้าย ( citizenตาราง) และชุดBเป็นชุดทางด้านขวา ( postalcodeตาราง) ในการสนทนาด้านล่าง

ข้ามเข้าร่วม

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

แถวนั้นแตกต่างกัน UNIONคือ 7 แถวในทั้งหมด แต่ไม่สามารถใช้ร่วมกับSQLชุดผลลัพธ์ทั่วไปได้ และนี่ไม่ใช่วิธีการCROSS JOINทำงานทั้งหมด:

CrossJoinUnion1

พยายามเป็นตัวแทนของมันเช่นนี้:

CrossJoinUnion2Crossing

..but ตอนนี้มันก็ดูเหมือนว่าINTERSECTIONซึ่งก็แน่นอนไม่ได้ นอกจากนี้ยังไม่มีองค์ประกอบในสิ่งINTERSECTIONที่อยู่ในชุดที่แตกต่างกันสองชุด อย่างไรก็ตามดูเหมือนว่าผลลัพธ์ที่ค้นหาได้จะคล้ายกับสิ่งนี้มาก:

CrossJoinUnionUnion3

สำหรับการอ้างอิงหนึ่งผลค้นหาสำหรับCROSS JOINs สามารถมองเห็นที่Tutorialgateway INTERSECTIONเช่นเดียวกับคนนี้เป็นที่ว่างเปล่า

เข้าร่วมภายใน

ค่าขององค์ประกอบขึ้นอยู่กับJOINเงื่อนไข เป็นไปได้ที่จะแสดงสิ่งนี้ภายใต้เงื่อนไขว่าทุกแถวจะมีลักษณะเฉพาะกับเงื่อนไขนั้น ความหมายid=xเป็นจริงสำหรับหนึ่งแถวเท่านั้น เมื่อแถวในตารางA( citizen) ตรงกับหลายแถวในตารางB( postalcode) ภายใต้JOINเงื่อนไขผลลัพธ์จะมีปัญหาเช่นเดียวกับCROSS JOIN: แถวจะต้องแสดงหลาย ๆ ครั้งและทฤษฎีเซตไม่ได้ถูกสร้างขึ้นมาเพื่อสิ่งนั้นจริงๆ ภายใต้เงื่อนไขของความเป็นเอกลักษณ์แผนภาพอาจทำงานได้ แต่โปรดจำไว้ว่าJOINเงื่อนไขนั้นจะกำหนดตำแหน่งขององค์ประกอบในแผนภาพ ดูเฉพาะค่าของJOINสภาพที่มีกับส่วนที่เหลือของแถวพร้อมสำหรับการนั่ง:

InnerJoinIntersection - เต็มแล้ว

การแสดงนี้ตกอยู่ห่างกันอย่างสมบูรณ์เมื่อใช้INNER JOINกับสภาพที่ทำให้มันเป็นON 1 = 1CROSS JOIN

ด้วยตัวเอง - JOINแถวต่างๆเป็นองค์ประกอบตัวตนที่เป็นจริงในทั้งสองตาราง แต่แสดงถึงตารางว่าทั้งสองAและBไม่เหมาะสมมาก ตัวอย่างเช่นJOINเงื่อนไขทั่วไปที่ทำให้องค์ประกอบในAการจับคู่องค์ประกอบที่แตกต่างใน B คือON A.parent = B.childการจับคู่จากAไปยังBองค์ประกอบแยกต่างหาก จากตัวอย่างที่เป็นSQLเช่นนี้:

SELECT *
  FROM citizen c1
  JOIN citizen c2 ON c1.id = c2.leader

SelfJoinResult

ความหมายสมิ ธ เป็นผู้นำของทั้งกรีนและเซ่น

เข้าร่วมด้านนอก

ปัญหาเริ่มต้นอีกครั้งเมื่อแถวหนึ่งมีการจับคู่หลายแถวกับอีกแถวในตารางอื่น นี่คือความซับซ้อนต่อไปเพราะOUTER JOINสามารถที่จะตรงกับชุดที่ว่างเปล่า แต่ในการตั้งทฤษฎีสหภาพของชุดใด ๆและชุดที่ว่างเปล่าอยู่เสมอเพียงC Cชุดที่ว่างเปล่าไม่เพิ่มอะไรเลย การเป็นตัวแทนของสิ่งนี้LEFT OUTER JOINมักจะแสดงให้ทุกคนAเห็นว่าแถวในAนั้นถูกเลือกไม่ว่าจะมีการแข่งขันหรือไม่Bก็ตาม อย่างไรก็ตาม "องค์ประกอบการจับคู่" มีปัญหาเช่นเดียวกับภาพประกอบด้านบน ขึ้นอยู่กับเงื่อนไข และชุดที่ว่างเปล่าดูเหมือนจะเดินไปที่A:

LeftJoinIntersection - เต็มแล้ว

ประโยคที่ทำให้รู้สึก

ค้นหาแถวทั้งหมดจาก a CROSS JOINด้วย Smith และรหัสไปรษณีย์บนดวงจันทร์:

SELECT *
  FROM citizen          c
 CROSS JOIN postalcode  p
 WHERE c.name = 'Smith'
   AND p.area = 'Moon';

ที่ - ผล

JOINตอนนี้แผนภาพเวนน์ไม่ได้ใช้เพื่อสะท้อนให้เห็นถึง มันใช้สำหรับข้อเท่านั้นWHERE :

ที่ไหน

.. และนั่นทำให้รู้สึก

เมื่อ INTERSECT และ UNION เข้าท่า

ตัด

ตามที่ได้อธิบายไม่ได้จริงๆINNER JOIN INTERSECTอย่างไรก็ตามINTERSECTs สามารถใช้กับผลลัพธ์ของข้อความค้นหาแยกต่างหาก นี่คือไดอะแกรมเวนน์เหมาะสมแล้วเนื่องจากองค์ประกอบจากคิวรีแบบแยกเป็นแถวที่จริงซึ่งเป็นของผลลัพธ์ใดผลลัพธ์หนึ่งหรือทั้งสองอย่าง จุดตัดจะส่งกลับเฉพาะผลลัพธ์ที่มีแถวอยู่ในข้อความค้นหาทั้งสอง สิ่งนี้SQLจะส่งผลให้แถวเดียวกันกับด้านบนWHEREและแผนภาพเวนน์จะเหมือนกัน:

SELECT *
  FROM citizen          c
 CROSS JOIN postalcode  p
 WHERE c.name = 'Smith'
INTERSECT
SELECT *
  FROM citizen          c
 CROSS JOIN postalcode  p
 WHERE p.area = 'Moon';

ยูเนี่ยน

OUTER JOINUNIONไม่ได้เป็น อย่างไรก็ตามUNIONทำงานภายใต้เงื่อนไขเดียวกันINTERSECTซึ่งทำให้ได้ผลลัพธ์ทั้งหมดที่รวมทั้งSELECTs:

SELECT *
  FROM citizen          c
 CROSS JOIN postalcode  p
 WHERE c.name = 'Smith'
UNION
SELECT *
  FROM citizen          c
 CROSS JOIN postalcode  p
 WHERE p.area = 'Moon';

ซึ่งเทียบเท่ากับ:

SELECT *
  FROM citizen          c
 CROSS JOIN postalcode  p
 WHERE c.name = 'Smith'
   OR p.area = 'Moon';

.. และให้ผลลัพธ์:

ยูเนี่ยน - ผลลัพธ์

นอกจากนี้ที่นี่แผนภาพเวนน์ทำให้รู้สึก:

ยูเนี่ยน

เมื่อมันใช้ไม่ได้

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

SELECT *
  FROM citizen
 WHERE name = 'Smith'
SELECT *
  FROM postalcode
 WHERE area = 'Moon';

.. พยายามรวมผลลัพธ์ด้วยการUNIONให้

ORA-01790: expression must have same datatype as corresponding expression

ที่ให้ความสนใจต่อการอ่านบอกว่าไม่มีการแผนภาพเวนน์เมื่ออธิบายร่วมและSQL ร่วมเป็นแผนภาพเวนน์ EXCEPTทั้งยังปก


1

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

โดยทั่วไปบ่อยกว่าไม่แบบสอบถามJOINเดือดลงไปสองกรณี:

สำหรับSELECTชุดย่อยของข้อมูลA:

  • ใช้INNER JOINเมื่อข้อมูลที่เกี่ยวข้องBคุณกำลังมองหาต้องมีอยู่ต่อการออกแบบฐานข้อมูล;
  • ใช้LEFT JOINเมื่อข้อมูลที่เกี่ยวข้องที่BคุณกำลังมองหาMIGHTหรือMIGHT ไม่มีอยู่ต่อการออกแบบฐานข้อมูล

1

ความแตกต่างระหว่างinner joinและouter joinเป็นดังนี้:

  1. Inner joinเป็นการรวมที่รวมตารางตาม tuples ที่ตรงกันในขณะที่outer joinเป็นการรวมที่รวมตารางตาม tuple ทั้งที่ตรงกันและไม่ตรงกัน
  2. Inner joinผสานแถวที่ตรงกันจากสองตารางที่ละเว้นแถวที่ไม่ตรงกันในขณะที่outer joinผสานแถวจากสองตารางและแถวที่ไม่ตรงกันจะเติมด้วยค่า null
  3. Inner joinเป็นเหมือนการดำเนินการทางแยกในขณะที่outer joinเป็นเหมือนการดำเนินการสหภาพ
  4. Inner joinเป็นสองประเภทในขณะที่outer joinสามประเภท
  5. outer joininner joinจะเร็วกว่า

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

1
@ M.achaibou โปรดอย่าทำการแก้ไขที่ทำให้เกิดการเปลี่ยนแปลงรูปแบบที่ไม่จำเป็น ชื่อของผู้ประกอบการไม่ได้เป็นรหัสเว้นแต่พวกเขาจะใช้ในรหัส กรุณาอย่าทำการเปลี่ยนแปลงในการโพสต์ความหมายโพสต์ความคิดเห็นไปยังผู้เขียน หากคุณไม่มีตัวแทนให้รอจนกว่าคุณจะทำ มันเกิดขึ้นว่าผู้ลงโฆษณาอนุมัติสิ่งนี้ แต่โปรดอย่าทำการแก้ไขดังกล่าว การเข้าร่วม PS Outer ไม่เร็วกว่าการรวมภายใน
philipxy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.