หา Top N ค่าที่เกิดบ่อยที่สุดด้วย GROUP BY และ COUNT
ตัวอย่าง: วิชาที่นักเรียนเลือกมากที่สุด
CREATE TABLE DemoTable610 (SubjectName VARCHAR(100));
INSERT INTO DemoTable610 VALUES
('MySQL'), ('Java'), ('MySQL'), ('MongoDB'), ('MySQL'),
('MySQL'), ('Java'), ('MongoDB'), ('C'), ('C++'),
('MongoDB'), ('MySQL'), ('Java'), ('Python'), ('MySQL');
Query: หา Top 2 วิชาที่มีนักเรียนมากที่สุด
SELECT SubjectName
FROM (
SELECT SubjectName
FROM DemoTable610
GROUP BY SubjectName
ORDER BY COUNT(SubjectName) DESC
LIMIT 2
) AS tbl
ORDER BY SubjectName;
ผลลัพธ์: Java, MySQL (เรียง A-Z)
+-------------+
| SubjectName |
+-------------+
| Java |
| MySQL |
+-------------+
อธิบาย Logic
GROUP BY SubjectName- จับกลุ่มตามชื่อวิชาCOUNT(SubjectName)- นับจำนวนในแต่ละกลุ่มORDER BY COUNT(...) DESC- เรียงจากมากไปน้อยLIMIT 2- เอา 2 อันดับแรก- Outer Query
ORDER BY SubjectName- เรียงผลลัพธ์สุดท้ายตามตัวอักษร
รูปแบบที่ทันสมัยกว่า: Window Function (MySQL 8.0+)
WITH ranked AS (
SELECT
SubjectName,
COUNT(*) AS cnt,
ROW_NUMBER() OVER (ORDER BY COUNT(*) DESC) AS rn
FROM DemoTable610
GROUP BY SubjectName
)
SELECT SubjectName, cnt
FROM ranked
WHERE rn <= 2
ORDER BY SubjectName;
ตัวอย่าง: Top 3 พร้อมแสดง Count
SELECT SubjectName, COUNT(*) AS frequency
FROM DemoTable610
GROUP BY SubjectName
ORDER BY frequency DESC, SubjectName
LIMIT 3;
ข้อควรระวัง: Tie (คะแนนเท่ากัน)
LIMIT 2 จะตัดทิ้งค่าที่เท่ากันอันดับ 3 แม้จะมี Count เท่ากัน
ใช้ DENSE_RANK() แทน ROW_NUMBER() ถ้าต้องการรวม Tie:
WITH ranked AS (
SELECT SubjectName, COUNT(*) AS cnt,
DENSE_RANK() OVER (ORDER BY COUNT(*) DESC) AS dr
FROM DemoTable610
GROUP BY SubjectName
)
SELECT SubjectName, cnt FROM ranked WHERE dr <= 2;
Performance Tips
- Index บน
SubjectNameช่วย GROUP BY เร็วขึ้น - ตารางใหญ่: ใช้ Summary Table / Materialized View แทน Query จริงทุกครั้ง
COUNT(*)เร็วกว่าCOUNT(column)(นับทุกแถว ไม่เช็ค NULL)