Based on the SQLD exam syllabusReport an error
If you put a condition in WHERE to find "departments whose average salary is over 2000", the query will not even run.
SELECT DEPTNO, AVG(SAL) FROM EMP WHERE AVG(SAL) > 2000 GROUP BY DEPTNO;SELECT DEPTNO, AVG(SAL) FROM EMP WHERE AVG(SAL) > 2000 GROUP BY DEPTNO
*
ERROR at line 1:
ORA-00934: group function is not allowed hereSELECT DEPTNO, ROUND(AVG(SAL)) AS AVG_SAL
FROM EMP
GROUP BY DEPTNO
HAVING AVG(SAL) > 2000
ORDER BY DEPTNO; DEPTNO AVG_SAL
---------- ----------
10 2917
20 2175HAVING MIN(SAL) > 1000.SELECT DEPTNO, MAX(SAL) FROM EMP GROUP BY DEPTNO HAVING MIN(SAL) > 1000 ORDER BY DEPTNO; DEPTNO MAX(SAL)
---------- ----------
10 5000The two clauses differ in what they filter and when.
| Aspect | WHERE | HAVING |
|---|---|---|
| What it filters | Rows | Groups |
| When it is processed | Before GROUP BY | After GROUP BY |
| Aggregate functions | Not allowed (ORA-00934) | Allowed |
| Plain columns allowed | Every column of the table | GROUP BY columns |
When you use both in one query, WHERE trims the rows first, the groups are made from the remaining rows, and then HAVING filters the groups. Looking at the result at each step makes the difference clear.
SELECT DEPTNO, COUNT(*) AS CNT FROM EMP GROUP BY DEPTNO HAVING COUNT(*) >= 5 ORDER BY DEPTNO; DEPTNO CNT
---------- ----------
20 5
30 6SELECT DEPTNO, COUNT(*) AS CNT FROM EMP WHERE SAL >= 1500 GROUP BY DEPTNO ORDER BY DEPTNO; DEPTNO CNT
---------- ----------
10 2
20 3
30 3SELECT DEPTNO, COUNT(*) AS CNT
FROM EMP
WHERE SAL >= 1500
GROUP BY DEPTNO
HAVING COUNT(*) >= 3
ORDER BY DEPTNO; DEPTNO CNT
---------- ----------
20 3
30 3SAL >= 1500: 8 of the 14 employees remain (KING, CLARK / JONES, SCOTT, FORD / ALLEN, BLAKE, TURNER).COUNT(*) >= 3: department 10, with 2 people, drops out.COUNT(*) in HAVING is not the original department headcount but the number of rows that passed WHERE. Department 30 originally has 6 people, but here it is 3.A condition on a GROUP BY column gives the same result whether you put it in WHERE or in HAVING.
SELECT DEPTNO, COUNT(*) FROM EMP WHERE DEPTNO <> 20 GROUP BY DEPTNO ORDER BY DEPTNO;SELECT DEPTNO, COUNT(*) FROM EMP GROUP BY DEPTNO HAVING DEPTNO <> 20 ORDER BY DEPTNO; DEPTNO COUNT(*)
---------- ----------
10 3
30 6A plain column that is not in GROUP BY cannot be used in HAVING. HAVING is the clause that looks at groups, so it cannot pick individual row values inside a group.
SELECT DEPTNO, COUNT(*) FROM EMP GROUP BY DEPTNO HAVING ENAME = 'KING';SELECT DEPTNO, COUNT(*) FROM EMP GROUP BY DEPTNO HAVING ENAME = 'KING'
*
ERROR at line 1:
ORA-00979: "ENAME": must appear in the GROUP BY clause or be used in an aggregate functionWHERE ENAME = 'KING'.In HAVING too, aggregate functions skip NULL. If you look for departments whose commission total is NULL, you find the departments with no commission at all.
SELECT DEPTNO FROM EMP GROUP BY DEPTNO HAVING SUM(COMM) IS NULL ORDER BY DEPTNO; DEPTNO
----------
10
20SUM(COMM) is also NULL. Department 30 has a total of 2200.HAVING can be used without GROUP BY. In that case the whole table (all the rows that passed WHERE) is a single group.
SELECT COUNT(*) FROM EMP HAVING COUNT(*) > 10; COUNT(*)
----------
14SELECT COUNT(*) FROM EMP HAVING COUNT(*) > 20;no rows selectedSQL is not processed in the order it is written (with SELECT first). Even if Oracle changes the execution plan internally, the result must be the same as if it had been processed in the order below.
⑤ SELECT DEPTNO, COUNT(*) AS CNT ← pick the columns to show and give them aliases
① FROM EMP ← the source table
② WHERE SAL >= 1500 ← filter rows
③ GROUP BY DEPTNO ← make groups
④ HAVING COUNT(*) >= 3 ← filter groups
⑥ ORDER BY CNT DESC ← sort| Order | Clause | What is visible at this step |
|---|---|---|
| 1 | FROM | Every column of the table |
| 2 | WHERE | Every column of the table (no aggregate results yet) |
| 3 | GROUP BY | Groups |
| 4 | HAVING | GROUP BY columns, aggregate results |
| 5 | SELECT | Calculated expressions, aliases are created here |
| 6 | ORDER BY | Up to SELECT aliases and position numbers |
This one table explains most of the errors we saw today.
An alias is created in the SELECT step. WHERE, which is processed earlier, does not know that name.
SELECT ENAME, SAL * 12 AS ANNUAL FROM EMP WHERE ANNUAL > 30000;SELECT ENAME, SAL * 12 AS ANNUAL FROM EMP WHERE ANNUAL > 30000
*
ERROR at line 1:
ORA-00904: "ANNUAL": invalid identifierSELECT ENAME, SAL * 12 AS ANNUAL
FROM EMP
WHERE SAL * 12 > 30000
ORDER BY ANNUAL DESC, ENAME;ENAME ANNUAL
---------- ----------
KING 60000
FORD 36000
SCOTT 36000
JONES 35700
BLAKE 34200⚠️ Note on the practice environment: The textbook uses the execution order to explain that SELECT aliases cannot be used in GROUP BY or HAVING either. The practice container used for these notes (an Oracle Database 23ai-family release) has a newer feature that allows
GROUP BY aliasandHAVING alias, so those run without errors. For the exam, it is safer to judge by the traditional rule that aliases cannot be used in WHERE, GROUP BY, or HAVING.
Here is what actually happened when we ran it in the practice container.
SELECT DEPTNO, COUNT(*) AS CNT FROM EMP GROUP BY DEPTNO HAVING CNT > 3 ORDER BY DEPTNO; DEPTNO CNT
---------- ----------
20 5
30 6GROUP BY 1) is not allowed in the default settings. In the container it raised ORA-03162.Total the salaries by job, leave out PRESIDENT, keep only the jobs whose total is over 5000, and show them from the largest total.
SELECT JOB, SUM(SAL) AS TOTAL
FROM EMP
WHERE JOB <> 'PRESIDENT'
GROUP BY JOB
HAVING SUM(SAL) > 5000
ORDER BY TOTAL DESC;JOB TOTAL
--------- ----------
MANAGER 8275
ANALYST 6000
SALESMAN 5600| Step | What it does | What remains |
|---|---|---|
| WHERE | Exclude KING | 13 rows |
| GROUP BY | Group by job | 4 groups: CLERK, SALESMAN, MANAGER, ANALYST |
| HAVING | Total over 5000 | CLERK (4150) is out, 3 groups |
| SELECT | JOB, and the alias TOTAL for the sum | |
| ORDER BY | TOTAL descending | 8275 → 6000 → 5600 |
PRESIDENT condition is about individual rows, so it goes in WHERE; the total condition is about groups, so it goes in HAVING.SUM(SAL) again.Tomorrow we cover ORDER BY, which sets the order of the results, and where NULL ends up when sorting.
Click a choice to reveal the answer and explanation.
Question 1
Which is the correct result of running the following SQL in Oracle? ```sql SELECT DEPTNO, AVG(SAL) FROM EMP WHERE AVG(SAL) > 2000 GROUP BY DEPTNO; ```
Question 2
Which of the following is the correct logical execution order of a SELECT statement?
Question 3
How many rows does the following SQL return? (The employees with SAL of 1500 or more are 2 in department 10, 3 in department 20, and 3 in department 30.) ```sql SELECT DEPTNO, COUNT(*) FROM EMP WHERE SAL >= 1500 GROUP BY DEPTNO HAVING COUNT(*) >= 3; ```
Question 4
Which is the correct result of running the following SQL in Oracle? ```sql SELECT ENAME, SAL * 12 AS ANNUAL FROM EMP WHERE ANNUAL > 30000; ```
Question 5
EMP has 14 rows. Which is the correct result of the following SQL? ```sql SELECT COUNT(*) FROM EMP HAVING COUNT(*) > 20; ```