HAVING เทียบกับ WHERE
การกรองก่อนจัดกลุ่มเทียบกับหลังจัดกลุ่ม และส่วนคำสั่งใดมองเห็นค่ารวม
HAVING เทียบกับ WHERE เป็นบทเรียน Coding Interview Prep ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Coding Interview Prep และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Coding Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน
คำถามที่คุณจะได้รับ
คำถามว่า ‘WHERE และ HAVING แตกต่างกันอย่างไร’ เป็นหนึ่งในคำถามสัมภาษณ์งานด้านเอสคิวแอลที่ถูกถามบ่อยที่สุด คำตอบที่ยังไม่ดีพอคือ ‘HAVING ใช้กับค่ารวม’ ส่วนคำตอบที่ดีจะอธิบายว่า แต่ละส่วนคำสั่งทำงานเมื่อใด ในกระบวนการประมวลผลของคำสั่งสอบถาม
ช่วงเวลานั้นคือหัวใจทั้งหมด: WHERE กรองแถว ก่อนการจัดกลุ่ม ส่วน HAVING กรองกลุ่ม หลังการรวมค่า
ตำแหน่งในลำดับการทำงาน
ทบทวนลำดับการทำงานเชิงตรรกะของคำสั่งสอบถาม:
FROM/JOIN→ สร้างชุดแถวWHERE→ กรองแถวแต่ละแถวGROUP BY→ รวมแถวให้เป็นกลุ่มHAVING→ กรองกลุ่มSELECT→ เลือกคอลัมน์ORDER BY→ เรียงลำดับ
WHERE ทำงานก่อนที่กลุ่มจะมีอยู่ ส่วน HAVING ทำงานภายหลัง ดังนั้น HAVING จึงมองเห็นค่ารวมได้ แต่ WHERE มองไม่เห็น
WHERE มองไม่เห็นค่ารวม
เนื่องจาก WHERE ทำงานก่อนการจัดกลุ่ม จึงยังไม่มีค่ารวมให้ใช้ การเขียน WHERE COUNT(*) > 5 ถือเป็นข้อผิดพลาดทางไวยากรณ์ในฐานข้อมูลมาตรฐานทุกระบบ
ผู้สัมภาษณ์มักใส่บรรทัดนี้มาโดยเฉพาะเพื่อทดสอบว่าคุณเข้าใจกระบวนการประมวลผลหรือไม่ ค่ารวมยังไม่มีอยู่ในขณะที่ WHERE ถูกประเมินผล
-- ERROR: aggregate not allowed in WHERE
SELECT department, COUNT(*)
FROM employees
WHERE COUNT(*) > 5
GROUP BY department;HAVING กรองกลุ่ม
ย้ายเงื่อนไขเกี่ยวกับค่ารวมไปไว้ใน HAVING แล้วคำสั่งจะทำงานได้ เพราะ HAVING ทำงานหลังจากสร้างกลุ่มและคำนวณค่ารวมของกลุ่มแล้ว
ให้ตีความว่า ‘จัดกลุ่มพนักงานก่อน แล้วเก็บไว้เฉพาะแผนกที่มีจำนวนมากกว่าห้า’
SELECT department, COUNT(*) AS headcount
FROM employees
GROUP BY department
HAVING COUNT(*) > 5;ใส่ตัวกรองแถวไว้ใน WHERE
ข้อผิดพลาดในทางกลับกันคือการกรองแถวดิบด้วย HAVING แม้มักให้คำตอบถูกต้อง แต่จะ ช้ากว่าและทำให้เข้าใจผิด เพราะคุณจัดกลุ่มแถวที่ตั้งใจจะทิ้งไปแล้ว
หลักจำง่าย ๆ: กรองจาก ค่าของคอลัมน์ดิบ → WHERE กรองจาก ค่ารวม → HAVING การกรองแถวตั้งแต่เนิ่น ๆ จะลดปริมาณข้อมูลที่การจัดกลุ่มต้องประมวลผล
-- Better: drop inactive rows BEFORE grouping
SELECT department, COUNT(*) AS headcount
FROM employees
WHERE status = 'active'
GROUP BY department
HAVING COUNT(*) > 5;ใช้ทั้งสองส่วนคำสั่งร่วมกัน
คำสั่งสอบถามที่สมบูรณ์มักใช้ทั้งสองส่วนคำสั่ง WHERE จะจำกัดแถวก่อน จากนั้น HAVING จะเก็บเฉพาะกลุ่มที่ตรงตามเงื่อนไข การอ่านจากบนลงล่างสอดคล้องกับลำดับการทำงานเชิงตรรกะ
ตัวอย่าง: จากคำสั่งซื้อที่ทำรายการในปีนี้ ให้ค้นหาลูกค้าที่ใช้จ่ายรวมมากกว่า 1000
SELECT customer_id, SUM(amount) AS total_spent
FROM orders
WHERE order_date >= '2024-01-01'
GROUP BY customer_id
HAVING SUM(amount) > 1000;HAVING กับคอลัมน์ที่ไม่ได้รวมค่า
HAVING สามารถอ้างอิงคอลัมน์ที่ใช้จัดกลุ่มได้ ไม่ได้จำกัดเฉพาะค่ารวมเท่านั้น HAVING department = 'Sales' เป็นคำสั่งที่ถูกต้อง แต่ไม่มีประโยชน์ เพราะควรใส่ตัวกรองนี้ไว้ใน WHERE เพื่อให้ทำงานเร็วกว่า
หากผู้สัมภาษณ์แสดง HAVING ที่กรองคอลัมน์ธรรมดาซึ่งใช้จัดกลุ่ม คำวิจารณ์ที่คาดหวังคือ ‘ย้ายไปไว้ใน WHERE เพื่อเพิ่มประสิทธิภาพ’
-- Works but inefficient; prefer WHERE department = 'Sales'
SELECT department, COUNT(*)
FROM employees
GROUP BY department
HAVING department = 'Sales';HAVING โดยไม่มี GROUP BY
กรณีที่ละเอียดอ่อนคือ HAVING สามารถใช้ได้แม้ไม่มี GROUP BY ทั้งตารางจะกลายเป็นกลุ่มโดยนัยเพียงกลุ่มเดียว และ HAVING จะกรองกลุ่มนั้น
หากเงื่อนไขค่ารวมเป็นเท็จ คุณจะได้ ศูนย์แถว แต่หากเป็นจริง คุณจะได้หนึ่งแถว กรณีนี้ไม่ค่อยมีประโยชน์นัก แต่ผู้สัมภาษณ์มักถามเพื่อยืนยันว่าคุณเข้าใจแนวคิดเรื่องกลุ่มโดยนัย
-- Returns the count only if the table has > 100 rows
SELECT COUNT(*) AS total
FROM orders
HAVING COUNT(*) > 100;HAVING ใช้ชื่อแทนจาก SELECT ได้หรือไม่
เช่นเดียวกับกลเม็ดเรื่องขอบเขตของชื่อแทนในส่วนอื่น ระบบฐานข้อมูลแต่ละแบบมีพฤติกรรมต่างกัน โพสต์เกรสและ MySQL อนุญาตให้ HAVING อ้างอิงชื่อแทนจาก SELECT ได้ ส่วน เซิร์ฟเวอร์เอสคิวแอลและออราเคิล ไม่อนุญาต
แนวทางที่ใช้ได้กับทุกระบบคือเขียนนิพจน์ค่ารวมซ้ำใน HAVING วิธีนี้ทำงานได้กับทุกกลไกฐานข้อมูลและช่วยหลีกเลี่ยงปัญหาในการสัมภาษณ์ที่ครอบคลุมหลายฐานข้อมูล
-- Portable: repeat the aggregate, do not rely on the alias
SELECT region, SUM(amount) AS total
FROM sales
GROUP BY region
HAVING SUM(amount) > 5000;มุมมองด้านประสิทธิภาพ
หากต้องการตอบให้โดดเด่น ให้เชื่อมโยงส่วนคำสั่งเข้ากับประสิทธิภาพ: WHERE ลดจำนวนแถวที่กลไกจัดกลุ่มต้องสแกนและสามารถใช้ดัชนีได้ ส่วน HAVING ทำงานกับกลุ่มที่รวมค่าแล้ว จึงไม่สามารถลดต้นทุนการจัดกลุ่มได้
ประเด็นที่ผู้สัมภาษณ์ต้องการฟังคือ เลื่อนตัวกรองทุกตัวไปไว้ให้เร็วที่สุดเท่าที่ทำได้ เฉพาะเงื่อนไขที่ขึ้นอยู่กับค่ารวมจริง ๆ เท่านั้นที่ต้องใช้ HAVING
คำตอบหนึ่งประโยค
จดจำประโยคนี้ไว้สำหรับการสัมภาษณ์: ‘WHERE กรองแถวก่อนการจัดกลุ่มและมองไม่เห็นค่ารวม ส่วน HAVING กรองกลุ่มหลังการรวมค่า และเป็นส่วนคำสั่งเดียวที่ใช้ตรวจสอบค่ารวมได้’
ตามด้วยรายการลำดับการทำงาน เพียงเท่านี้คุณก็จะให้คำตอบที่ครบถ้วนและฟังดูเป็นมืออาชีพ
ตรวจสอบความเข้าใจอย่างรวดเร็ว
ตัดสินใจว่าแต่ละเงื่อนไขควรอยู่ในส่วนคำสั่งใด
สรุปทบทวน
WHERE: กรองแถวก่อน GROUP BY และห้ามใช้ค่ารวม HAVING: กรองกลุ่มหลังการรวมค่า และเป็นตำแหน่งเดียวที่อนุญาตให้ใช้เงื่อนไขค่ารวม
- ใส่ตัวกรองคอลัมน์ดิบไว้ใน WHERE เพื่อความเร็วและการใช้ดัชนี
- HAVING สามารถอ้างอิงคอลัมน์ที่จัดกลุ่มได้ แต่ไม่ควรใช้กับตัวกรองทั่วไป
- HAVING ทำงานได้โดยไม่มี GROUP BY โดยใช้กลุ่มโดยนัยของทั้งตาราง
- เขียนนิพจน์ค่ารวมซ้ำใน HAVING เพื่อความปลอดภัยเมื่อใช้กับระบบฐานข้อมูลหลายแบบ
คำถามที่พบบ่อย
บทเรียน “HAVING เทียบกับ WHERE” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “HAVING เทียบกับ WHERE” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Coding Interview Prep ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Coding Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “HAVING เทียบกับ WHERE”
การกรองก่อนจัดกลุ่มเทียบกับหลังจัดกลุ่ม และส่วนคำสั่งใดมองเห็นค่ารวม คุณปฏิบัติ Coding Interview Prep ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Coding Interview Prep หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Coding Interview Prep บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “HAVING เทียบกับ WHERE” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Coding Interview Prep นี้ได้ไหม
ได้ บทเรียน Coding Interview Prep ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- กฎ GROUP BY สำหรับคอลัมน์ใน SELECT
- HAVING เทียบกับ WHERE
- จัดกลุ่มด้วยหลายคอลัมน์และนิพจน์
- นับและกรองกลุ่ม