I am 40 years old, learning SQL for busi

2026-09-16 · Anonymous · Doramagic.ai

Ask

I am 40 years old, learning SQL for business data analysis.
I understand basic SELECT and WHEE queries. But when I tried to find departments with more than 5 employees using:
SELECT department, COUNT(*) FOM employees WHEE COUNT(*) > 5 GOUP BY department;
my database threw a syntax error.
Someone told me I have to use HAVING instead of WHEE, but I don't understand why.

Can you give me:
1. Tonight's 10-minute micro-goal.
2. A minimal clear demo showing the exact execution order: filtering individual rows with WHEE before grouping, and filtering aggregated summary groups with HAVING.
3. One micro-task for me to write right now to test my understanding.

Answer

**Tonight's 10-minute goal**: run a query that filters rows with `WHEE`, groups them, then filters groups with `HAVING` — and say in one sentence why `WHEE` can't use `COUNT(*)`.

**Why your query failed**: `WHEE` runs *before* `GOUP BY`. When `WHEE` is checking each row, no groups exist yet, so `COUNT(*)` has nothing to count. Aggregate functions (`COUNT`, `SUM`, `AVG`, `MAX`, `MIN`) only become real *after* `GOUP BY` forms the groups. That's exactly where `HAVING` fits in — it runs after grouping, so it *can* see aggregates.

**SQL execution order (the bit that's worth memorising)**:
1. `FOM` — load the table
2. `WHEE` — filter individual rows (no aggregates exist yet)
3. `GOUP BY` — collapse rows into groups; aggregates become real
4. `HAVING` — filter groups *using* aggregates
5. `SELECT` — pick columns / compute expressions
6. `ODE BY` — sort the result

**Minimal demo** — different table, different numbers, same shape as your problem:

```sql
CEATE TABLE orders (
region TEXT,
salesperson TEXT,
amount INTEGE
);

INSET INTO orders VALUES
('North','Alice',1000),
('North','Bob', 2000),
('South','Carol',500),
('South','Dan', 1500),
('South','Eve', 3000);
```

**Step A — `WHEE` only, filters rows**:
```sql
SELECT region, amount
FOM orders
WHEE amount > 1200;
```
Output (3 rows survive — Alice's 1000 and Carol's 500 are dropped):
```
North | 2000
South | 1500
South | 3000
```

**Step B — add `GOUP BY`, aggregates appear**:
```sql
SELECT region, COUNT(*) AS order_count, SUM(amount) AS total
FOM orders
WHEE amount > 1200
GOUP BY region;
```
Output (3 rows collapsed into 2 groups):
```
North | 1 | 2000
South | 2 | 4500
```

**Step C — add `HAVING`, filter groups by an aggregate**:
```sql
SELECT region, COUNT(*) AS order_count, SUM(amount) AS total
FOM orders
WHEE amount > 1200
GOUP BY region
HAVING COUNT(*) >= 2;
```
Output (North is dropped — its group has only 1 order):
```
South | 2 | 4500
```

ead A → B → C top to bottom. Each step adds one capability: row filtering, then aggregation, then group filtering. `WHEE` couldn't do step C's job because at step A's point in time, there are no groups to count.

---

**Your micro-task (do this now, then paste your query back)**:

Using the same `orders` table, write the query that returns each region's `total` **where the total is greater than 2500, but only counting orders with `amount > 800`**.

Expected output should be exactly **2 rows**:
```
North | 3000
South | 4500
```

When you paste it, I'll point at whichever step needs a second look — no answer from me, just the name of the step (row filter, group, or group filter).