อะไรคือวิธีที่ดีที่สุดในการเข้าร่วมโต๊ะเดียวกันสองครั้ง


108

ซับซ้อนนิดหน่อย แต่ฉันมี 2 ตาราง สมมติว่าโครงสร้างเป็นดังนี้:

*Table1*
ID
PhoneNumber1
PhoneNumber2

*Table2*
PhoneNumber
SomeOtherField

สามารถรวมตารางได้ตาม Table1.PhoneNumber1 -> Table2PhoneNumber หรือ Table1.PhoneNumber2 -> Table2.PhoneNumber

ตอนนี้ฉันต้องการรับชุดผลลัพธ์ที่มี PhoneNumber1, SomeOtherField ที่สอดคล้องกับ PhoneNumber1, PhoneNumber2 และ SomeOtherField ที่สอดคล้องกับ PhoneNumber2

ฉันคิด 2 วิธีในการทำสิ่งนี้ - ไม่ว่าจะโดยการเข้าร่วมบนโต๊ะสองครั้งหรือโดยการเข้าร่วมครั้งเดียวด้วย OR ในส่วนคำสั่ง ON

วิธีที่ 1 :

SELECT t1.PhoneNumber1, t1.PhoneNumber2, 
   t2.SomeOtherFieldForPhone1, t3.someOtherFieldForPhone2
FROM Table1 t1
INNER JOIN Table2 t2
   ON t2.PhoneNumber = t1.PhoneNumber1
INNER JOIN Table2 t3
   ON t3.PhoneNumber = t1.PhoneNumber2

ดูเหมือนว่าจะได้ผล

วิธีที่ 2 :

มีข้อความค้นหาที่มีลักษณะเช่นนี้ -

SELECT ...
FROM Table1
INNER JOIN Table2 
   ON Table1.PhoneNumber1 = Table2.PhoneNumber OR
      Table1.PhoneNumber2 = Table2.PhoneNumber

ฉันยังไม่ได้ทำงานนี้และไม่แน่ใจว่ามีวิธีทำหรือไม่

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

คำตอบ:


151

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

วิธีที่ 1ตามที่คุณอธิบายว่าเป็นทางออกที่ดีที่สุดของคุณ ดูเหมือนจะค่อนข้างสั้นเนื่องจากรูปแบบการตั้งชื่อและนามแฝงสั้น ๆ แต่ ... นามแฝงเป็นเพื่อนของคุณเมื่อต้องเข้าร่วมตารางเดียวกันหลายครั้งหรือใช้แบบสอบถามย่อยเป็นต้น

ฉันจะทำความสะอาดสิ่งต่างๆเล็กน้อย:

SELECT t.PhoneNumber1, t.PhoneNumber2, 
   t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2
FROM Table1 t
JOIN Table2 t1 ON t1.PhoneNumber = t.PhoneNumber1
JOIN Table2 t2 ON t2.PhoneNumber = t.PhoneNumber2

ฉันทำอะไรลงไป:

  • ไม่จำเป็นต้องระบุ INNER - โดยนัยจากข้อเท็จจริงที่ว่าคุณไม่ได้ระบุ LEFT หรือ RIGHT
  • อย่า n ต่อท้ายตารางการค้นหาหลักของคุณ
  • N-Suffix นามแฝงตารางที่คุณจะใช้หลาย ๆ ครั้งเพื่อให้ชัดเจน

* DBA วิธีหนึ่งที่จะหลีกเลี่ยงความปวดหัวของการอัปเดตคีย์ธรรมชาติคือการไม่ระบุคีย์หลักและข้อ จำกัด ของคีย์ต่างประเทศซึ่งจะทำให้เกิดปัญหากับการออกแบบฐานข้อมูลที่ไม่ดี ฉันเคยเห็นสิ่งนี้บ่อยกว่านี้


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

6
@volumeone - ฉันคิดว่าคุณอาจเข้าใจผิดในส่วนสุดท้ายของคำตอบของฉัน คีย์หลักและต่างประเทศมีความคิดที่ดี การหลีกเลี่ยงเป็นการปฏิบัติที่ไม่ดีการออกแบบที่ไม่ดีและไม่ดี
Paul Sasik

สมบูรณ์แบบ .. แต่ทำไมนามแฝงจึงเป็นสิ่งจำเป็นในสถานการณ์นี้?
Raiden Core

มีวิธีทำอย่างไรโดยไม่ต้องเข้าร่วมโต๊ะเดียวกันซ้ำสอง? อาจใช้เงื่อนไขใน where clause ...
JohnOsborne

5

อย่างแรกก็ดีเว้นแต่ว่า Phone1 หรือ (มีโอกาสมากกว่า) phone2 จะเป็นโมฆะ ในกรณีนี้คุณต้องการใช้การรวมด้านซ้ายแทนการรวมภายใน

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


จุดเยี่ยม! สิ่งนี้จะทำให้ฉันปวดหัวมากในภายหลัง ... ขอบคุณ!
froadie

4

คุณสามารถใช้UNIONเพื่อรวมสองการรวมเข้าด้วยกัน:

SELECT Table1.PhoneNumber1 as PhoneNumber, Table2.SomeOtherField as OtherField
  FROM Table1
  JOIN Table2
    ON Table1.PhoneNumber1 = Table2.PhoneNumber
 UNION
SELECT Table1.PhoneNumber2 as PhoneNumber, Table2.SomeOtherField as OtherField
  FROM Table1
  JOIN Table2
    ON Table1.PhoneNumber2 = Table2.PhoneNumber

1
ฉันคิดถึงสิ่งนี้ แต่ฉันต้องการให้ส่งคืนเป็นบันทึกเดียวที่ถูกทำให้เป็นมาตรฐาน ...
froadie

โอเคฉันคิดว่าตรงกันข้าม ถ้าเป็นเช่นนั้นฉันจะทำโดยใช้วิธีแรกของคุณ ฉันจะแก้ไขคำตอบของฉัน
Pointy

3

ปัญหาของฉันคือการแสดงบันทึกแม้ว่าจะไม่มีหรือมีหมายเลขโทรศัพท์เพียงหมายเลขเดียว (สมุดที่อยู่แบบเต็ม) ดังนั้นฉันจึงใช้ LEFT JOIN ซึ่งรับบันทึกทั้งหมดจากทางซ้ายแม้ว่าจะไม่มีข้อมูลที่ตรงกันทางด้านขวาก็ตาม สำหรับฉันสิ่งนี้ใช้งานได้ในMicrosoft Access SQL (พวกเขาต้องการวงเล็บ!)

SELECT t.PhoneNumber1, t.PhoneNumber2, t.PhoneNumber3
   t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2, t3.someOtherFieldForPhone3
FROM 
(
 (
  Table1 AS t LEFT JOIN Table2 AS t3 ON t.PhoneNumber3 = t3.PhoneNumber
 )
 LEFT JOIN Table2 AS t2 ON t.PhoneNumber2 = t2.PhoneNumber
)
LEFT JOIN Table2 AS t1 ON t.PhoneNumber1 = t1.PhoneNumber;

2

วิธีแรกคือแนวทางที่เหมาะสมและจะทำในสิ่งที่คุณต้องการ อย่างไรก็ตามด้วยการรวมด้านในคุณจะเลือกแถวจากTable1หมายเลขโทรศัพท์ทั้งสองTable2เท่านั้น คุณอาจต้องการทำLEFT JOINเพื่อให้ทุกแถวจากTable1ถูกเลือก หากหมายเลขโทรศัพท์ไม่ตรงกันแสดงว่าSomeOtherFields จะเป็นโมฆะ หากคุณต้องการให้แน่ใจว่าคุณมีหมายเลขโทรศัพท์ที่ตรงกันอย่างน้อยหนึ่งหมายเลขคุณสามารถทำได้WHERE t2.PhoneNumber IS NOT NULL OR t3.PhoneNumber IS NOT NULL

วิธีที่สองอาจมีปัญหา: จะเกิดอะไรขึ้นถ้าTable2มีทั้งสองPhoneNumber1และPhoneNumber2? จะเลือกแถวไหน ขึ้นอยู่กับข้อมูลของคุณคีย์ต่างประเทศ ฯลฯ ซึ่งอาจเป็นปัญหาหรือไม่ก็ได้

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