EXISTS และ NOT EXISTS ที่สัมพันธ์กับคิวรีภายนอก
ทางเลือกของการเชื่อมตารางแบบตัดออกที่แข็งแกร่งและจัดการ NULL ได้อย่างถูกต้อง
EXISTS และ NOT EXISTS ที่สัมพันธ์กับคิวรีภายนอก เป็นบทเรียน Coding Interview Prep ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Coding Interview Prep และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Coding Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน
EXISTS ใช้ตรวจสอบการมีอยู่
EXISTS รับคิวรีย่อยและคืนค่า TRUE ทันทีที่คิวรีย่อยนั้นให้ผลลัพธ์อย่างน้อยหนึ่งแถว มิฉะนั้นจะคืนค่า FALSE โดยจะไม่คืนแถวเหล่านั้นออกมาเอง
เมื่อมีคิวรีย่อยแบบสัมพันธ์อยู่ภายใน EXISTS คำสั่งนี้จะกลายเป็นการตรวจสอบการมีอยู่ทีละแถวภายนอกว่า "มีแถวที่ตรงกันสำหรับแถวภายนอกนี้หรือไม่"
เนื่องจาก EXISTS จะหยุดทันทีเมื่อพบแถวแรก จึงไม่สนใจว่ามีแถวที่ตรงกันกี่แถว รายละเอียดด้านความหมายนี้เป็นประเด็นยอดนิยมในการสัมภาษณ์
EXISTS แบบสัมพันธ์พื้นฐาน
ค้นหาลูกค้าที่สั่งซื้ออย่างน้อยหนึ่งรายการ คิวรีภายในเชื่อมโยงกับคิวรีภายนอกผ่าน o.customer_id = c.customer_id
สำหรับลูกค้าแต่ละราย EXISTS จะถามว่ามีคำสั่งซื้อของลูกค้ารายนี้อยู่หรือไม่ หากมี ก็เก็บลูกค้ารายนั้นไว้
SELECT c.customer_id, c.name
FROM customers c
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.customer_id
);เหตุใดจึงใช้ SELECT 1 ภายใน EXISTS
คุณจะเห็น SELECT 1, SELECT * หรือ SELECT NULL ภายใน EXISTS ทั้งหมดให้ผลเทียบเท่ากัน
EXISTS ตรวจสอบเพียงว่ามีแถวถูกส่งกลับมาหรือไม่ ไม่ได้ตรวจสอบเนื้อหาของแถว ดังนั้นคอลัมน์ที่เลือกส่งออกจึงไม่สำคัญ ตัวปรับประสิทธิภาพจะไม่สนใจคอลัมน์เหล่านั้น
SELECT 1 เป็นรูปแบบที่ใช้กันทั่วไปเพื่อสื่อเจตนาว่า "ฉันสนใจเพียงการมีอยู่เท่านั้น" เลือกใช้รูปแบบใดรูปแบบหนึ่งและใช้ให้สม่ำเสมอ อย่าปล่อยให้ผู้สัมภาษณ์เข้าใจว่ารายการคอลัมน์มีผลในกรณีนี้
NOT EXISTS ใช้ค้นหารายการที่ไม่มี
NOT EXISTS จะกลับด้านการตรวจสอบ โดยเก็บแถวภายนอกไว้เฉพาะเมื่อคิวรีย่อยแบบสัมพันธ์ไม่คืนแถวใดเลย
นี่คือการเชื่อมตารางเพื่อค้นหารายการที่ไม่มีแบบมาตรฐาน เช่น ลูกค้าที่ไม่มีคำสั่งซื้อ สินค้าที่ไม่เคยถูกขาย และนักเรียนที่ไม่มีการส่งงาน
SELECT c.customer_id, c.name
FROM customers c
WHERE NOT EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.customer_id
);กับดัก NULL ของ NOT IN
นี่คือประเด็นเด็ดในการสัมภาษณ์ NOT IN ที่ใช้กับคิวรีย่อยซึ่งอาจมีค่า NULL จะทำงานอย่างคาดไม่ถึงและอันตราย หากรายการนั้นมี NULL แม้เพียงหนึ่งค่า NOT IN จะไม่คืนแถวใดออกมาเลย
สาเหตุคือการเปรียบเทียบกับ NULL ให้ผลเป็น UNKNOWN และ NOT IN ต้องการให้การเปรียบเทียบทุกครั้งเป็น FALSE ค่า UNKNOWN เพียงค่าเดียวทำให้เงื่อนไขทั้งหมดใช้ไม่ได้
NOT EXISTS ไม่มีปัญหานี้ เพราะตรวจสอบเพียงการมีอยู่ของแถวและจัดการกับค่า NULL ได้อย่างปลอดภัย
-- Risky: returns nothing if any o.customer_id is NULL
SELECT c.customer_id FROM customers c
WHERE c.customer_id NOT IN (SELECT o.customer_id FROM orders o);
-- Safe: NULLs do not break it
SELECT c.customer_id FROM customers c
WHERE NOT EXISTS (
SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id
);เหตุใด NOT EXISTS จึงปลอดภัยกับ NULL
เหตุผลอยู่ที่ตรรกะการจับคู่ NOT EXISTS ตรวจสอบว่ามีแถวภายในใดที่ตรงตาม o.customer_id = c.customer_id หรือไม่
แถวที่ o.customer_id เป็น NULL จะไม่ตรงกับการเท่ากันนี้เลย (NULL = ค่าใด ๆ ให้ผลเป็น UNKNOWN ไม่ใช่ TRUE) ดังนั้นแถวนั้นจึงไม่นับเป็นรายการที่ตรงกัน การตรวจสอบการมีอยู่จึงยังคงถูกต้อง
สำหรับ NOT IN ค่า NULL เดียวกันนี้จะกลายเป็นส่วนหนึ่งของการเปรียบเทียบกับรายการ ซึ่งผลเป็น UNKNOWN และลบล้างผลลัพธ์ทั้งหมด นี่คือเหตุผลที่การคัดเลือกผู้สมัครระดับอาวุโสมักชอบ NOT EXISTS
EXISTS พร้อมเงื่อนไขเพิ่มเติม
ซับคิวรีแบบสัมพันธ์สามารถมีเงื่อนไขเพิ่มเติมได้ ค้นหาลูกค้าที่สั่งซื้ออย่างน้อยหนึ่งรายการซึ่งมีมูลค่ามากกว่า 1000
เงื่อนไขเพิ่มเติมอยู่ภายในซับคิวรี EXISTS และมีขอบเขตแยกตามลูกค้าแต่ละราย
SELECT c.customer_id, c.name
FROM customers c
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.customer_id
AND o.amount > 1000
);ประสิทธิภาพ: พฤติกรรมแบบหยุดทันที
EXISTS สามารถหยุดตรวจสอบรีเลชันด้านในทันทีที่พบแถวที่ตรงกันหนึ่งแถว โดยไม่ต้องสร้างหรือนับชุดผลลัพธ์ทั้งหมด
ด้วยเหตุนี้ EXISTS จึงมักมีประสิทธิภาพ โดยเฉพาะเมื่อคอลัมน์ที่ใช้เชื่อมโยงมีดัชนี เพราะการตรวจสอบของแต่ละแถวสามารถพบรายการที่ตรงกันได้อย่างรวดเร็วแล้วหยุดทันที
เปรียบเทียบกับ COUNT(*) > 0 แบบสัมพันธ์ ซึ่งบังคับให้นับรายการที่ตรงกันทุกรายการ ควรเลือกใช้ EXISTS เมื่อคุณต้องการเพียงคำตอบว่ามีหรือไม่มี
EXISTS เทียบกับ COUNT เพื่อทดสอบการมีอยู่
ผู้เข้าสัมภาษณ์บางคนอาจเขียนการนับแบบสัมพันธ์เพื่อทดสอบว่ามีข้อมูลอยู่หรือไม่ วิธีนี้ใช้ได้ แต่สิ้นเปลืองการประมวลผล
รูปแบบที่ใช้ COUNT จะนับคำสั่งซื้อที่ตรงกันทุกคำสั่งซื้อ ส่วน EXISTS จะหยุดหลังจากพบรายการแรก สำหรับการตรวจสอบการมีอยู่เพียงอย่างเดียว EXISTS สื่อเจตนาได้ชัดเจนและเปิดให้ตัวปรับประสิทธิภาพคิวรีหยุดตรวจสอบได้ทันที
-- Works but counts everything
SELECT c.customer_id FROM customers c
WHERE (SELECT COUNT(*) FROM orders o
WHERE o.customer_id = c.customer_id) > 0;
-- Better: stops at first match
SELECT c.customer_id FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o
WHERE o.customer_id = c.customer_id);ตัวอย่างที่ทำตามได้: สินค้าที่ไม่เคยถูกสั่งซื้อ
คำถามสัมภาษณ์คลาสสิกเกี่ยวกับการเชื่อมเพื่อค้นหาแถวที่ไม่ตรงกันคือ ให้แสดงรายการสินค้าที่ไม่เคยถูกสั่งซื้อ NOT EXISTS อ่านได้แทบเหมือนข้อกำหนดภาษาอังกฤษ
สำหรับสินค้าแต่ละรายการ ให้ตรวจสอบว่ามีรายการในคำสั่งซื้อใดอ้างถึงสินค้านั้นหรือไม่ แล้วเก็บไว้เฉพาะรายการที่ไม่พบเลย
SELECT p.product_id, p.name
FROM products p
WHERE NOT EXISTS (
SELECT 1
FROM order_items oi
WHERE oi.product_id = p.product_id
);EXISTS ใน NOT EXISTS สำหรับคิวรีแบบหาร
การซ้อน EXISTS ไว้ภายใน NOT EXISTS แสดงการหารเชิงสัมพันธ์: "ค้นหาแถวที่ตรงกับ ALL ของชุดข้อมูล" ตัวอย่างคำถามคลาสสิกคือ "ลูกค้าที่สั่งซื้อสินค้าทุกชนิดในหมวดหมู่หนึ่ง"
ตรรกะคือ เก็บลูกค้าไว้เมื่อไม่มีสินค้าใดที่ลูกค้าไม่ได้สั่งซื้อ การปฏิเสธซ้อนกันนี้เป็นลักษณะเด่นของคิวรีแบบหาร และผู้สัมภาษณ์ใช้ทดสอบความเข้าใจ EXISTS อย่างลึกซึ้ง
SELECT c.customer_id
FROM customers c
WHERE NOT EXISTS (
SELECT 1 FROM products p
WHERE p.category = 'Coffee'
AND NOT EXISTS (
SELECT 1 FROM order_items oi
JOIN orders o ON o.order_id = oi.order_id
WHERE oi.product_id = p.product_id
AND o.customer_id = c.customer_id
)
);ตรวจสอบด่วน
เลือกรูปแบบที่ปลอดภัยที่สุดในการค้นหาลูกค้าที่ไม่มีคำสั่งซื้อ
สรุป: EXISTS และ NOT EXISTS แบบสัมพันธ์
ประเด็นสำคัญ:
EXISTSคือการตรวจสอบการมีอยู่ในแต่ละแถว ซึ่งหยุดทันทีเมื่อพบรายการแรก คอลัมน์ที่เลือกภายในไม่มีผล (ใช้SELECT 1)NOT EXISTSคือการเชื่อมเพื่อค้นหาแถวที่ไม่ตรงกันซึ่งปลอดภัยต่อ NULL เมื่อต้องการค้นหาแถวที่ไม่มีรายการตรงกันNOT INที่มี NULL อยู่ในรายการจะคืนค่าเป็น ไม่พบแถวใดเลย ควรเลือกใช้NOT EXISTS- สำหรับการตรวจสอบการมีอยู่ EXISTS เหมาะกว่า
COUNT(*) > 0แบบสัมพันธ์ เพราะหยุดได้ตั้งแต่เนิ่น ๆ
ควรกล่าวถึงกับดัก NULL ของ NOT IN โดยไม่ต้องรอให้ผู้สัมภาษณ์ถาม เพราะเป็นสัญญาณที่เชื่อถือได้ว่าคุณมีวุฒิภาวะด้าน SQL
คำถามที่พบบ่อย
บทเรียน “EXISTS และ NOT EXISTS ที่สัมพันธ์กับคิวรีภายนอก” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “EXISTS และ NOT EXISTS ที่สัมพันธ์กับคิวรีภายนอก” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Coding Interview Prep ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Coding Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “EXISTS และ NOT EXISTS ที่สัมพันธ์กับคิวรีภายนอก”
ทางเลือกของการเชื่อมตารางแบบตัดออกที่แข็งแกร่งและจัดการ NULL ได้อย่างถูกต้อง คุณปฏิบัติ Coding Interview Prep ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Coding Interview Prep หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Coding Interview Prep บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “EXISTS และ NOT EXISTS ที่สัมพันธ์กับคิวรีภายนอก” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Coding Interview Prep นี้ได้ไหม
ได้ บทเรียน Coding Interview Prep ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- กายวิภาคของคิวรีย่อยที่สัมพันธ์กับคิวรีภายนอก
- ฟังก์ชันรวมแยกตามกลุ่มโดยไม่มี GROUP BY
- EXISTS และ NOT EXISTS ที่สัมพันธ์กับคิวรีภายนอก
- เขียนคิวรีย่อยที่สัมพันธ์กับคิวรีภายนอกใหม่เป็นการเชื่อมตาราง