8.7. Review Questions
1. What is a subquery?
A subquery is a query that is nested inside a SELECT, INSERT, UPDATE, or DELETE statement, or inside another subquery. A subquery can be used anywhere an expression is allowed.
2. Which part of the query/subquery is considered the inner query, and which part is considered the outer query?
A subquery is also called an inner query or inner select, while the statement containing a subquery is also called an outer query or outer select
3. Can a subquery always be done as a join? Why or why not?
No.
4. When writing a query that will have a subquery, how do you determine which table/tables will go in the outer query?
The result contains their columns.
5. Which predicate can usually be reformulated into a join?
IN
6. When using operators, are many values acceptable from a result of a subquery?
No.
7. What can you do to insure a working subquery?
8.8. Exercises
Unless specified otherwise, use the Student_course database to answer the following questions. Also, use appropriate column headings when displaying your output.
Use the techniques from this chapter to construct and execute the following queries:
1. Find the student numbers of students who have earned As or Bs in courses taught in the fall semester. Do this in two ways: first using a subquery, and then using a join.
SELECT COUNT (DISTINCT g.STUDENT_NUMBER )
FROM Grade_report g
WHERE (GRADE = 'A' OR GRADE = 'B') AND
g.SECTION_ID IN
(SELECT s.SECTION_ID FROM Section s
WHERE s.SEMESTER = 'FALL')
SELECT COUNT (DISTINCT g.STUDENT_NUMBER )
FROM Grade_report g
INNER JOIN Section s
ON g.SECTION_ID = s.SECTION_ID
WHERE (GRADE = 'A' OR GRADE = 'B') AND s.SEMESTER = 'FALL'
2. Find all students who took a course offered by the Accounting department. List the student name and student number, the course name, and the grade in that course. (Hint: Begin with Department_to_major and use an appropriate WHERE.) Note that this task cannot be done with a multilevel subquery. Why?
SELECT st.SNAME, st.STNO, c.COURSE_NAME, g.GRADE
FROM
Course c INNER JOIN Department_to_major d
ON c.OFFERING_DEPT = d.Dcode
INNER JOIN Section sc
ON sc.COURSE_NUM = c.COURSE_NUMBER
INNER JOIN Grade_report g
ON g.SECTION_ID = sc.SECTION_ID
INNER JOIN Student st
ON st.STNO = g.STUDENT_NUMBER
WHERE DNAME = 'Accounting'
3. For every students who is a sophomore (class = 2), find the name and the name of the department that includes the student's major.
SELECT s.SNAME, d.DNAME
FROM Student s INNER JOIN Department_to_major d
ON s.MAJOR = d.Dcode
WHERE s.CLASS = 2
4. Find the names of the departments that offer courses at the junior or senior levels (either one) but not at the freshman level. The course level is the first digit after the prefix; for example, AAAA3yyy is a junior course, and so on.
Hint: Begin by creating the outer querythe names of departments that offer courses at the junior or senior levels. Save this query as q8_4. Then, construct the subquerya list of departments that offer courses at the freshman level. Save the subquery as a view. Examine both lists of departments. When you have the outer query and the subquery results, recall the original query that you saved (q8_4) and add the subquery. Check your result with the department lists you just generated. Redo the last part of the experiment with your view. You should get the same result.
SELECT t1.OFFERING_DEPT
FROM
( SELECT DISTINCT OFFERING_DEPT
FROM Course
WHERE SUBSTRING(COURSE_NUMBER, 5, 1) = '2' OR SUBSTRING(COURSE_NUMBER, 5, 1) = '3'
) t1
WHERE t1.OFFERING_DEPT NOT IN
(
SELECT OFFERING_DEPT
FROM Course
WHERE SUBSTRING(COURSE_NUMBER, 5, 1) = '1'
)
5. Find the names of courses that are prerequisites for other courses. List the course number and name, and the number and name of the prerequisite.
SELECT c1.COURSE_NAME as cname, c1.COURSE_NUMBER as cnum, c2.COURSE_NAME as pname, c2.COURSE_NUMBER as pnum
FROM [Course] c1, [Prereq] p, [Course] c2
WHERE c1.COURSE_NUMBER = p.COURSE_NUMBER AND c2.COURSE_NUMBER = p.PREREQ
6. List the names of instructors who teach courses that have other than three-hour credits. Do the problem in two ways: once with IN and once with NOT..IN.
SELECT DISTINCT INSTRUCTOR
FROM Section
WHERE COURSE_NUM IN
( SELECT [COURSE_NUMBER]
FROM [Course]
WHERE [CREDIT_HOURS] != 3
)
SELECT DISTINCT INSTRUCTOR
FROM Section
WHERE COURSE_NUM NOT IN
( SELECT [COURSE_NUMBER]
FROM [Course]
WHERE [CREDIT_HOURS] = 3
)
7. Create a table called Secretary with the columns dcode (of data type CHAR(4)) for department code and name (of data type VARCHAR(20)) for the secretary name. Populate the table as follows:
Secretary
dCode name
ACCT Beryl
COSC Kaitlyn
ENGL David
HIST Christina
BENG Fred
HINDI Chloe
CREATE TABLE Secretary
( dcode CHAR(4), name VARCHAR(20))
GO
INSERT Secretary VALUES('ACCT', 'Beryl');
INSERT Secretary VALUES('COSC', 'Kaitlyn');
INSERT Secretary VALUES('ENGL', 'David');
INSERT Secretary VALUES('HIST', 'Christina');
INSERT Secretary VALUES('BENG', 'Fred');
INSERT Secretary VALUES('HIND', 'Chloe');
a. Create a query that lists the names of departments that have secretaries (use IN and the Secretary table in a subquery with the Department_to_major table in the outer query). Save this query as q8_7a.
SELECT *
FROM Department_to_major
WHERE Dcode IN
(SELECT Dcode FROM Secretary)
b. Create a query that lists the names of departments (using the Department_to_major table) that do not have secretaries (use NOT IN). Save this query as q8_7b.
SELECT *
FROM Department_to_major
WHERE Dcode NOT IN
(SELECT Dcode FROM Secretary)
c. Add one more row to the Secretary table that contains <null,'Brenda'> (which you could see, for example, in a situation in which you have hired Brenda but have not yet assigned her to a department).
INSERT Secretary VALUES( NULL, 'Brenda')
d. Recall q8_7a and rerun it. Recall q87_b and rerun it.
The behavior of NOT..IN when nulls exist may surprise you. If nulls may exist in the subquery, then NOT..IN either should not be used (Chapter 10 shows how to use another predicate, NOT EXISTS, which is a workaround to this problem), or should include AND whatever IS NOT NULL. If you use NOT..IN in a subquery, you must either ensure that nulls will not occur in the subquery or use some other predicate (such as NOT EXISTS). Perhaps the best advice is to avoid NOT..IN unless you cannot figure out another way to solve a problem.
e. To see a correct answer, add the phrase WHERE dcode IS NOT NULL to the subquery in the IN and NOT..IN cases and run them again.
SELECT *
FROM Department_to_major
WHERE Dcode IN
(SELECT Dcode FROM Secretary WHERE Dcode IS NOT NULL)
SELECT *
FROM Department_to_major
WHERE Dcode NOT IN
(SELECT Dcode FROM Secretary WHERE Dcode IS NOT NULL)
Do not delete the Secretary table, because we will revisit this problem in Chapter 10.
8. Devise a list of course names that are offered in the fall semester in rooms where the capacity is equal to or above the average room size.
SELECT DISTINCT c.COURSE_NAME
FROM Section s INNER JOIN [Room] r
ON s.BLDG = r.BLDG AND s.ROOM = r.ROOM
INNER JOIN Course c
ON c.COURSE_NUMBER = s.COURSE_NUM
WHERE SEMESTER = 'FALL' AND CAPACITY >= (SELECT AVG(CAPACITY) FROM Room WHERE CAPACITY IS NOT NULL)