0Pricing
SQL Interview Prep · บทเรียน

กับดักการใช้ WHERE กับการเชื่อมตารางภายนอก

เหตุใดการกรองคอลัมน์จากการเชื่อมตารางภายนอกใน WHERE จึงเปลี่ยนให้เป็นการเชื่อมตารางภายในโดยไม่รู้ตัว

กับดักการใช้ WHERE กับการเชื่อมตารางภายนอก เป็นบทเรียน SQL Interview Prep ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน SQL Interview Prep และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส SQL Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน

กับดักที่ทำให้ทุกคนพลาด

นี่คือข้อผิดพลาดของการ JOIN แบบด้านนอกที่พบบ่อยที่สุดและผู้สัมภาษณ์มักวางเป็นกับดัก: “แสดงลูกค้าทุกคนและคำสั่งซื้อของพวกเขาจากปี 2024 รวมถึงลูกค้าที่ไม่มีคำสั่งซื้อในปี 2024”

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

คำสั่งที่มีข้อผิดพลาด

นี่คือข้อผิดพลาดที่เกิดขึ้น คำสั่งดูสมเหตุสมผล: เก็บลูกค้าทั้งหมดไว้ เชื่อมกับคำสั่งซื้อของลูกค้า แล้วกรองให้เหลือปี 2024

แต่ลูกค้าที่ไม่มีคำสั่งซื้อ หรือไม่มีคำสั่งซื้อในปี 2024 จะหายไปจากผลลัพธ์ ข้อกำหนดที่ต้องรวมลูกค้าเหล่านั้นไว้จึงไม่เป็นไปตามที่ต้องการ

-- BUG: drops customers with no 2024 order
SELECT c.name, o.id, o.order_date
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.order_date >= '2024-01-01';

เหตุผลที่คำสั่งทำงานผิดพลาด

โปรดทบทวนลำดับการทำงาน: JOIN จะทำงานก่อน และสร้างแถวที่คอลัมน์คำสั่งซื้อทุกคอลัมน์มีค่า NULL สำหรับลูกค้าที่ไม่ตรงกัน จากนั้น WHERE จึงทำงาน

สำหรับลูกค้าที่ไม่ตรงกัน o.order_date จะเป็น NULL ดังนั้น o.order_date >= '2024-01-01' จึงประเมินผลเป็น UNKNOWN ไม่ใช่จริง WHERE จะเก็บไว้เฉพาะแถวที่มีค่าเป็นจริง จึงกรองแถวที่มีค่า NULL ออกไป ซึ่งเป็นแถวที่ LEFT JOIN พยายามเก็บไว้พอดี

NULL ทำให้ตัวกรองใช้การไม่ได้

การเปรียบเทียบกับ NULL ใด ๆ จะให้ผลเป็น UNKNOWN: NULL >= '2024-01-01' เป็น UNKNOWN, NULL = 5 เป็น UNKNOWN และแม้แต่ NULL <> 5 ก็เป็น UNKNOWN

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

วิธีแก้: ใส่ตัวกรองใน ON

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

-- CORRECT: filter lives in ON
SELECT c.name, o.id, o.order_date
FROM customers c
LEFT JOIN orders o
  ON o.customer_id = c.id
  AND o.order_date >= '2024-01-01';
-- customers with no 2024 order: kept, NULL order

ON กับ WHERE ในประโยคเดียว

กฎที่ควรพูดในการสัมภาษณ์คือ

สำหรับตารางที่ถูกเก็บไว้ (ตารางด้านนอก) เงื่อนไขที่ใช้กับอีกตารางหนึ่งต้องอยู่ใน ON ส่วนเงื่อนไขที่ใช้กับตารางที่ถูกเก็บไว้เองต้องอยู่ใน WHERE

  • ON ตัดสินว่าอะไรถือเป็นการตรงกัน (ทำงานระหว่างการ JOIN)
  • WHERE กรองแถวสุดท้าย (ทำงานภายหลังและลบแถวที่มีค่า NULL ออก)

ผลลัพธ์เทียบกันทีละด้าน

ข้อมูลชุดเดียวกัน ตำแหน่งของตัวกรองสองแบบให้คำตอบต่างกัน สมมติว่า Carol ไม่มีคำสั่งซื้อในปี 2024

  • ตัวกรองใน WHERE: Carol หายไป ผลลัพธ์จึงมีผลเหมือนการทำ INNER JOIN
  • ตัวกรองใน ON: Carol ปรากฏหนึ่งครั้งพร้อมค่า NULL ในคอลัมน์คำสั่งซื้อ ซึ่งเป็นไปตามข้อกำหนด

ความแตกต่างของผลลัพธ์คือประเด็นสำคัญทั้งหมดของกับดักนี้

-- ON version output
-- Alice | 50 | 2024-03-01
-- Bob   | 20 | 2024-05-02
-- Carol | NULL | NULL   <-- preserved

กรณีที่ WHERE ถูกต้องจริง

การใช้ WHERE กับการ JOIN แบบด้านนอกไม่ได้เป็นข้อผิดพลาดเสมอไป การกรอง ตารางที่ถูกเก็บไว้เป็นสิ่งที่ทำได้ เพราะไม่เกี่ยวข้องกับค่า NULL ที่เกิดจากการ JOIN

และในบทเรียนก่อนหน้า การ JOIN แบบค้นหาแถวที่ไม่มีคู่ตรงกันก็ ตั้งใจใช้ WHERE o.id IS NULL เพื่ออาศัยพฤติกรรมนี้โดยตรง ทักษะสำคัญคือการรู้ว่ากำลังอยู่ในกรณีใด

-- Fine: filtering the preserved (left) table
SELECT c.name, o.id
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE c.country = 'US';

หลักการตรวจจับ

เมื่อตรวจทานการ JOIN แบบด้านนอก ให้ดูส่วนคำสั่ง WHERE ว่ามีเงื่อนไขที่ใช้กับคอลัมน์ของ ตารางที่ไม่ได้ถูกเก็บไว้หรือไม่ (ยกเว้นการตรวจสอบ IS NULL สำหรับการ JOIN แบบค้นหาแถวที่ไม่มีคู่ตรงกัน)

หากพบ o.someColumn = ... หรือการตรวจสอบช่วงหรือความเท่ากันของฝั่งด้านนอกใน WHERE ให้สงสัยว่าอาจเป็นกับดัก ถามตัวเองว่า “สิ่งนี้ทำให้ LEFT JOIN ของฉันกลายเป็น INNER JOIN หรือไม่” โดยปกติแล้วคำตอบคือใช่

เงื่อนไขหลายรายการ

คุณสามารถใช้ตำแหน่งทั้งสองแบบร่วมกันได้ เงื่อนไขการตรงกันบนตารางขวาให้อยู่ใน ON ส่วนตัวกรองหลังการ JOIN ที่ใช้กับตารางซ้ายโดยตรงให้อยู่ใน WHERE ทั้งสองส่วนทำงานร่วมกันได้อย่างชัดเจน

SELECT c.name, o.id, o.amount
FROM customers c
LEFT JOIN orders o
  ON o.customer_id = c.id
  AND o.amount > 100          -- match condition
WHERE c.signup_year = 2023;    -- preserved-table filter

การอธิบายออกเสียง

ในการสัมภาษณ์ ให้อธิบายกลไกการทำงาน ไม่ใช่เพียงบอกวิธีแก้

“การ JOIN ทำงานก่อนและเติมค่า NULL ให้คอลัมน์ของตารางขวาที่ไม่ตรงกัน เงื่อนไขใน WHERE ที่ใช้กับคอลัมน์เหล่านั้นจะประเมินผลเป็น UNKNOWN สำหรับแถวที่มีค่า NULL และ WHERE จะลบแถวที่ไม่ได้ผลเป็นจริงออก ดังนั้นการ JOIN แบบด้านนอกจึงยุบลงเป็นการ JOIN แบบ INNER การใส่เงื่อนไขไว้ใน ON จะทำให้เงื่อนไขนั้นยังเป็นเงื่อนไขการตรงกัน และเก็บแถวที่ไม่ตรงกันไว้” คำอธิบายนี้ใช้ได้ผลเสมอ

ตรวจสอบความเข้าใจ

คุณต้องแสดงลูกค้าทั้งหมดและเฉพาะคำสั่งซื้อของพวกเขาในปี 2024 โดยยังคงเก็บลูกค้าที่ไม่มีคำสั่งซื้อไว้

สรุป

การกรองคอลัมน์ของ ตารางที่ไม่ได้ถูกเก็บไว้ด้วย WHERE จะเปลี่ยนการ JOIN แบบด้านนอกให้กลายเป็นการ JOIN แบบ INNER อย่างเงียบ ๆ เนื่องจากค่า NULL จากแถวที่ไม่ตรงกันทำให้เงื่อนไขประเมินผลเป็น UNKNOWN และ WHERE จะลบแถวเหล่านั้นออก

  • เงื่อนไขการตรงกันบนตารางด้านนอกให้อยู่ใน ON
  • ตัวกรองบนตารางที่ถูกเก็บไว้ให้อยู่ใน WHERE
  • IS NULL ใน WHERE คือการ JOIN แบบค้นหาแถวที่ไม่มีคู่ตรงกันโดยตั้งใจ ไม่ใช่กับดัก
  • อธิบายลำดับการทำงานเพื่อแสดงให้เห็นว่าคุณเข้าใจเหตุผล

คำถามที่พบบ่อย

บทเรียน “กับดักการใช้ WHERE กับการเชื่อมตารางภายนอก” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “กับดักการใช้ WHERE กับการเชื่อมตารางภายนอก” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส SQL Interview Prep ให้อัปเกรดเป็น CoddyKit PRO คอร์ส SQL Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “กับดักการใช้ WHERE กับการเชื่อมตารางภายนอก”

เหตุใดการกรองคอลัมน์จากการเชื่อมตารางภายนอกใน WHERE จึงเปลี่ยนให้เป็นการเชื่อมตารางภายในโดยไม่รู้ตัว คุณปฏิบัติ SQL Interview Prep ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน SQL Interview Prep หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน SQL Interview Prep บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “กับดักการใช้ WHERE กับการเชื่อมตารางภายนอก” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน SQL Interview Prep นี้ได้ไหม

ได้ บทเรียน SQL Interview Prep ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. LEFT JOIN และการคงแถวที่ไม่ตรงกัน
  2. ความหมายของ RIGHT และ FULL OUTER JOIN
  3. ค้นหาแถวที่ไม่มีรายการตรงกัน (การเชื่อมตารางแบบตัดออก)
  4. กับดักการใช้ WHERE กับการเชื่อมตารางภายนอก
← กลับไปที่ SQL Interview Prep