Learning Objectives – after this chapter you will be able to:
  • Write single, multiple and nested subqueries and multi-column comparisons.
  • Use subqueries in UPDATE, DELETE, INSERT and CREATE TABLE … AS SELECT.
  • Use a subquery in the VALUES clause and ORDER BY in a subquery for top-N analysis (Oracle8i).
  • Write correlated subqueries and use EXISTS, NOT EXISTS, ANY and ALL.
What is a Subquery?

A subquery is a query within another query. The outer query is the main query and the inner one the subquery. A normal subquery is executed first and its result is passed to the main query. Because a subquery usually returns a list of values, the IN operator is used very often.

Simple subqueries
select name, qual from faculty
where fcode in ( select fcode from course_faculty where ccode = 'ora' );

select * from batches
where fcode = ( select fcode from faculty where name = 'Kevin Loney' );   -- single value

select * from faculty
where fcode not in ( select fcode from batches
                     where months_between(sysdate, stdate) <= 3 );
Multiple, Nested and Multi-column Subqueries
  • Multiple subqueries – a main query can receive values from more than one subquery (combined with AND / OR).
  • Nested subqueries – a subquery can depend on another subquery. Oracle allows nesting up to 16 levels; more than 3 levels is not recommended for performance.
  • Multi-column – a subquery may return several columns that are compared with several values: where (ccode, enddate - stdate) in (select ...).
Nested and multi-column subqueries
select rollno, name, bcode from students
where bcode in ( select bcode from batches
                 where fcode in ( select fcode from faculty where qual like '%MS%' ) );

select * from batches
where (ccode, enddate - stdate) in
      ( select ccode, max(enddate - stdate) from batches group by ccode );

select ccode, name, fee from courses
where fee = ( select max(fee) from courses );
Subqueries in DML and DDL
UPDATE, DELETE, CREATE TABLE … AS and INSERT … SELECT
update courses set fee = fee * 1.1
where ccode in ( select ccode from batches group by ccode having count(*) > 5 );

delete from batches where bcode not in ( select bcode from students );

update batches set fcode = ( select fcode from batches where bcode = 'b1' )
where bcode = 'b7';                                   -- subquery supplies the new value

create table new_batches as
select bcode, ccode, fcode, stdate, timing from batches where stdate > sysdate;

insert into new_batches
select bcode, ccode, fcode, stdate, timing from batches where stdate > sysdate;
  • CREATE TABLE … AS SELECT creates the table with the structure of the query; only NOT NULL constraints are copied (other constraints such as the primary key are not).
  • For INSERT … SELECT the order and type of columns must match the target table (or list the columns).
  • The notes show how to “rename” a column by creating a new table with an alias, dropping the old table, using RENAME newproducts TO products and re-adding constraints.
The notes were written for Oracle8i, which had no command to rename a column. Later Oracle releases provide ALTER TABLE … RENAME COLUMN old TO new.
New in Oracle8i
Subquery in VALUES and ORDER BY in a subquery
insert into students values ( (select max(rollno) + 1 from students),
                              'b7', 'Robert Lafore', 'm', sysdate, null, null );

select ccode, name, fee
from ( select * from courses order by fee desc )
where rownum < 3;                                     -- top-2 fees (top-N analysis)
Correlated Subquery

A correlated subquery receives a value from the main query, uses it (usually in its condition) and returns the result to the main query. It is recognised by a main-query column used inside the subquery, and it is executed once for each row of the main query.

Correlated subqueries
select * from batches b1
where enddate - stdate >= ( select avg(enddate - stdate)
                            from batches
                            where ccode = b1.ccode );      -- longer than course average

select name, fee from courses c1
where 2 = ( select count(*) from courses where fee > c1.fee );   -- 3rd highest fee
Normal subqueryCorrelated subquery
Executed only once, before the main queryExecuted once for each row of the main query
Sends a value to the main queryReceives value(s) from the main query and sends value(s) back
EXISTS, NOT EXISTS, ANY and ALL
  • EXISTS is true if the subquery returns any row; NOT EXISTS is true if it returns none. They do not compare values – what the subquery selects does not matter. They are used with correlated subqueries.
  • ANY – the condition is true if it holds for any value in the list; ALL – it must hold for all values. Syntax: value operator ANY|ALL (list) with =, !=, >, >=, <, <=.
select ccode, name, fee from courses
where not exists ( select * from batches where ccode = courses.ccode );   -- no batch yet

select name from courses
where fee > any ( select fee from courses where duration = 25 );
-- same as: where fee > ( select min(fee) from courses where duration = 25 )
rate = 10Result
rate > ANY (15, 20)False
rate > ANY (5, 15)True
rate > ALL (10, 20)False
rate > ALL (5, 7)True
Key Takeaways
  • A normal subquery runs once, first; a correlated subquery runs once per main-query row.
  • Subqueries work in SELECT, UPDATE, DELETE, INSERT and CREATE TABLE … AS.
  • EXISTS checks for rows, not values; > ANY behaves like > MIN, > ALL like > MAX.
Chapter 11 Notes (PDF)
ch11.pdf 16 pages 355 KB Open in PDF Viewer (Free Tool)

Your browser cannot show this PDF here. Open Chapter 11 Notes (PDF)

ch11.pdfKeys: ← → page · + − zoom · F full screen
Question / Answer (15 questions)

Moderate-level questions based on the Chapter 11 notes (PDF). Click a question to see the answer.

Answer : A subquery is a query within another query; the outer query is the main query and the inner query is the subquery. A (normal) subquery is always executed first and its result is passed to the main query, which is then executed using that result.

Answer : Because subqueries generally generate a list of values, and the main query must compare a single value against that list. For example, WHERE fcode IN (SELECT fcode FROM course_faculty WHERE ccode = 'ora') displays faculty who can handle the Oracle course.

Answer : A main query can receive values from more than one subquery. Example: SELECT * FROM batches WHERE fcode IN (SELECT fcode FROM faculty WHERE qual LIKE '%MS%') OR ccode IN (SELECT ccode FROM courses WHERE fee > 5000) – both subqueries are executed and then the main query.

Answer : A nested subquery is a subquery that depends on another subquery, which may depend on another, and so on – e.g. students of batches taken by faculty with qualification MS. Subqueries can be nested up to 16 levels, but more than 3 levels is not recommended for performance.

Answer : The multiple columns returned are compared with multiple values in parentheses, e.g. WHERE (ccode, enddate - stdate) IN (SELECT ccode, MAX(enddate - stdate) FROM batches GROUP BY ccode), which returns the batches that took the maximum duration for each course.

Answer : The WHERE clause of UPDATE and DELETE can contain a subquery, e.g. increasing the fee of courses that have more than 5 batches, or DELETE FROM batches WHERE bcode NOT IN (SELECT bcode FROM students). A subquery can also supply the new value in SET, e.g. SET fcode = (SELECT fcode FROM batches WHERE bcode = 'b1').

Answer : It creates a new table from an existing table using a subquery; the structure of the new table is the same as the structure of the query and the rows returned are inserted. Only NOT NULL constraints are carried to the new table – e.g. NEW_BATCHES keeps NOT NULL on STDATE but not the primary key.

Answer : The order and type of columns in the query and the target table should be the same; otherwise the columns must be listed according to the requirement.

Answer : A subquery can be used in the VALUES clause of INSERT (e.g. (SELECT MAX(rollno) + 1 FROM students) to get the next roll number), and ORDER BY is permitted in a subquery, which allows top-N analysis using ROWNUM.

Answer : SELECT ccode, name, fee FROM (SELECT * FROM courses ORDER BY fee DESC) WHERE ROWNUM < 3. The subquery sorts the courses in descending order of fee and the main query takes only the first two rows using the ROWNUM pseudo column.

Answer : A correlated subquery receives some input (a value) from the main query, uses it – generally in its condition – and sends the result back to the main query. It is identified by the use of a column of the main query inside the subquery, e.g. WHERE ccode = b1.ccode.

Answer : A correlated subquery is executed once for each row of the main query, because the value it uses may change from row to row. A normal subquery is executed only once before the main query and only sends a value to the main query, whereas a correlated subquery receives values from and sends values to the main query.

Answer : SELECT name, fee FROM courses c1 WHERE 2 = (SELECT COUNT(*) FROM courses WHERE fee > c1.fee). For each course the subquery counts courses with a higher fee; if exactly two fees are higher, that fee is the third highest.

Answer : EXISTS is true if the subquery returns any row; NOT EXISTS is true if the subquery returns no row. They do not compare column values, so what is selected in the inner query does not matter. They are used with correlated subqueries, e.g. courses for which no batch has started: WHERE NOT EXISTS (SELECT * FROM batches WHERE ccode = courses.ccode).

Answer : Both compare one value with a set of values using a relational operator. ANY is true if the condition is satisfied by any value in the list; ALL is true only if it is satisfied by all values. For x = 15, x > ANY (10,20) is TRUE because 15 is greater than 10.
MCQ Test : Check Your Understanding (5 questions)

Select an option and press Check Answer, or answer all questions and press Submit Test to see your score. Each answer comes with an explanation.

Q1. A correlated subquery is executed:

Show Answer

Correct Answer : D. Once for each row of the main query
Because it uses a value from the current row of the main query, it runs once for each main-query row.

Q2. Up to how many levels can subqueries be nested (as per the notes)?

Show Answer

Correct Answer : A. 16
Subqueries can be nested up to 16 levels, though more than 3 is not recommended for performance.

Q3. What is the result of 10 > ALL (5, 7)?

Show Answer

Correct Answer : B. True
10 is greater than both 5 and 7, so the ALL condition is true.

Q4. When CREATE TABLE ... AS SELECT is used, which constraints of the source table are copied?

Show Answer

Correct Answer : C. Only NOT NULL
Only NOT NULL constraints are carried over; others must be added again with ALTER TABLE.

Q5. Which operator checks only whether the subquery returns any row?

Show Answer

Correct Answer : D. EXISTS
EXISTS returns true if any row is retrieved by the subquery; it does not compare values.

Bibliography/References

The chapter notes PDF is the course study material and is credited to its author below. The explanations, questions and MCQs on this page are original study aids written for this course from the topics covered in that PDF. The other works are cited for verification and further reading. Oracle, SQL*Plus and PL/SQL are trademarks of Oracle Corporation; other names belong to their respective owners.

  1. Srikanth, P. (n.d.). Oracle For Beginners (chapter notes – the PDF shown on each chapter page). Srikanth Technologies. http://www.srikanthtechnologies.com/
  2. Oracle Corporation. (n.d.). Oracle Database SQL Language Reference, 19c. https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/
  3. Oracle Corporation. (n.d.). Oracle Database Development Guide, 19c. https://docs.oracle.com/en/database/oracle/oracle-database/19/adfns/
  4. Silberschatz, A., Korth, H. F., & Sudarshan, S. (2019). Database System Concepts (7th ed.). McGraw-Hill Education.
  5. Elmasri, R., & Navathe, S. B. (2016). Fundamentals of Database Systems (7th ed.). Pearson.