Group By
Sql tutorial · PySpark.in
4.2 GROUP BY and HAVING in SQL
When working with large amounts of data, we often need to:
- Combine multiple rows into summarized results
- Calculate totals, averages, counts, etc.
- Filter grouped results
SQL provides the following clauses for this purpose:
- GROUP BY
- HAVING
GROUP BY
The GROUP BY clause is used to group rows that contain the same values in specified columns.
It is commonly used with aggregation functions such as:
- COUNT()
- SUM()
- AVG()
- MIN()
- MAX()
Syntax
```
hide
SELECT column_name,
aggregate_function(column_name)
FROM table_name
GROUP BY column_name;
```
Example Table — player_match_details
name | match_id | score |
|---|---|---|
David | 1 | 45 |
David | 2 | 60 |
Joseph | 1 | 70 |
Joseph | 2 | 46 |
Lokesh | 1 | 95 |
Lokesh | 2 | 91 |
Example: Calculate Total Score of Each Player
```
sql
CREATE TABLE player_match_details (
match_id INT,
name VARCHAR(50),
score INT
);
INSERT INTO player_match_details (match_id, name, score)
VALUES
(1, 'David', 45),
(2, 'David', 60),
(3, 'Joseph', 70),
(4, 'Joseph', 46),
(5, 'Lokesh', 95),
(6, 'Lokesh', 91);
SELECT name,
SUM(score) AS total_score
FROM player_match_details
GROUP BY name;
```
Output
name | total_score |
|---|---|
David | 105 |
Joseph | 116 |
Lokesh | 186 |
How GROUP BY Works
Step 1 — Original Data
name | score |
|---|---|
David | 45 |
David | 60 |
Joseph | 70 |
Joseph | 46 |
Lokesh | 95 |
Lokesh | 91 |
↓
Step 2 — Rows Are Grouped by name
Group |
|---|
David → (45, 60) |
Joseph → (70, 46) |
Lokesh → (95, 91) |
↓
Step 3 — SUM(score) Is Applied
name | total_score |
|---|---|
David | 105 |
Joseph | 116 |
Lokesh | 186 |
GROUP BY with WHERE
The WHERE clause is used to filter rows before grouping happens.
This means only the filtered rows participate in aggregation.
Syntax
```
hide
SELECT column_name,
aggregate_function(column_name)
FROM table_name
WHERE condition
GROUP BY column_name;
```
Example: Count Half Centuries Scored by Each Player
A half century means a score greater than or equal to 50.
```
sql
SELECT name,
COUNT(*) AS half_centuries
FROM player_match_details
WHERE score >= 50
GROUP BY name;
```
Output
name | half_centuries |
|---|---|
David | 1 |
Joseph | 1 |
Lokesh | 2 |
Execution Flow
Step 1 — Apply WHERE Condition
```
hide
WHERE score >= 50
```
Filtered rows:
name | score |
|---|---|
David | 60 |
Joseph | 70 |
Lokesh | 95 |
Lokesh | 91 |
↓
Step 2 — GROUP BY name
Group |
|---|
David → (60) |
Joseph → (70) |
Lokesh → (95, 91) |
↓
Step 3 — COUNT Rows
name | half_centuries |
|---|---|
David | 1 |
Joseph | 1 |
Lokesh | 2 |
HAVING Clause
The HAVING clause is used to filter grouped data after GROUP BY is applied.
Unlike WHERE, HAVING works on aggregated results.
Syntax
```
hide
SELECT column_name,
aggregate_function(column_name)
FROM table_name
GROUP BY column_name
HAVING condition;
```
Example: Players with More Than One Half Century
```
sql
SELECT name,
COUNT(*) AS half_centuries
FROM player_match_details
WHERE score >= 50
GROUP BY name
HAVING COUNT(*) > 1;
```
Output
name | half_centuries |
|---|---|
Lokesh | 2 |
Execution Flow
Step 1 — WHERE Filters Rows
```
hide
WHERE score >= 50
```
name | score |
|---|---|
David | 60 |
Joseph | 70 |
Lokesh | 95 |
Lokesh | 91 |
↓
Step 2 — GROUP BY Creates Groups
Group |
|---|
David → (60) |
Joseph → (70) |
Lokesh → (95, 91) |
↓
Step 3 — COUNT Aggregation
name | half_centuries |
|---|---|
David | 1 |
Joseph | 1 |
Lokesh | 2 |
↓
Step 4 — HAVING Filters Groups
```
hide
HAVING COUNT(*) > 1
```
Final Result:
name | half_centuries |
|---|---|
Lokesh | 2 |
WHERE vs HAVING
Feature | WHERE | HAVING |
|---|---|---|
Used On | Individual rows | Groups |
Applied Before/After GROUP BY | Before | After |
Can Use Aggregate Functions? | No | Yes |
Purpose | Filter rows | Filter grouped results |
Important Difference
WHERE Filters Rows Before Grouping
```
sql
SELECT name, SUM(score)
FROM player_match_details
WHERE score > 50
GROUP BY name;
```
Only rows with score > 50 are grouped.
HAVING Filters Groups After Aggregation
```
sql
SELECT name, SUM(score) AS total_score
FROM player_match_details
GROUP BY name
HAVING SUM(score) > 100;
```
Here:
- Rows are grouped first
- Total score is calculated
- Groups with total score greater than 100 are displayed
Output
name | total_score |
|---|---|
David | 105 |
Joseph | 116 |
Lokesh | 186 |
Order of Execution in SQL Query
Understanding execution order is very important.
SQL executes queries in this order:
FROM
→ WHERE
→ GROUP BY
→ HAVING
→ SELECT
→ ORDER BY
More Sql tutorials
All tutorials · Try the free PySpark compiler · Practice challenges