You are on page 1of 5

A subquery can itself include one or more subqueries.

Any number of subqueries can be


nested in a statement.

This query finds the names of authors who have participated in writing at least one
popular computer book.

USE pubs
SELECT au_lname, au_fname
FROM authors
WHERE au_id IN
(SELECT au_id
FROM titleauthor
WHERE title_id IN
(SELECT title_id
FROM titles
WHERE type = 'popular_comp'))

The innermost query returns the title ID numbers PC1035, PC8888, and PC9999. The
query at the next higher level is evaluated with these title IDs and returns the author ID
numbers. Finally, the outer query uses the author IDs to find the names of the authors.

You can also express this query as a join:

USE pubs
SELECT au_lname, au_fname
FROM authors INNER JOIN titleauthor ON authors.au_id = titleauthor.au_id
JOIN titles ON titleauthor.title_id = titles.title_id
WHERE type = 'popular_comp'

Correlated Subqueries with Aliases

Correlated subqueries can be used in operations such as selecting data from a table
referenced in the outer query. In this case a table alias (also called a correlation name)
must be used to specify unambiguously which table reference to use. For example, you
can use a correlated subquery to find the types of books published by more than one
publisher. Aliases are required to distinguish the two different roles in which the titles
table appears.

USE pubs
SELECT DISTINCT t1.type
FROM titles t1
WHERE t1.type IN
(SELECT t2.type
FROM titles t2
WHERE t1.pub_id <> t2.pub_id)

Here is the result set:


type
----------
business
psychology

(2 row(s) affected)

The preceding nested query is equivalent to this self-join:

USE pubs
SELECT DISTINCT t1.type
FROM titles t1 INNER JOIN titles t2 ON t1.type = t2.type
AND t1.pub_id <> t2.pub_id

Subqueries with Aliases

Many statements in which the subquery and the outer query refer to the same table can be
stated as self-joins (joining a table to itself). For example, you can find authors who live
in the same city as Livia Karsen by using a subquery:

USE pubs
SELECT au_lname, au_fname, city
FROM authors
WHERE city IN
(SELECT city
FROM authors
WHERE au_fname = 'Livia'
AND au_lname = 'Karsen')

Here is the result set:

au_lname au_fname city


---------------------------------------- -------------------- ----------
Green Marjorie Oakland
Straight Dean Oakland
Stringer Dirk Oakland
MacFeather Stearns Oakland
Karsen Livia Oakland

(5 row(s) affected)

Or you can use a self-join:

USE pubs
SELECT au1.au_lname, au1.au_fname, au1.city
FROM authors AS au1 INNER JOIN authors AS au2 ON au1.city = au2.city
AND au2.au_lname = 'Karsen'
AND au2.au_fname = 'Livia'

Table aliases are required because the table being joined to itself appears in two different
roles. Aliases can also be used in nested queries that refer to the same table in an inner
and outer query.
USE pubs
SELECT au1.au_lname, au1.au_fname, au1.city
FROM authors AS au1
WHERE au1.city in
(SELECT au2.city
FROM authors AS au2
WHERE au2.au_fname = 'Livia'
AND au2.au_lname = 'Karsen')

Explicit aliases make it clear that reference to authors in the subquery does not mean the
same thing as the reference in the outer query.

Subqueries in UPDATE, DELETE, and INSERT Statements

Subqueries can be nested in UPDATE, DELETE, and INSERT statements, as well as in


SELECT statements.

The following query doubles the price of all books published by New Moon Books. The
query updates the titles table; its subquery references the publishers table.

UPDATE titles
SET price = price * 2
WHERE pub_id IN
(SELECT pub_id
FROM publishers
WHERE pub_name = 'New Moon Books')

Here's an equivalent UPDATE statement using a join:

UPDATE titles
SET price = price * 2
FROM titles INNER JOIN publishers ON titles.pub_id = publishers.pub_id
AND pub_name = 'New Moon Books'

You can remove all sales records of business books with this nested query:

DELETE sales
WHERE title_id IN
(SELECT title_id
FROM titles
WHERE type = 'business')

Here's an equivalent DELETE statement using a join:

DELETE sales
FROM sales INNER JOIN titles ON sales.title_id = titles.title_id
AND type = 'business'

Subqueries with IN
The result of a subquery introduced with IN (or with NOT IN) is a list of zero or more
values. After the subquery returns results, the outer query makes use of them.

This query finds the names of the publishers who have published business books.

USE pubs
SELECT pub_name
FROM publishers
WHERE pub_id IN
(SELECT pub_id
FROM titles
WHERE type = 'business')

Here is the result set:

pub_name
----------------------------------------
Algodata Infosystems
New Moon Books

(2 row(s) affected)

This statement is evaluated in two steps. First, the inner query returns the identification
numbers of the publishers that have published business books (1389 and 0736). Second,
these values are substituted into the outer query, which finds the names that go with the
identification numbers in publishers.

USE pubs
SELECT pub_name
FROM publishers
WHERE pub_id in ('1389', '0736')

One difference in using a join rather than a subquery for this and similar problems is that
the join lets you show columns from more than one table in the result. For example, if
you want to include the titles of the business books in the result, you must use a join
version.

USE pubs
SELECT pub_name, title
FROM publishers INNER JOIN titles ON publishers.pub_id = titles.pub_id
AND type = 'business'

Here is the result set:

pub_name title
---------------------- -------------------------------------------------
Algodata Infosystems The Busy Executive's Database Guide
Algodata Infosystems Cooking with Computers: Surreptitious Balance
Sheets
New Moon Books You Can Combat Computer Stress!
Algodata Infosystems Straight Talk About Computers
(4 row(s) affected)

This query shows the join produces four rows, not two as in the preceding subquery.

Here is another example of a query that can be formulated with either a subquery or a
join. This query finds the names of all second authors who live in California and who
receive less than 30 percent of the royalties for a book.

USE pubs
SELECT au_lname, au_fname
FROM authors
WHERE state = 'CA'
AND au_id IN
(SELECT au_id
FROM titleauthor
WHERE royaltyper < 30
AND au_ord = 2)

Here is the result set:

au_lname au_fname
---------------------------------------- --------------------
MacFeather Stearns

(1 row(s) affected)

The inner query is evaluated, producing the ID numbers of the three authors who meet
the subquery qualifications. The outer query is then evaluated. Notice that you can
include more than one condition in the WHERE clause of both the inner and the outer
query.

Using a join, the same query is expressed like this:

USE pubs
SELECT au_lname, au_fname
FROM authors INNER JOIN titleauthor ON authors.au_id = titleauthor.au_id
WHERE state = 'CA'
AND royaltyper < 30
AND au_ord = 2

A join can always be expressed as a subquery. A subquery can often, but not always, be
expressed as a join. This is because joins are symmetric: you can join table A to B in
either order and get the same answer. The same is not true if a subquery is involved.

You might also like