10.6. Review Questions
1. What is a noncorrelated subquery?
A noncorrelated subquery is a subquery that is independent of the outer query. In other words,
the subquery could be executed on its own.
2. Which type of subquery can be executed on its own?
They do not have information from outer query.
3. Which part of a query is evaluated first, the query or the subquery?
For correlated subquery, query is done first.
4. What are correlated subqueries?
correlated subquery is an inner subquery whose information is referenced by the main, outer
query such that the inner query may be thought of as being executed repeatedly.
5. What does the EXISTS predicate do?
EXISTS predicate seeks only to find whether the subquery WHERE can be satisfied.
6. What are considered universal qualifiers?
In SQL, "for all" and "for each" are the universal qualifiers, whereas "there exists" is the
existential qualifier.
7. Is correlation necessary when we use EXISTS? Why?
correlation is usually necessary with EXISTS. EXISTS only return a status.
8. Explain how the "for all" type SQL query involves a double-nested correlated subquery
using the NOT EXISTS predicate.
10.7. Exercises
Unless specified otherwise, use the Student_course database to answer the following questions.
Also, use appropriate column headings when displaying your output.
1. List the names of students who have received Cs. Do this in three ways: (a) as a join,
(b) as an uncorrelated subquery, and (c) as a correlated subquery. Show both results and
account for any differences.
SELECT DISTINCT s.SNAME, g.GRADE
FROM Student s INNER JOIN Grade_report g
ON s.STNO = g.STUDENT_NUMBER
WHERE g.GRADE = 'C'
-- Without DISTINCT, one name will shows many times.
SELECT s.SNAME
FROM Student s
WHERE s.STNO in ( SELECT g.STUDENT_NUMBER
FROM Grade_report g
WHERE g.GRADE = 'C')
SELECT s.SNAME
FROM Student s
WHERE EXISTS ( SELECT 1
FROM Grade_report g
WHERE g.GRADE = 'C' and g.STUDENT_NUMBER = s.STNO)
2. In section "Existence Queries and Correlation," you were asked to find the names of
students who have taken a computer science class and earned a grade of B. We noted that it
could be done in several ways. One query could look like this:
SELECT s.sname
FROM Student s
WHERE s.stno IN
(SELECT gr.student_number
FROM Grade_report gr, Section
WHERE Section.section_id = gr.section_id
AND Section.course_num LIKE 'COSC____'
AND gr.grade = 'B')
Redo this query, putting the finding of the COSC course in a correlated subquery. The query
should be as follows:
The Student table uncorrelated subquery to the Grade_report table, correlated EXISTS to the
Section table.
SELECT s.sname
FROM Student s
WHERE s.stno IN
(SELECT gr.student_number
FROM Grade_report gr
WHERE gr.grade = 'B'
AND EXISTS (
SELECT 1
FROM Section
WHERE Section.section_id = gr.section_id
AND Section.course_num LIKE 'COSC____')
)
3. In the section "SQL Universal and Existential Qualifiers," we illustrated both an
existence query:
SELECT s.sname
FROM Student s
WHERE EXISTS
(SELECT 'X'
FROM Grade_report gr
WHERE s.stno = gr.student_number
AND gr.grade = 'C')
and a NOT EXISTS version:
SELECT s.sname
FROM Student s
WHERE NOT EXISTS
(SELECT 'X'
FROM Grade_report gr
WHERE s.stno = gr.student_number
AND gr.grade = 'C')
Show that the EXISTS version is the complement of the NOT EXISTS versioncount the rows in the
EXISTS result, the rows in the NOT EXISTS result, and the rows in the Student table. Also,
devise a query to give the same result with IN and NOT..IN.
SELECT s.sname
FROM Student s
WHERE s.stno IN
(SELECT gr.student_number
FROM Grade_report gr
WHERE gr.grade = 'C')
SELECT s.sname
FROM Student s
WHERE s.stno NOT IN
(SELECT gr.student_number
FROM Grade_report gr
WHERE gr.grade = 'C')
4. Discover whether all students take courses by counting the students, and then count
those students whose student numbers are in the Grade_report table and those whose student
numbers are not in the table. Use IN and then NOT..IN, and then use EXISTS and NOT EXISTS. How
many students take courses and how many students do not?
SELECT COUNT(s.STNO) as [cnt in student]
FROM Student s
SELECT COUNT(GR.STUDENT_NUMBER) as [all grade rows],
COUNT(DISTINCT gr.STUDENT_NUMBER) as [all student in grade report]
FROM Grade_report gr
SELECT COUNT(s.STNO) as [count in grade table]
FROM Student s
WHERE s.STNO IN
(SELECT gr.STUDENT_NUMBER FROM Grade_report gr)
SELECT COUNT(s.STNO) as [count without grade table]
FROM Student s
WHERE s.STNO NOT IN
(SELECT gr.STUDENT_NUMBER FROM Grade_report gr)
SELECT COUNT(s.STNO) as [count in grade table]
FROM Student s
WHERE EXISTS
(SELECT 1 FROM Grade_report gr
WHERE gr.STUDENT_NUMBER = s.STNO)
SELECT COUNT(s.STNO) as [count in grade table]
FROM Student s
WHERE NOT EXISTS
(SELECT 1 FROM Grade_report gr
WHERE gr.STUDENT_NUMBER = s.STNO)
a. Find out which students have taken courses but who have not taken COSC courses. Create
a set of student names and courses from the Student, Grade_report, and Section tables (use the
prefix COSC to indicate computer science courses). Then, use NOT..IN to "subtract" from that
set another set of student names of students (who take courses) who have taken COSC courses.
For this set difference, use NOT..IN.
SELECT DISTINCT st.SNAME
FROM Student st, Grade_report gr
WHERE gr.STUDENT_NUMBER = st.STNO
AND gr.STUDENT_NUMBER NOT IN
(
SELECT gr1.STUDENT_NUMBER
FROM Section sc,Grade_report gr1
WHERE sc.SECTION_ID = gr1.SECTION_ID
AND sc.COURSE_NUM Like 'COSC%'
)
b. Change NOT..IN to NOT EXISTS (with other appropriate changes) and explain the result.
The "other appropriate changes" include adding the correlation and the change of the result
column in the subquery set.
SELECT DISTINCT st.SNAME
FROM Student st, Grade_report gr
WHERE gr.STUDENT_NUMBER = st.STNO
AND NOT EXISTS
(
SELECT 1
FROM Section sc,Grade_report gr1
WHERE sc.SECTION_ID = gr1.SECTION_ID
AND gr1.STUDENT_NUMBER = st.STNO
AND sc.COURSE_NUM Like 'COSC%'
)
5. There exists a table called Plants. List the table and then find out what company or
companies have plants in all cities. Verify your result manually.
SELECT company, plantlo
FROM Plants x
WHERE NOT EXISTS
(SELECT 'X'
FROM Plants y
WHERE NOT EXISTS
(SELECT 'Y'
FROM Plants z
WHERE x.COMPANY = z.COMPANY
AND y.PLANTLO = z.PLANTLO
)
)
6. Run the following query and print the result:
SELECT distinct name, langu
FROM Cap x
WHERE NOT EXISTS
(SELECT 'X'
FROM Cap y
WHERE NOT EXISTS
(SELECT 'X'
FROM Cap z
WHERE X.langu =Z.langu
AND Y.name=Z.name))
Save the query (e.g., save forall) and hand in the result.
a. Recreate the Cap table (e.g., call it some other name, such as LANG1). To do this,
first create the table and then use the INSERT statement with the sub select option (INSERT
INTO LANG1 AS SELECT * FROM Cap).
b. Add a new person to your table who speaks only BENG.
c. Recall your previous SELECT (get for all).
d. CHANGE the table from CAP to LANG1 (for all occurrences, use CHANGE/Cap/lang1/
repeatedly, assuming that you called your table LANG1).
e. Start the new query (the one you just created with LANG1 in it).
f. How is this result different from the situation in which Newperson was not in LANG1?
Provide an explanation of why the query did what it did.
7. The Department_to_major table is a list of four-letter department codes with the
department names. In Chapter 8, Exercise 7 (hereafter referred to as Exercise 8-7), you
created a table called Secretary, which should now have data like this:
Secretary
dCode Name
ACCT Beryl
COSC Kaitlyn
ENGL David
HIST Christina
BENG Fred
Null Brenda
In Exercise 8-7, you did the following:
1. Create a query that lists the names of departments that have secretaries (use IN and
the Secretary table in a subquery). Save this query as q8_7a.
SELECT *
FROM Department_to_major d
WHERE d.Dcode IN
( SELECT s.dcode
FROM Secretary s )
2. Create a query that lists the names of departments that do not have secretaries (use
NOT..IN). Save this query as q8_7b.
SELECT *
FROM Department_to_major d
WHERE d.Dcode NOT IN
( SELECT s.dcode
FROM Secretary s
WHERE s.dcode IS NOT NULL)
3. Add one more row to the Secretary table that contains <null,'Brenda'>. (This could be
a situation in which you have hired Brenda but have not yet assigned her to a department.)
4. Recall q8_7a and rerun it.
5. Recall q8_7b and rerun it.
We remarked in Exercise 8-7 that the NOT..IN predicate has problems with nulls: the behavior
of NOT..IN when nulls exist may surprise you. If nulls may exist in the subquery, then NOT..IN
should not be used. If you use NOT..IN in a subquery, you must ensure that nulls will not
occur in the subquery or you must use some other predicate, such as NOT EXISTS. Perhaps the
best advice is to avoid NOT..IN.
Here, we repeat Exercise 8-7 using NOT EXISTS:
8. Reword query q8_7a to use EXISTS. You will have to correlate the inner and outer
queries. Save this query as q10_7aa.
SELECT *
FROM Department_to_major d
WHERE EXISTS
( SELECT 1
FROM Secretary s
WHERE s.dcode = d.Dcode )
9. Reword query q8_7b to use NOT EXISTS. You will have to correlate the inner and outer
queries. Save this query as q10_7bb. You should not have a phrase IS NOT NULL in your NOT
EXISTS query.
SELECT *
FROM Department_to_major d
WHERE NOT EXISTS
( SELECT 1
FROM Secretary s
WHERE s.dcode = d.Dcode)
10. Rerun q8_9a with and without <null, Brenda>.
11. Rerun q8_9b with and without <null, Brenda>.
Note the difference in behavior versus the original question. List the names of those
departments that do or do not have secretaries. The point here is to encourage you to use NOT
EXISTS in a correlated subquery, rather than NOT..IN.