← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

MySQL GROUP BY and Aggregates

database Intermediate

Also Known As

GROUP BY MySQL aggregate functions MySQL HAVING vs WHERE COUNT SUM AVG MySQL

TL;DR

GROUP BY collapses rows with matching column values into one — aggregate functions (COUNT, SUM, AVG, MAX, MIN) compute values per group.

Explanation

GROUP BY is used with aggregate functions to summarise data. MySQL's ONLY_FULL_GROUP_BY mode (default since 5.7) requires all SELECT columns to be in GROUP BY or wrapped in an aggregate — preventing non-deterministic results. HAVING filters groups after aggregation; WHERE filters rows before aggregation. ROLLUP adds subtotals. Window functions (MySQL 8) provide aggregation without collapsing rows.

Common Misconception

You can SELECT any column when using GROUP BY. Without ONLY_FULL_GROUP_BY enabled, MySQL silently returns a random value for un-aggregated, un-grouped columns.

Why It Matters

Selecting non-aggregated columns without ONLY_FULL_GROUP_BY returns a random value from the group — a silent correctness bug that produces different results on different MySQL versions.

Common Mistakes

  • Using WHERE to filter aggregate results instead of HAVING — WHERE runs before aggregation.
  • Selecting non-aggregated columns not in GROUP BY — non-deterministic on MySQL permissive mode.
  • GROUP BY on an unindexed column — triggers filesort in the EXPLAIN Extra column.

Avoid When

  • Do not use GROUP BY on an unindexed column for large tables — add an index to avoid filesort.
  • Do not use GROUP BY as a workaround for DISTINCT — they have different semantics.

When To Use

  • Use GROUP BY with COUNT/SUM/AVG for reporting and analytics queries.
  • Use HAVING to filter groups — e.g. users with more than 5 orders.

Code Examples

✗ Vulnerable
-- ONLY_FULL_GROUP_BY error in MySQL 5.7+
SELECT user_id, email, COUNT(*) AS orders
FROM orders
GROUP BY user_id; -- email not in GROUP BY or aggregate
✓ Fixed
SELECT user_id,
       COUNT(*)        AS order_count,
       SUM(total)      AS revenue,
       MAX(created_at) AS last_order
FROM orders
GROUP BY user_id
HAVING COUNT(*) > 5
ORDER BY revenue DESC;

Added 31 Mar 2026
Views 18
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 2 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Google 5 Perplexity 2 Unknown AI 2 Meta AI 1 ChatGPT 1 Ahrefs 1
crawler 11 crawler_json 1
DEV INTEL Tools & Severity
⚙ Fix effort: Low
⚡ Quick Fix
Every column in SELECT must appear in GROUP BY or be wrapped in an aggregate function — use HAVING to filter on aggregate results
📦 Applies To
web cli
🔗 Prerequisites
🔍 Detection Hints
SELECT with GROUP BY where some columns are not aggregated
Auto-detectable: ✓ Yes semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✓ Auto-fixable Fix: Low Context: Line

✓ schema.org compliant