Based on the SQLD exam syllabusReport an error
WITH name AS (subquery) is a notation that gives an inline view a name and pulls it out to the front of the statement.Most of yesterday's subqueries could run on their own, independent of the outside. (SELECT AVG(SAL) FROM EMP) gives 2073.21… even if you detach it and run it. This kind of subquery is a non-correlated subquery.
"Employees who earn more than their own department's average" is different. The department whose average is needed changes with every outer row.
SELECT E.ENAME, E.DEPTNO, E.SAL FROM EMP E WHERE E.SAL > (SELECT AVG(S.SAL) FROM EMP S WHERE S.DEPTNO = E.DEPTNO) ORDER BY E.DEPTNO, E.ENAME;ENAME DEPTNO SAL
---------- ---------- ----------
KING 10 5000
FORD 20 3000
JONES 20 2975
SCOTT 20 3000
ALLEN 30 1600
BLAKE 30 2850E.DEPTNO inside the subquery is a column of the main query. With this reference, it is a correlated subquery.E.DEPTNO is.| Type | Non-correlated subquery | Correlated subquery |
|---|---|---|
| References an outer column | No | Yes |
| Number of executions (conceptually) | Once. The result is passed to the main query | Re-evaluated for every main query row |
| Execution order | Subquery → main query | Read a main query row → run the subquery with that value |
| Runs on its own | Yes | No |
The same pattern also finds "the top earner in each department". It gives the same result as yesterday's multi-column subquery (DEPTNO, SAL) IN (...).
SELECT E.ENAME, E.SAL FROM EMP E WHERE E.SAL = (SELECT MAX(SAL) FROM EMP S WHERE S.DEPTNO = E.DEPTNO) ORDER BY E.ENAME;ENAME SAL
---------- ----------
BLAKE 2850
FORD 3000
KING 5000
SCOTT 3000= does not raise ORA-01427.EXISTS is almost always used as a correlated subquery. Here is the number of employees who have at least one subordinate, that is, the number of managers.
SELECT COUNT(*) FROM EMP E WHERE EXISTS (SELECT 1 FROM EMP M WHERE M.MGR = E.EMPNO); COUNT(*)
----------
6A scalar subquery is a subquery placed where a single value belongs. It is mostly used in the SELECT clause, and its result must be one row and one column. Here we attach the headcount of each department, based on DEPT.
SELECT D.DNAME, (SELECT COUNT(*) FROM EMP E WHERE E.DEPTNO = D.DEPTNO) AS CNT FROM DEPT D ORDER BY D.DEPTNO;DNAME CNT
-------------- ----------
ACCOUNTING 3
RESEARCH 5
SALES 6
OPERATIONS 0D.DEPTNO, it is also a correlated subquery.COUNT(*) returns 0. The result stays at 4 rows, based on DEPT.It is also used to fetch the name for a code value instead of using a join.
SELECT E.ENAME, (SELECT D.DNAME FROM DEPT D WHERE D.DEPTNO = E.DEPTNO) AS DNAME FROM EMP E WHERE E.JOB = 'MANAGER' ORDER BY E.ENAME;ENAME DNAME
---------- --------------
BLAKE SALES
CLARK ACCOUNTING
JONES RESEARCH| Subquery result | Value of the scalar subquery |
|---|---|
| 1 row, 1 column | That value |
| 0 rows | NULL (not an error) |
| 2 or more rows | ORA-01427 |
| 2 or more columns | ORA-00913 |
With 0 rows, it becomes NULL. If you look for the PRESIDENT in each department, there is no row to find in any department other than 10.
SELECT D.DNAME, (SELECT E.ENAME FROM EMP E WHERE E.DEPTNO = D.DEPTNO AND E.JOB = 'PRESIDENT') AS PRES FROM DEPT D ORDER BY D.DEPTNO;DNAME PRES
-------------- ----------
ACCOUNTING KING
RESEARCH
SALES
OPERATIONSMAX, even an empty set produces 1 row (with value NULL). The result is the same NULL, but note that COUNT returns 0 (W4 Day 1).If a department has several employees, you cannot pick a single ENAME.
SELECT D.DNAME, (SELECT ENAME FROM EMP E WHERE E.DEPTNO = D.DEPTNO) AS ENAME FROM DEPT D;SELECT D.DNAME, (SELECT ENAME FROM EMP E WHERE E.DEPTNO = D.DEPTNO) AS ENAME FROM DEPT D
*
ERROR at line 1:
ORA-01427: single-row subquery returns more than one rowReturning two columns cannot go in a single-value slot either. Only KING earns 5000 or more, so there is 1 row, but it has 2 columns.
SELECT D.DNAME, (SELECT ENAME, SAL FROM EMP E WHERE E.DEPTNO = D.DEPTNO AND E.SAL >= 5000) AS X FROM DEPT D;SELECT D.DNAME, (SELECT ENAME, SAL FROM EMP E WHERE E.DEPTNO = D.DEPTNO AND E.SAL >= 5000) AS X FROM DEPT D
*
ERROR at line 1:
ORA-00913: too many values⚠️ Pitfall: If a scalar subquery returns 0 rows, the result is NULL, not an error. An error occurs only when it returns 2 or more rows (ORA-01427) or 2 or more columns (ORA-00913).
A subquery placed in the FROM clause is called an inline view. Its result is used on the spot like a temporary table. Here we build the department averages as an inline view and join it with EMP.
SELECT E.ENAME, E.SAL, A.AVG_SAL FROM EMP E, (SELECT DEPTNO, ROUND(AVG(SAL)) AS AVG_SAL FROM EMP GROUP BY DEPTNO) A WHERE E.DEPTNO = A.DEPTNO AND E.SAL > A.AVG_SAL ORDER BY E.ENAME;ENAME SAL AVG_SAL
---------- ---------- ----------
ALLEN 1600 1567
BLAKE 2850 1567
FORD 3000 2175
JONES 2975 2175
KING 5000 2917
SCOTT 3000 2175AVG_SAL can be shown as a result column. The value of a WHERE-clause subquery cannot be pulled out into the SELECT.A is a table with 3 rows (the number of departments), and it is joined to the 14 rows of EMP on DEPTNO.Outside the inline view, you can reference only the column names produced by the inner SELECT. If you give an expression an alias, that alias becomes the column name.
SELECT DEPTNO, AVG_SAL FROM (SELECT DEPTNO, ROUND(AVG(SAL)) AS AVG_SAL FROM EMP GROUP BY DEPTNO) WHERE AVG_SAL > 2000 ORDER BY DEPTNO; DEPTNO AVG_SAL
---------- ----------
10 2917
20 2175A column that was not SELECTed inside is not visible outside.
SELECT X.ENAME FROM (SELECT ENAME FROM EMP WHERE DEPTNO = 10) X WHERE X.SAL > 1000;SELECT X.ENAME FROM (SELECT ENAME FROM EMP WHERE DEPTNO = 10) X WHERE X.SAL > 1000
*
ERROR at line 1:
ORA-00904: "X"."SAL": invalid identifierYou also use an inline view when you want to use a SELECT alias in WHERE. A WHERE at the same query level is processed before SELECT, so it does not know the alias.
SELECT ENAME, SAL * 12 AS ANNUAL FROM EMP WHERE ANNUAL >= 36000;SELECT ENAME, SAL * 12 AS ANNUAL FROM EMP WHERE ANNUAL >= 36000
*
ERROR at line 1:
ORA-00904: "ANNUAL": invalid identifierSELECT ENAME, ANNUAL FROM (SELECT ENAME, SAL * 12 AS ANNUAL FROM EMP) WHERE ANNUAL >= 36000 ORDER BY ANNUAL DESC, ENAME;ENAME ANNUAL
---------- ----------
KING 60000
FORD 36000
SCOTT 36000ANNUAL is visible.X, A). In Oracle, you do not use AS before a table alias.An inline view is used only within its own statement. To use the same SELECT in several places, you give it a name and store it in the database. This is a view.
CREATE VIEW view_name AS
SELECT statement;
CREATE OR REPLACE VIEW V_EMP10 AS
SELECT EMPNO, ENAME, JOB FROM EMP WHERE DEPTNO = 10;
SELECT * FROM V_EMP10; -- Query it like a table
DROP VIEW V_EMP10; -- Drops only the view definition. The EMP data is untouchedCREATE OR REPLACE changes the definition if a view with the same name already exists. A view's definition is not modified with ALTER VIEW.| Advantage | Description | In the case of V_EMP10 |
|---|---|---|
| Independence | Even if the table structure changes, you can fix only the view definition and leave the code that uses the view as is | Even if an EMP column name changes, only the V_EMP10 definition is edited |
| Convenience | Hide a complex join or aggregation behind one view and query it briefly | SELECT * FROM V_EMP10 without writing the condition every time |
| Security | Include only the columns and rows you want to show and hide the rest | Leave out SAL and COMM and grant permission on this view only |
WITH pulls an inline view out to the front of the statement and gives it a name. This is the inline view join above rewritten with WITH.
WITH DEPT_AVG AS (SELECT DEPTNO, ROUND(AVG(SAL)) AS AVG_SAL FROM EMP GROUP BY DEPTNO) SELECT E.ENAME, E.SAL, A.AVG_SAL FROM EMP E JOIN DEPT_AVG A ON E.DEPTNO = A.DEPTNO WHERE E.SAL > A.AVG_SAL ORDER BY E.ENAME;ENAME SAL AVG_SAL
---------- ---------- ----------
ALLEN 1600 1567
BLAKE 2850 1567
FORD 3000 2175
JONES 2975 2175
KING 5000 2917
SCOTT 3000 2175DEPT_AVG is a name used only within this statement. It is not stored like a view.| Comparison | Inline view | WITH clause | View |
|---|---|---|---|
| Where it is defined | Inside the FROM clause | At the very start of the statement | A database object |
| Scope of use | Once, at that spot | Within that statement | Anywhere until dropped |
| Storage | No | No | Stores only the definition (the SELECT statement) |
Tomorrow we cover set operators that combine or subtract the results of two SELECTs vertically.
Click a choice to reveal the answer and explanation.
Question 1
The top salary by department is 5000 (KING) for department 10, 3000 (FORD and SCOTT) for 20, and 2850 (BLAKE) for 30. How many rows does the following SQL return? ```sql SELECT E.ENAME FROM EMP E WHERE E.SAL = (SELECT MAX(SAL) FROM EMP S WHERE S.DEPTNO = E.DEPTNO); ```
Question 2
DEPT has 4 departments, and departments 10, 20, and 30 each have several employees. Which is the correct result of running the following SQL in Oracle? ```sql SELECT D.DNAME, (SELECT ENAME FROM EMP E WHERE E.DEPTNO = D.DEPTNO) FROM DEPT D; ```
Question 3
DEPT 40 (OPERATIONS) has no employees. Which statement about the result of the following SQL is correct? ```sql SELECT D.DNAME, (SELECT MAX(SAL) FROM EMP E WHERE E.DEPTNO = D.DEPTNO) AS MAX_SAL FROM DEPT D; ```
Question 4
Which statement about views (VIEW) is NOT correct?
Question 5
Which of the following runs without an error in Oracle?