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

กฎ GROUP BY สำหรับคอลัมน์ใน SELECT

เหตุใดทุกคอลัมน์ที่ไม่ใช่ฟังก์ชันรวมจึงต้องปรากฏใน GROUP BY และโหมด only-full-group-by

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

เหตุใดผู้สัมภาษณ์จึงเริ่มด้วย GROUP BY

GROUP BY คือจุดที่การสัมภาษณ์แยกผู้สมัครระดับต้นออกจากผู้สมัครระดับกลาง กฎข้อเดียวที่มักทดสอบมากที่สุดคือ ทุกคอลัมน์ในรายการ SELECT ของคุณต้องอยู่ภายในฟังก์ชันรวม หรือระบุไว้ใน GROUP BY

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

กลุ่มคืออะไรในความเป็นจริง

GROUP BY จะรวมหลายแถวให้เหลือหนึ่งแถวต่อคีย์ที่ไม่ซ้ำกัน หลังจากจัดกลุ่มแล้ว ระบบประมวลผลจะไม่มีแถวแต่ละแถวเหลืออยู่ มีเพียงแถวสรุปหนึ่งแถวต่อกลุ่มเท่านั้น

  • คอลัมน์ที่ใช้จัดกลุ่มจะมีค่าที่ชัดเจนเพียงหนึ่งค่าต่อกลุ่ม
  • ฟังก์ชันรวมอย่าง COUNT, SUM, AVG จะลดค่าจำนวนมากให้เหลือหนึ่งค่า
  • คอลัมน์ดิบอื่น ๆ จะกำกวม เพราะไม่ทราบว่าควรแสดงค่าจากแถวใด
SELECT department, COUNT(*) AS headcount
FROM employees
GROUP BY department;

ข้อผิดพลาดแบบคลาสสิก

นี่คือข้อผิดพลาดที่ผู้สัมภาษณ์ชื่นชอบ คุณจัดกลุ่มด้วย department แต่เลือก name ซึ่งเป็นคอลัมน์ที่ไม่ได้ผ่านฟังก์ชันรวมและไม่ได้อยู่ใน GROUP BY ด้วย

แต่ละแผนกมีพนักงานหลายคน จึงมีหลายชื่อต่อกลุ่ม ระบบประมวลผลไม่สามารถเลือกชื่อใดชื่อหนึ่งได้ ดังนั้น SQL ตามมาตรฐานจึงปฏิเสธคิวรี

-- ERROR: name is not in GROUP BY and not aggregated
SELECT department, name, COUNT(*)
FROM employees
GROUP BY department;

สองวิธีในการแก้ไข

มีวิธีแก้ไขที่ถูกต้องอยู่สองวิธี และผู้สัมภาษณ์ต้องการได้ยินว่าคุณรู้ว่าทั้งสองวิธีให้คำตอบแตกต่างกัน:

  • เพิ่มคอลัมน์ลงใน GROUP BY หากคุณต้องการจัดกลุ่มให้ละเอียดขึ้นจริง ๆ (หนึ่งแถวต่อแผนกและชื่อ)
  • ครอบคอลัมน์ด้วยฟังก์ชันรวม เช่น MAX(name) หรือ COUNT(name) หากคุณต้องการหนึ่งค่าต่อกลุ่มเดิม
-- Finer grouping
SELECT department, name, COUNT(*) AS rows_for_person
FROM employees
GROUP BY department, name;

ONLY_FULL_GROUP_BY ใน MySQL

กับดักยอดนิยมคือ MySQL รุ่นเก่าอนุญาตให้เลือกคอลัมน์ที่ไม่ได้อยู่ในกลุ่ม และส่งคืนค่าใดค่าหนึ่งจากกลุ่มโดยไม่แจ้งให้ทราบ ส่งผลให้รายงานผิดพลาดแต่ดูเหมือนถูกต้อง

MySQL รุ่นปัจจุบันเปิดใช้ ONLY_FULL_GROUP_BY เป็นค่าเริ่มต้น ซึ่งบังคับใช้กฎตามมาตรฐาน โพสต์เกรส, SQL Server และออราเคิลบังคับใช้กฎนี้มาโดยตลอด หากถูกถามว่าทำไมคิวรีจึง ‘ทำงานบนเซิร์ฟเวอร์เก่าแต่ตอนนี้กลับไม่ทำงาน’ นี่คือคำตอบ

-- Legal under ONLY_FULL_GROUP_BY because every
-- selected column is grouped or aggregated
SELECT department, MAX(hire_date) AS latest_hire
FROM employees
GROUP BY department;

ข้อยกเว้นจากการขึ้นต่อกันเชิงฟังก์ชัน

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

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

-- Legal: id is the PK, so name is determined by it
SELECT e.id, e.name, COUNT(o.id) AS orders
FROM employees e
LEFT JOIN orders o ON o.employee_id = e.id
GROUP BY e.id;

ตัวอย่าง: ยอดขายตามภูมิภาค

สมมติว่าคุณต้องจัดทำรายงานยอดขายรวมต่อภูมิภาค คีย์สำหรับจัดกลุ่มคือ region ส่วนค่าที่วัดคือ SUM(amount) ทุกสิ่งที่เหลือต้องผ่านการรวมค่าหรือตัดออก

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

SELECT region,
       SUM(amount)   AS total_sales,
       COUNT(*)      AS num_orders,
       AVG(amount)   AS avg_order
FROM sales
GROUP BY region;

การผสมรายละเอียดกับข้อมูลสรุป

โจทย์ที่มักใช้เป็นกลลวง: ‘แสดงยอดเงินของคำสั่งซื้อแต่ละรายการพร้อมยอดรวมของภูมิภาค’ คุณไม่สามารถทำเช่นนี้ด้วย GROUP BY แบบทั่วไปได้ เพราะการจัดกลุ่มจะทำลายแถวแต่ละรายการ

คำตอบที่ถูกต้องคือฟังก์ชันหน้าต่าง (SUM(amount) OVER (PARTITION BY region)) หรือเชื่อมกลับไปยังคิวรีย่อยที่จัดกลุ่มไว้ การตระหนักว่า GROUP BY เป็นเครื่องมือที่ไม่ถูกต้องสำหรับกรณีนี้คือประเด็นของคำถาม

-- Detail rows kept, region total added per row
SELECT order_id, region, amount,
       SUM(amount) OVER (PARTITION BY region) AS region_total
FROM sales;

GROUP BY กับชื่อแทนใน SELECT

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

  • MySQL และโพสต์เกรส: อนุญาตให้จัดกลุ่มด้วยชื่อแทนใน SELECT
  • SQL Server และออราเคิล: ไม่อนุญาต คุณต้องเขียนนิพจน์ทั้งหมดซ้ำ

คำตอบที่ใช้ข้ามระบบได้คือเขียนนิพจน์ซ้ำใน GROUP BY ซึ่งทำงานได้ทุกที่

-- Portable: repeat the expression rather than the alias
SELECT EXTRACT(YEAR FROM order_date) AS yr, COUNT(*)
FROM sales
GROUP BY EXTRACT(YEAR FROM order_date);

DISTINCT เทียบกับ GROUP BY เพื่อหาค่าที่ไม่ซ้ำ

หากคุณต้องการเพียงชุดค่าที่ไม่ซ้ำกันและไม่มีฟังก์ชันรวม GROUP BY ที่ไม่มีฟังก์ชันรวมจะทำงานเหมือน DISTINCT ผู้สัมภาษณ์อาจถามว่าวิธีใดสื่อความหมายได้ชัดเจนกว่า

ใช้ DISTINCT เพื่อสื่อเจตนาว่า ‘ฉันต้องการแถวที่ไม่ซ้ำกัน’ และเก็บ GROUP BY ไว้ใช้เมื่อคุณคำนวณค่ารวมด้วย ผลลัพธ์เหมือนกัน แต่สื่อความหมายและอ่านง่ายแตกต่างกัน

-- These return the same rows
SELECT DISTINCT department, role FROM employees;
SELECT department, role FROM employees GROUP BY department, role;

วิธีอธิบายในการสัมภาษณ์

เมื่อพบคำถามเกี่ยวกับ GROUP BY ให้อธิบายกฎออกมาดัง ๆ: ‘คอลัมน์ที่เลือกทุกคอลัมน์ต้องเป็นคีย์สำหรับจัดกลุ่มหรือถูกครอบด้วยฟังก์ชันรวม เพราะการจัดกลุ่มจะเหลือหนึ่งแถวต่อคีย์’

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

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจของคุณเกี่ยวกับกฎหลักของ GROUP BY

สรุปทบทวน

กฎ: ทุกคอลัมน์ใน SELECT ต้องเป็นคีย์การจัดกลุ่มหรือค่าที่ผ่านการรวม เหตุผล: GROUP BY จะเหลือหนึ่งแถวต่อคีย์ ดังนั้นคอลัมน์ดิบที่ไม่ได้จัดกลุ่มจึงมีความกำกวม

  • แก้การละเมิดกฎด้วยการจัดกลุ่มคอลัมน์นั้นหรือรวมค่าของคอลัมน์
  • พฤติกรรมเดิมของ MySQL จะคืนค่าแบบสุ่ม ส่วน ONLY_FULL_GROUP_BY จะบังคับใช้มาตรฐาน
  • การขึ้นต่อเชิงฟังก์ชันของคีย์หลักเป็นข้อยกเว้นทางกฎหมายเพียงกรณีเดียว
  • หากต้องการคงรายละเอียดของแถวไว้ข้างยอดรวมของกลุ่ม ให้ใช้ฟังก์ชันหน้าต่างแทน GROUP BY

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

บทเรียน “กฎ GROUP BY สำหรับคอลัมน์ใน SELECT” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “กฎ GROUP BY สำหรับคอลัมน์ใน SELECT”

เหตุใดทุกคอลัมน์ที่ไม่ใช่ฟังก์ชันรวมจึงต้องปรากฏใน GROUP BY และโหมด only-full-group-by คุณปฏิบัติ Coding Interview Prep ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

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

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

บทเรียน “กฎ GROUP BY สำหรับคอลัมน์ใน SELECT” ใช้เวลานานแค่ไหน

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

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

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

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

  1. กฎ GROUP BY สำหรับคอลัมน์ใน SELECT
  2. HAVING เทียบกับ WHERE
  3. จัดกลุ่มด้วยหลายคอลัมน์และนิพจน์
  4. นับและกรองกลุ่ม
← กลับไปที่ Coding Interview Prep