Skip to content

GROUP BY & HAVING

GROUP BY — จัดกลุ่มแล้ว Aggregate

Section titled “GROUP BY — จัดกลุ่มแล้ว Aggregate”

GROUP BY แบ่งแถวออกเป็นกลุ่มตามค่าของคอลัมน์ แล้วทำ aggregate แยกตามกลุ่ม

เหมือนใช้ Pivot Table — ลากคอลัมน์ไปเป็น Row แล้วเลือก SUM/COUNT ใน Values

กฎสำคัญ: SELECT กับ GROUP BY

Section titled “กฎสำคัญ: SELECT กับ GROUP BY”
-- ถูกต้อง: active อยู่ใน GROUP BY, COUNT เป็น aggregate
SELECT active, COUNT(*) FROM students GROUP BY active;
-- error! name ไม่ได้อยู่ใน GROUP BY และไม่ใช่ aggregate
SELECT active, name, COUNT(*) FROM students GROUP BY active;
-- ERROR: column "name" must appear in GROUP BY clause

GROUP BY หลายคอลัมน์

Section titled “GROUP BY หลายคอลัมน์”
-- จัดกลุ่มตาม active และปีที่สมัคร
SELECT active,
EXTRACT(YEAR FROM enrolled_on) AS enroll_year,
COUNT(*) AS num_students,
SUM(price) AS total_price
FROM students
GROUP BY active, EXTRACT(YEAR FROM enrolled_on)
ORDER BY active DESC, enroll_year;

ผลลัพธ์:

activeenroll_yearnum_studentstotal_price
TRUE202419500.00
TRUE2025312200.00
FALSE202417800.00
FALSE202512100.00

HAVING กรองผลลัพธ์หลังจาก GROUP BY — ใช้เมื่อต้องการกรองตามค่า aggregate

-- เฉพาะกลุ่มที่มีนักเรียนมากกว่า 1 คน
SELECT active,
COUNT(*) AS num_students
FROM students
GROUP BY active
HAVING COUNT(*) > 1;
WHEREHAVING
กรอง แถว ก่อน GROUP BYกรอง กลุ่ม หลัง GROUP BY
ใช้กับคอลัมน์ปกติใช้กับ aggregate function
ทำงานก่อนทำงานทีหลัง
-- WHERE กรองแถว + HAVING กรองกลุ่ม
SELECT active,
COUNT(*) AS num_students,
AVG(price) AS avg_price
FROM students
WHERE enrolled_on >= '2025-01-01' -- กรองแถว: เฉพาะปี 2025+
GROUP BY active
HAVING AVG(price) > 3000; -- กรองกลุ่ม: เฉลี่ยเกิน 3000

ตัวอย่างจริง: สรุปรายเดือน

Section titled “ตัวอย่างจริง: สรุปรายเดือน”
SELECT EXTRACT(MONTH FROM enrolled_on) AS month,
COUNT(*) AS signups,
SUM(price) AS revenue
FROM students
WHERE enrolled_on >= '2025-01-01'
GROUP BY EXTRACT(MONTH FROM enrolled_on)
HAVING SUM(price) > 2000
ORDER BY month;