Advanced SQL
Advanced SQL
Chapter 6 Advanced S QL
Chapter Overview
Chapter Objectives
Specific student learning objectives are included at the beginning of the chapter. From
an instructor’s point of view, the objectives of this chapter are to:
3. Help the students understand the possibilities views (both dynamic and
materialized) offer in database management.
6. Discuss triggers and stored procedures and provide examples of how these might
be used.
Key Terms
Classroom Ideas
1. Have students program in a system that supports S QL along with this chapter. The
nuances of joining multiple tables, nesting subqueries, properly qualifying built-in
functions, and so forth are really only learned by writing a wide variety of non-trivial
queries. There are exercises at the end of the chapter that will provide such
practice for students.
2. If students have access to Oracle, have them take a look at the various data
dictionary views available to them as a user. You may also want to discuss the
various DBA views available and show these to the students during your lecture.
Remember that Teradata University for Academics, in collaboration with University
of Arkansas Walton College Enterprise Systems, provides access to Teradata S QL
for classroom use, and that you may set up access for yourself and your students.
The databases from the text are available, as are much larger data sets that you
may want to use. Teradata University’s home page is
https://www.teradata.com/University/Academics.
3. When discussing multiple table queries, always emphasize that there is more than
one way to write a query. For example, show the students a query using a join and
then the same query using subqueries.
4. Emphasize the cases when a subquery is needed and cannot be substituted with a
join. A good example of this would be the case where one needs to find all
customers who have never purchased a product (using a subquery with the NOT IN
qualifier).
5. The capabilities and benefits of views are not as obvious to students as you might
expect. First, many relational systems place limitations on operations that may be
performed on views (for example, no or restricted modification). Second, views are
not just the relational term for temporary table or for subschemas (from the network
model); rather, views provide a capability for simpler query writing for casual users.
Finally, views may have negative performance implications compared to temporary,
intermediate tables explicitly created by a prewritten procedure. These points
should be emphasized in lectures or assignments. Consider having students create
both a view and a temporary table (or materialized view) in S Q L. In most S Q L
systems, a temporary table can be created by the use of a SAVE or KEEP clause at
the end of a query, or one can use a CREATE TABLE command that has a query
(rather than column definitions) as its object. Then, the same query can be run and
timed against both the view and temporary tables. As another alternative, have
students derive the view table as part of the FROM clause of a query. One way to
estimate the timing of each approach, given small data sets, is to use the EXPLAIN
command (or similar command with your R DBMS) on each version of the query to
show students how the query would be processed using each approach.
6. Develop an exercise for the students to explore the effects of a trigger. Have them
create and populate some tables, then write an insert trigger for one of the tables
that might impact other tables. You could then have the students insert some
records and see the results. It is important to show the effects of triggers through
examples that the students can try out, followed by problems that they would have
to solve by writing triggers. The same can be said for stored procedures.
b. Correlated subquery. This type of subquery is processed outside in, rather than
inside out. That is, the inner query is executed for each row in the outer query,
and the inner query depends in some way on values from the current row in the
outer query. The results of the inner query will, in turn, affect the final results of
the outer query.
c. Materialized view. Materialized view is, in essence, a copy of data in base tables
physically stored based on a view definition.
e. Join. The most frequently used relational operation, which brings together data
from two or more related tables into one result table
g. Self join. A join that requires matching rows in a table with other rows in the
same table. This is a join that joins a table with itself and often occurs with the
presence of a unary relationship in the database, such as a Supervisor or
Manager of Employees within an Employee table.
h. Outer join. A join in which rows that do not have matching values in common
columns are nevertheless included in the result table. Outer joins return all the
values in one of the tables included in the join, regardless of whether a match
exists in the other table(s) or not.
i. Virtualized table (or virtual table). A table that does not exist as a permanent
structure on a storage medium but that the DBMS creates as needed.
b equi-join
d derived table
f natural join
c correlated subquery
a outer join
e trigger
Outer joins are often used in database maintenance to find rows that do not
have matching values in common columns. Null values appear in columns
where there is no match between tables. Another example would be a query
that returns all customers—whether they have placed orders in the last four
months or not—along with the date of the most recent order placed within the
last four months. Customers who have not placed an order would be returned
with a null value under most recent order.
Correlated subqueries use the result of the outer query to determine the
processing of the inner query. Thus, the inner query varies for each row
referenced in the outer query.
specific to a group to which the instance belongs (such as the Average Age
within a team).
6-7. Explain that any query that can be written using the subquery approach can also
be written using the joining approach, but not vice versa:
While Oracle allows a subquery to return more than one column, most systems
allow pairwise joining of one and only one column in an inner query with one
column in an outer query. (An exception to this is when a subquery is used with
the EXISTS keyword.) You can display data only from the table(s) referenced in
the outer query. If you want to include data from the subquery in the result, then
you would have to use the join technique because data from the subquery
cannot be included in the results. The joining technique is useful when data from
several relations are to be retrieved and displayed, and the relationships are not
necessarily nested.
Use UNION when you want to combine the output from multiple queries
together. However, each query involved must output the same number of
columns, and the columns must have the same data types.
Views are used to create an additional layer of separation between data stored
on a physical storage medium and the structural mechanism that provides
access to the data. Views allow D BAs to give users and developers a
perspective to the data that fits their specific needs and does not allow them to
see data elements beyond those that they need for their specific task. Providing
access to the database through views tailored to the needs of a specific user
group reduces the risk of errors, security breaches, and violations of privacy.
The additional virtual layer also reduces the impact of possible changes to the
base tables—in such situations, it might be possible to avoid any externally
visible changes by simply changing the way a view is specified in relation to the
base tables.
When a view is used to update data in the base tables, it is essential to make
sure that the view does not create ambiguity in terms of the elements that the
update addresses. In practice, only views created with straightforward single
table, non-aggregate queries can be used for updates.
The WITH CHECK OPTION will create a condition the violations of which will
prevent a view from being updated.
Derived tables are used to create a temporary table that is treated as if it were
an actual table. This table is not persistent in that it goes away after the query in
which it was created is run.
One example of the use of a derived table would be to find all ships that were
loaded beyond capacity. In this example, a shipment’s weight is calculated by
computing the sum of the quantity order times the weight. The query follows:
SELECT Ship.ShipNo
FROM Ship, Shipment,
(SELECT ShipmentLine.ShipmentID,
SUM(Item.Weight*ShipmentLine.Quantity) AS Tweight
FROM ShipmentLine,Item
WHERE ShipmentLine.ItemNo = Item.ItemNo
GROUP BY ShipmentID) AS ShipWt
WHERE Ship.ShipNo = Shipment.ShipNo AND
Shipment.ShipmentID = ShipWt.ShipmentID AND Ship.Capacity <
ShipWt.Tweight;
The simplest way to address this problem is to convert one of the data types.
For example, if one data type is a character and the other numeric, you could
use a function such as Oracle’s TO_CHAR to convert the numeric to a
character.
The outer join is not easily implemented for more than two tables. The results
vary by R DBMS vendor and should be thoroughly tested before implementing.
They are hard to see coming until they fail to fire. They may fire without
notification. Cascading triggers and endless loop triggers are also possible.
Flexibility: Routines can be used for more purposes than constraints or triggers
Applicability: Routines may apply to the entire database and not just one
application.
The key new features of S Q L:2016 are as follows: 1) more effective processing
of time-series data with Row Pattern Recognition; 2) trigonometric and logarithm
functions; 3) Java Script Object Notation support; and 4) Polymorphic Table
Functions for creating sophisticated custom functions.
6-23. Mechanisms for dealing with temporal issues before the extensions were
introduced:
Even before the temporal extensions, it was not atypical to see specifications of
valid time frames included in table structures. For example, there might have
been a separate PRODUCTPRICE table that included the following attributes:
With this type of table structure, it was possible to emulate a mechanism for
dealing with time-dependent values, but it was much more difficult to use this
structure without the language components specifically designed for time.
a. Display the course I D and course name for all courses with an ISM prefix:
Query:
b. Display the numbers and names of all courses for which Professor Berndt has
been qualified:
Query:
SELECT Course.CourseID,
Course.CourseName
FROM Faculty,
Course,
Qualified
WHERE Faculty.FacultyName = 'Berndt' AND
c. Display the class roster, including student name, for all students enrolled in
section 2714 of I SM 4212:
Query:
SELECT Student.StudentID,
Student.StudentName,
Section.CourseID,
Registration.SectionNo
FROM Student,
Registration,
Section
WHERE Section.SectionNo= Registration.SectionNo AND
Student.StudentID= Registration.StudentID AND
Registration.SectionNo=2714
ORDER BY StudentName;
6-27. Is any instructor qualified to teach I S M 3113 and not qualified to teach I S M
4930?
Query:
SELECT Faculty.FacultyID,
Faculty.FacultyName
FROM Faculty,
Qualified
WHERE Qualified.FacultyID=Faculty.FacultyID AND
Qualified.CourseID='ISM 3113'
MINUS
SELECT Faculty.FacultyID, Faculty.FacultyName
FROM Faculty, Qualified
WHERE Qualified.FacultyID=Faculty.FacultyID
6-28. SQ L queries:
a. How many students were enrolled in section 2714 during semester I-2021?
SELECT COUNT(StudentID)
FROM Section
WHERE SectionNo = 2714;
SELECT COUNT(StudentID)
FROM Section
WHERE CourseID = 'ISM 3113';
6-29. SQ L queries:
a. What are the names of the course(s) that student Altvater took during the
semester I-2021?
SELECT Course.CourseName
FROM Course, Section,Registration, Student
WHERE Course.CourseID = Section.CourseID AND
Section.SectionNo = Registration.SectionNo AND
Registration.StudentID = Student.StudentID AND
StudentName = 'Altvater' AND
Section.Semester = 'I-2021';
There are no courses that satisfy this condition. Using section 'II-2021' will
produce results.
b. List names of the students who have taken at least one course that Professor
Collins is qualified to teach.
c. List the names of the students who took at least one course with “Syst” in its
name during the semester I-2021.
d. How many students did Professor Collins teach during the semester I-2021?
This query requires the use of the ASSIGNMENT relation mentioned in the
introduction to the section. Let’s assume ASSIGNMENT has two columns:
FacultyID and SectionNo, signifying that a specific faculty member has been
assigned to teach a specific section.
SELECT COUNT(StudentID)
FROMStudent, Registration, Section, Assignment, Faculty
WHERE Student.StudentID = Registration.StudentID AND
Registration.SectionNo = Section.SectionNo AND
Section.SectionNo = Assignment.SectionNo AND
Assignment.FacultyID = Faculty.FacultyID AND
Faculty.FacultyName = 'Collins' AND
Section.Semester = 'I-2021';
e. List the names of the courses that at least two faculty members are qualified to
teach.
SELECT CourseName
FROM Course
WHERE CourseID IN
( SELECT CourseID
FROM Qualified
GROUP BY CourseID
HAVING Count(FacultyID)>=2);
6-30.
a. Which students were not enrolled in any courses during semester I-2021?
Query:
FROM Student
WHERE NOT EXISTS
( SELECT *
FROM Registration, Section
WHERE Student.StudentID = Registration.StudentID AND
Registration.SectionNo = Section.SectionNo AND Semester=
'I-2021');
b. Which faculty members are not qualified to teach any courses?
SELECT FacultyName
FROM Faculty
WHERE FacultyID NOT IN
(SELECT FacultyID
FROM Qualified);
With the book data set, the query does not produce any results. You can test
this very easily by adding another instructor into the data set.
6-31. List primary and foreign keys for all entities in Figure 6-16:
Tutor
Student
MatchHistory
TutorReport
Query:
ALTER TABLE Student
ADD COLUMN MathScore NUMBER(2,1);
Query:
ALTER TABLE Tutor
ADD COLUMN Subject VARCHAR(7)
CHECK (Subject IN ('Reading', 'Math', 'ESL'));
6-34. Suggested solution for tutors who tutor in more than one subject area:
One approach is to adjust the database design to allow tutors the ability to
declare more than one subject preference for tutoring. Based on the prior
specifications (including Problem and Exercise 6-33), the business rule
appeared to be that tutors only tutored in one subject, thus the subject could be
stored with tutor information. Under this new requirement, the database needs
the ability to track more than one subject per tutor. This can be accomplished by
adding two tables to the current design (TutorSubject, Subject) and by altering
the structure of the MatchHistory table to track the Subject involved in each
match of Tutor and Student, as noted in the revised E RD.
It is also possible to assume that (1) each tutor is certified only once or (2) that a
tutor must be certified in each of the subjects. A second assumption would
require that CertDate be moved to the TutorSubject relation. This is a good
opportunity to show how making an assumption without interviewing the
database user may result in an incorrect data model because the correct
business rule has not been uncovered.
After completing Exercise 6-33 (where subject values of “Reading, Math, and E
SL” were added to teachers’ certifications), some students may ask if it is
important for the database to track what Subject each Student is studying. This
inquiry can be used in class as an example of how an analyst can uncover
additional business rules that have not been initially elicited from the client in
interviews. You may expand this question to track student assessment scores
for math and E SL in addition to the existing READ score. This should lead to
consideration that, just as tutors may only be certified in one area, students may
elect to study in one to three areas, depending on their needs. The data model
would need to be expanded further to handle this.
6-35. Students matched with a tutor with “Temp Stop” status in 2021:
SELECT MatchHistory.StudentID
FROM MatchHistory, Tutor
WHERE MatchHistory.TutorID = Tutor.TutorID AND
Tutor.Status = ‘Temp Stop’ AND
MatchHistory.StartDate >= #1/1/2021#)
First, a query named CH7P35 returns a list of all reports ever submitted for each
currently active student. The query is sorted by tutor and report dates for that
tutor.
SELECT MatchHistory.MatchID,
MatchHistory.EndDate,
MatchHistory.TutorID,
TutorReport.Month
FROM MatchHistory LEFT JOIN TutorReport ON
MatchHistory.MatchID = TutorReport.MatchID
WHERE (((MatchHistory.EndDate) IS NULL)) OR
(((MatchHistory.EndDate)>#6/30/2021#) AND ((TutorReport.Month) Is Null))
ORDER BY MatchHistory.MatchID, TutorReport.Month;
Next, a query is built to retrieve data from query Ch7P35. This second query
returns just those tutors with active students who have not turned in a July
report.
Motivated students may add parameters to this query so it will work for any
month.
Note: This solution assumes the creation of a PERSON table to store the
common contact data for STUDENTs and TUTORs, and the linking of the
STUDENT and TUTOR table to the PERSON table. Individual student answers
may vary from this proposed solution due to this assumption.
PersonEMail VARCHAR(25),
PersonType CHAR(1));
ALTER TABLE Student (
ADD COLUMN PersonID VARCHAR(5));
ALTER TABLE Student (
ADD CONSTRAINT STPERSONID_FK
PersonID REFERENCES Person(PersonID));
ALTER TABLE Tutor (
ADD COLUMN PersonID VARCHAR(5));
ALTER TABLE Tutor (
ADD CONSTRAINT TTUTORID_FK
REFERENCES Person(PersonID));
6-38. Determine the total number of hours and the total number of lessons Tutor 106
taught in June and July 2021:
6-39. List the Read scores of students who were ever taught by tutors whose status is
Dropped
6-40. List all active students in June by name, including number of hours tutored and
number of lessons completed:
Query:
SELECT Student.StudentID,
MatchHistory.EndDate,
Person.LastName,
SUM(TutorReport.Hours) AS TotalHours,
SUM(TutorReport.Lessons) AS TotalLessons
FROM (Person INNER JOIN Student ON Person.PersonID =
Student.StudentID) INNER JOIN (MatchHistory LEFT JOIN
TutorReport ON MatchHistory.MatchID =
TutorReport.MatchID) ON Student.StudentID =
MatchHistory.StudentID
GROUP BY Student.StudentID, MatchHistory.EndDate,
Person.LastName
HAVING (((MatchHistory.EndDate) Is Null));
6-42. Total number of lessons taught in 2021 by tutors in each of the three Status
categories:
This answer assumes any active tutor may be available to accept a new
student:
Query:
SELECT Person.LastName,
Person.FirstName,
Tutor.Status
FROM Person INNER JOIN Tutor ON
Person.PersonID = Tutor.PersonID
WHERE (((Tutor.Status)= 'Active'));
SELECT T.TutorID,
Person.LastName,
Person.FirstName
FROM Person INNER JOIN Tutor AS T
ON Person.PersonID = T.PersonID
WHERE (((T.TutorID) IN
(SELECT MH.TutorID FROM MatchHistory MH
WHERE EndDate IS NOT NULL) AND
(T.TutorID) NOT IN
(SELECT MH.TutorID FROM MatchHistory MH
WHERE EndDate IS NULL)) AND ((T.STATUS)= 'Active'));
Query:
SELECT MatchHistory.TutorID
FROM MatchHistory
WHERE MatchHistory.MatchID NOT IN
(SELECT DISTINCT TutorReport.MatchID
FROM TutorReport);
Oracle Query:
SELECT Customer_T.CustomerID
FROM Customer_T
WHERE Customer_T.CustomerID
NOT IN (SELECT CustomerID from Order_T);
6-46. List product line names and for each product line number of products and
average product price.
Oracle Query:
SELECT ProductLineName,
COUNT(ProductID),
AVG(ProductStandardPrice)
FROM Productline_T, Product_T
WHERE Product_T.ProductLineID = Productline_T.ProductLineID
GROUP BY Productline_T.ProductLineID, ProductLineName;
6-47. Modify previous query to include only those product lines the average price of
which is higher than $200.
SELECT ProductLineName,
COUNT(ProductID) AS [NbrOfProducts],
AVG(ProductStandardPrice) AS [Avg Price]
FROM Productline_T, Product_T
WHERE Product_T.ProductLineID = Productline_T.ProductLineID
GROUP BY Productline_T.ProductLineID, ProductLineName
HAVING AVG(ProductStandardPrice)>200;
Oracle Query:
SELECT ProductLineName,
COUNT(ProductID),
AVG(ProductStandardPrice)
FROM Productline_T, Product_T
WHERE Product_T.ProductLineID = Productline_T.ProductLineID
GROUP BY Productline_T.ProductLineID, ProductLineName
HAVING AVG(ProductStandardPrice)>200;
6-48. List the names and number of employees supervised (label this value
HeadCount) for all the supervisors who supervise more than two employees:
SELECT S.EmployeeName,
COUNT(E.EmployeeID) AS [HeadCount]
FROM Employee_T S,
Employee_T E
WHERE S.EmployeeID = E.EmployeeSupervisor
GROUP BY S.EmployeeName
HAVING COUNT(E.EmployeeID) > 2;
Oracle Query:
SELECT S.EmployeeName,
COUNT(E.EmployeeID) AS HeadCount
FROM Employee_T S,
Employee_T E
WHERE S.EmployeeID = E.EmployeeSupervisor
GROUP BY S.EmployeeName
HAVING COUNT(E.EmployeeID) > 2;
Result:
EmployeeName HeadCount
Robert Lewis 3
You can verify this by running a simpler query that computes the number of
employees each employee supervises. From this query you would see that
there are three supervisors (those who supervise anyone), and the other two
supervisors supervise only one employee each.
SELECT E1.EmployeeName,
E1.EmployeeBirthdate,
E2.EmployeeName AS Manager,
E2.EmployeeBirthdate AS ManagerBirth
FROM Employee_T E1,
Employee_T E2
WHERE E1.EmployeeSupervisor = E2.EmployeeID
AND E1.EmployeeBirthdate < E2.EmployeeBirthdate;
P&E 6-49 Instance Diagram (with sample data for illustration purposes only; not
showing values from P VFC database)
6-50. Display order number, customer number, order date and items ordered for some
customer (example shows CustomerID=4, students may have chosen another
valid customer I D number in their solutions):
SELECT Order_T.OrderID,
Order_T.CustomerID,
Order_T.OrderDate,
OrderLine_T.ProductID,
Product_T.ProductDescription,
OrderLine_T.OrderedQuantity
Oracle Query:
SELECT Order_T.OrderID,
Order_T.CustomerID,
Order_T.OrderDate,
OrderLine_T.ProductID,
Product_T.ProductDescription,
OrderLine_T.OrderedQuantity
FROM OrderLine_T,
Order_T,
Product_T
WHERE Order_T.OrderID=OrderLine_T.OrderID AND
OrderLine_T.ProductID=Product_T.ProductID AND
Order_T.CustomerID = 4;
6-51. Display each item ordered for order #1, its standard price, and total price for
each item ordered:
SELECT OrderLine_T.ProductID,
Product_T.ProductStandardPrice,
OrderLine_T.OrderedQuantity*
Product_T.ProductStandardPrice AS LineTotal
FROM Product_T,OrderLine_T
WHERE Product_T.ProductID = OrderLine_T.ProductID AND
OrderLine_T.OrderID = 1;
SELECT WorkCenter_T.WorkcenterID,
GROUP BY WorkCenter_T.WorkcenterID;
Oracle Query:
SELECT WorkCenter_T.WorkcenterID
FROM WorkCenter_T
WHERE WorkcenterID IN (
SELECT WorkcenterID
EmployeeSkills_T.SkillID = 'QC1');
SELECT SUM(OrderLine_T.OrderedQuantity*
Product_T.ProductStandardPrice)
FROM Product_T,OrderLine_T
WHERE Product_T.ProductID = OrderLine_T.ProductID AND
OrderLine_T.OrderID = 1;
6-55. List for each vendor those materials that the vendor supplies the supply unit
price of which is at least four times the material standard price:
SELECT P.ProductID,
ProductDescription,
P.ProductStandardPrice,
SUM(U.QuantityRequired*R.ProductStandardPrice) AS
TotCost
FROM Product_T P,
Uses_T U,
RawMaterial_T P
Or here is another interesting approach using a derived table in the SELECT list:
SELECT P.ProductID,
P.ProductDescription,
P.ProductStandardPrice,
TotCost
FROM Product_T P,
(SELECT P1.ProductID,
SUM(P1.ProductStandardPrice*U.QuantityRequired) AS TotCost
FROM Uses_T U, RawMaterial_T R, Product_T P1
WHERE U.MaterialID = R.MaterialID AND
U.ProductID = P1.ProductID
GROUP BY P1.ProductID) Cost_T
WHERE P.ProductID = Cost_T.ProductID;
6-57. For every order that has been received, display the order ID, the total dollar
amount owed on that order (you’ll have to calculate this total from attributes in
one or more tables; label this result Total_Due), and the amount received in
payments on that order (assume there is only one payment made on each
order). To make this query a little simpler, you don’t have to include those
orders for which no payment has yet been received. List the results in
decreasing order by the difference between total due and amount paid:
Query:
Just to help to verify the result, the following shows all 11 rows of the payment
table, and as assumed, there is only one payment per order, but not all orders
have payments. Note: Dates in this database sometimes change between
editions of the associated textbook, so your results may vary in terms of dates:
SELECT OrderLine_T.OrderID,
SUM(OrderedQuantity*ProductStandardPrice) AS TotalDue,
PaymentAmount
FROM OrderLine_T, Product_T, Payment_T
WHERE OrderLine_T.ProductID = Product_T.ProductID AND
OrderLine_T.OrderID = Payment_T.OrderID
GROUP BY OrderLine_T.OrderID, PaymentAmount
ORDER BY SUM(OrderedQuantity*ProductStandardPrice) -
PaymentAmount DESC;
In Oracle S QL:
SELECT OrderLine_T.OrderID,
SUM(OrderedQuantity*ProductStandardPrice) AS
TotalDue,
PaymentAmount
FROM OrderLine_T,
Product_T,
Payment_T
WHERE OrderLine_T.ProductID = Product_T.ProductID AND
OrderLine_T.OrderID = Payment_T.OrderID
GROUP BY OrderLine_T.OrderID, PaymentAmount
ORDER BY TotalDue - PaymentAmount DESC;
6-58. List each customer who has bought computer desks and the number of units
bought by each customer:
The first solution is a better approach to this request as it will retrieve a result set
of computer desks, whether or not the material and description of said desk is
“oak” as is currently shown in the P VFC data set. The second solution is an
alternative approach that relies upon the only computer desk description found
in the current P VF C data set.
SELECT Customer_T.CustomerID,
CustomerName,
SUM(OrderedQuantity) as UnitsBought
FROM OrderLine_T,
Order_T,
Product_T,
Customer_T
WHERE ProductDescription LIKE '*Computer Desk*' AND
Order_T.OrderID = OrderLine_T.OrderID AND
Product_T.ProductId = OrderLine_T.ProductID AND
Customer_T.CustomerID = Order_T.CustomerID
GROUP BY Customer_T.CustomerID, CustomerName;
Oracle Query:
SELECT Customer_T.CustomerID,
CustomerName,
SUM(OrderedQuantity) as UnitsBought
FROM OrderLine_T,
Order_T,
Product_T,
Customer_T
WHERE ProductDescription LIKE '%Computer Desk%' AND
Order_T.OrderID = OrderLine_T.OrderID AND
Product_T.ProductId = OrderLine_T.ProductID AND
Customer_T.CustomerID = Order_T.CustomerID
GROUP BY Customer_T.CustomerID, CustomerName;
6-59. List each customer who bought at least one product that belongs to product line
Basic in March 2021. List each customer only once.
Oracle Query:
6-60. Modify your answer to Problem and Exercise 6-59 so that you include the
number of products in product line Basic that the customer ordered in March
2021.
Oracle Query:
6-61. Modify your answer to Problem and Exercise 6-60 so that the list includes the
number of products each customer bought in each product line in March 2021.
SELECT C.CustomerID,
C.CustomerName,
PL.ProductLineName,
COUNT(P.ProductID)
FROM Customer_T C,
Order_T O,
OrderLine_T OL,
Product_T P,
ProductLine_T PL
WHERE C.CustomerID = O.CustomerID AND
O.OrderID = OL.OrderID AND
OL.ProductID = P.ProductID AND
P.ProductLineID = PL.ProductLineID AND
SUBSTR(O.OrderDate,4,6)='MAR-21'
GROUP BY C.CustomerID,
C.CustomerName,
PL.ProductLineID,
PL.ProductLineName;
6-62. List in alphabetical order the names of all employees (managers) who are now
managing people with skill I D B S12. List each such manager’s name only once,
even if that manager manages several people with this skill:
6-63. Display the salesperson name, product finish, and total quantity sold (label as
TotSales) for each finish by each salesperson:
6-64. Write a query to list the number of products produced in each work center (label
this result ‘TotalProducts’). If a work center does not produce any products,
display the result with a total of 0:
SELECT WorkCenter_T.WorkCenterID,
COUNT(ProductID) AS TotalProducts
FROM WorkCenter_T LEFT OUTER JOIN ProducedIn_T
ON WorkCenter_T.WorkCenterID=ProducedIn_T.WorkCenterID
GROUP BY WorkCenter_T.WorkCenterID;
6-65. Develop a list of all the P VFC customers by name with the number of vendors in
the same state as that customer (label this computed result NumVendors):
Microsoft Access Query (Note that Access does not support MINUS):
SELECT Order_T.OrderID
FROM Order_T LEFT OUTER JOIN Payment_T ON
Order_T.OrderID = Payment_T.OrderID
WHERE Payment_T.PaymentID IS NULL;
Oracle Query:
SELECT OrderID
FROM Order_T
MINUS
SELECT OrderID
FROM Payment_T;
6-67. Names of states where customers reside, but have no salesperson residing in
that state:
First, a query solution using MINUS operator (does not work with Microsoft
Access):
SELECT CustomerState
FROM Customer_T
MINUS
SELECT SalesPersonState
FROM Salesperson_T;
Student answers will vary as to which approach is chosen as the “most natural,”
especially based on their experiences or level of comfort with mathematical set
manipulations.
6-68. Produce a list of all the products (show product description) and the number of
times each product has been ordered:
This query requires an outer join because some products may not have been
ordered. Because many S QL systems do not have an outer join operator, often
this type of query must use the UNION command. The following answer uses
this second approach because it will work with almost any system. Also, note
that the question wants the number of times a product has been ordered, not the
total quantity ordered:
FROM Product_T
WHERE EXISTS
(SELECT * FROM OrderLine_T
WHERE (OrderLine_T.ProductID =
Product_T.ProductID))=FALSE;
Oracle Query:
SELECT Product_T.ProductID,
ProductDescription,
COUNT(*) as TimesOrdered
FROM Product_T,OrderLine_T
WHERE Product_T.ProductID = OrderLine_T.ProductID
GROUP BY Product_T.ProductID, ProductDescription
UNION
SELECT ProductID,
ProductDescription,
0
FROM Product_T
WHERE NOT EXISTS
(SELECT *
FROM OrderLine_T
WHERE OrderLine_T.ProductID =
Product_T.ProductID);
6-69. Display the customer I D, name, and order I D for all customer orders. For those
customers who do not have any orders, include them in the display once:
SELECT c.CustomerID,
CustomerName,
NVL(OrderID,0)
FROM Customer_T c LEFT OUTER JOIN Order_T o ON
c.CustomerID = o.CustomerID;
OR
SELECT CUST.CustomerID,
CustomerName,
OrderID
FROM Customer_T CUST LEFT OUTER JOIN Order_T ORD ON
CUST.CustomerID = ORD.CustomerID
ORDER BY CUST.CustomerID;
6-70. Display the Employee I D and Employee Name for those employees who do not
possess the skill Router. Display the results in order by EmployeeName:
SELECT EmployeeID,
EmployeeName
FROM Employee_T
WHERE EmployeeID NOT IN
(SELECT ES.EmployeeID
FROM EmployeeSkills_T ES, Skill_T S
WHERE SkillDescription = 'Router' AND
ES.SkillID = S.SkillID)
ORDER BY EmployeeName;
6-71. Name of customer 16, and other customers in same zip code
SELECT C1.CustomerName,
C2.CustomerName,
C1.CustomerPostalCode
FROM Customer_T C1, Customer_T C2
WHERE C1.CustomerID = 16 AND
C1.CustomerPostalCode = C2.CustomerPostalCode AND
SELECT C1.CustomerName,
C2.CustomerName AS CName2,
C1.CustomerPostalCode
FROM Customer_T C1, Customer_T C2
WHERE C1.CustomerPostalCode = C2.CustomerPostalCode AND
C2.CustomerID <> C1.CustomerID;
6-73. Display the customer I D, name, and order I D for all customer orders. For those
customers who do not have any orders, include them in the display once, with a
0 value for OrderID:
SELECT Customer_T.CustomerID,
CustomerName,
OrderID
FROM Customer_T,
Order_T
WHERE Customer_T.CustomerID = Order_T.CustomerID
UNION
SELECT CustomerID, CustomerName, 0
FROM Customer_T
WHERE NOT EXISTS
(SELECT * FROM Order_T
WHERE Order_T.CustomerID = Customer_T.CustomerID);
6-74. Show the customer I D and name for all the customers who have ordered both
products with I Ds 3 and 4 on the same order:
SELECT C.CustomerID,
CustomerName
FROM Customer_T C,
Order_T O1,
OrderLine_T OL1
WHERE C.CustomerID = O1.CustomerID AND
O1.OrderID = OL1.OrderID AND
OL1.ProductID = 3 AND
O1.OrderID IN
(SELECT OrderID
FROM OrderLine_T OL2
WHERE OL2.ProductID = 4);
Or here is another interesting approach using derived tables (color for some
parentheses helps to show the nesting of SELECTs):
6-75. Customer names of customers who have ordered (on same or different orders)
both products 3 and 4:
Oracle Query:
SELECT C.CustomerID,
CustomerName
FROM Customer_T C,
Order_T O1,
OrderLine_T OL1
WHERE C.CustomerID = O1.CustomerID AND
O1.OrderID = OL1.OrderID AND
OL1.ProductID = 3
INTERSECT
SELECT C.CustomerID,
CustomerName
FROM Customer_T C,
Order_T O1,
OrderLine_T OL1
WHERE C.CustomerID = O1.CustomerID AND
O1.OrderID = OL1.OrderID AND
OL1.ProductID = 4;
6-76. List vendor I D, vendor name, material I D, material name, and supply unit price
for those materials that are provided by more than one vendor:
This query will not yield the desired result when there are two or more products
that have the same largest standard price. You would need to re-write the query
to use the comparison >= operator.
6-78. List the I Ds and names of all products that cost less than the average product
price in their product line.
6-79. List the I Ds and names of those sales territories that have at least 50 percent
more customers as the average number of customers per territory.
6-80. List the order number, product ID and ordered quantity for all customer orders
for which the ordered quantity is greater than the average ordered quantity of
that product: (Hint: This involves a correlated subquery.)
SELECT Order11.OrderID,
Order11.OrderedQuantity,
Order11.ProductID
FROM PRODUCT_T INNER JOIN OrderLine_T AS Order11 ON
PRODUCT_T.ProductID = Order11.ProductID
WHERE (((Order11.OrderedQuantity)>(
SELECT AVG(OrderedQuantity) FROM OrderLine_T x1
WHERE x1.ProductID = Order11.ProductID)) AND
((PRODUCT_T.ProductID)=[Order11].[ProductID]));
Oracle Query:
SELECT Order11.OrderID,
Order11.OrderedQuantity,
Order11.ProductID
FROM Product_T,OrderLine_T Order11
WHERE Product_T.ProductID = Order11.ProductID AND
Order11.OrderedQuantity >
(SELECT AVG(OrderedQuantity)
FROM OrderLine_T x1
WHERE x1.ProductID = Order11.ProductID);
6-81. List the salesperson that has sold the most computer desks:
It is easiest to create a subquery first. The first query we will call tsales:
Next, find the SalesPersonID for the salesperson who had the highest sales:
SELECT SalespersonID
FROM tsales
WHERE totsales = (SELECT MAX(totsales) FROM tsales);
Oracle Query:
SELECT Salesperson_T.SalespersonID,
SUM(OrderedQuantity) AS TotSales
FROM OrderLine_T,
Order_T,
Product_T,
DoesBusinessIn_T,
Salesperson_T
WHERE Order_T.OrderID = OrderLine_T.OrderID AND
OrderLine_T.ProductID = Product_T.ProductID AND
ProductDescription = 'Oak Computer Desk' AND
Order_T.CustomerID = DoesBusinessIn_T.CustomerID AND
Salesperson_T.SalesTerritoryID =
DoesBusinessIn_T.TerritoryID
GROUP BY Salesperson_T.SalespersonID;
Save the result as tsales and run to find the salesperson with the most computer
desk sales:
SELECT Salesperson_ID
FROM tsales
WHERE totsales = (SELECT MAX(totsales) FROM tsales);
6-82. Display in product I D order the product I D and total amount ordered of that
product by the customer who has bought the most of that product; use a derived
table in a FROM clause to answer this query. Note that the result of this query is
a subset (first and last columns) of the prior query result.
SELECT F1.ProductID,
MAX(F1.ProdCustTotal) as TotOrdered
FROM (SELECT ProductID, CustomerID, SUM(OrderedQuantity)
AS ProdCustTotal
FROM OrderLine_T OL2, Order_T O2
WHERE OL2.OrderID = O2.OrderID
Result:
ProductID TotOrdered
1 9
2 26
3 12
4 4
5 10
6 4
7 4
8 2
10 9
13 2
14 10
17 5
20 1
6-83. Employee information for all employees in each state who were hired before the
most recently hired person in that state:
SELECT *
FROM Employee_T E1
WHERE EmployeeDateHired <
(SELECT MAX(EmployeeDateHired)
FROM Employee_T E2
WHERE E1.EmployeeState = E2.EmployeeState);
a. List the IDs for all the products that have sold in total more than 20 units across
all orders:
SELECT X.ProductID
FROM OrderLine_T X
GROUP BY X.ProductID
HAVING SUM(X.OrderedQuantity) > 20;
ProductID
b. List all the IDs for the orders that include products that satisfy this first query
along with the number of products on those orders (see result below for an
example). Only orders with three or more products.
SELECT Y.OrderID,
COUNT(Y.ProductID) AS NumProductsOnOrder
FROM OrderLine_T Y
WHERE Y.OrderID IN
(SELECT T.OrderID
FROM OrderLine_T T
WHERE T.ProductID IN
(SELECT X.ProductID
FROM OrderLine_T X
GROUP BY X.ProductID
HAVING SUM(X.OrderedQuantity) > 20))
GROUP BY Y.OrderID
HAVING COUNT(Y.ProductID) >= 3;
OrderI
NumProductsOnOrder
D
2 3
4 4
1 3
c. What are the (other) products sold on the orders in the Part b. result:
ProductID ProductDescription
2 Birch coffee table
3 Oak computer desk
4 Entertainment center
5 Writer’s desk
6 8-Drawer dresser
8 48” bookcase
10 96” bookcase
14 Writer’s Desk
6-85. For each product display, in ascending order by product I D, the product I D and
description along with the customer I D and name for the customer who has
bought the most of that product; also show the total quantity ordered by that
customer (who has bought the most of that product). Use a correlated subquery:
Result:
6-87. Three differences that you may want to help the students discover:
o Primary and foreign keys are specified with the CREATE TABLE or ALTER
TABLE commands in S QL*PLUS. M S Access uses a graphical interface to
create tables and to establish primary and foreign keys.
o MS Access S QL does not include the CREATE VIEW or DROP VIEW
commands. Instead, the query that would be used as part of the CREATE VIEW
syntax is saved as a query, which can be accessed later through new select
statements by simply specifying the query name.
o MS Access has a keyword, DISTINCTROW, which is not found in other D BMS
SQ L implementations.
o Both use the semicolon to mark the end of a statement and cause it to execute.
o Basic SQ L syntax is very similar, using the keywords SELECT, FROM, WHERE,
GROUP BY, ORDER BY, and HAVING in the same fashion.
o Both use brackets to specify the order of expression evaluation.
o Subqueries and correlated subqueries can be written in both.
o Both are insensitive to spacing and line breaks within a statement.
Project Questions
The answers will depend on the students’ and the instructor’s choices.
The answers will depend on the students’ and the instructor’s choices.
6-90. Create a strategy for reviewing your database implementation with the
appropriate stakeholders.
In addition, it is essential that the key stakeholders understand that the database
has been designed to be used as a foundation for applications, by experts, or
through sophisticated front-end tools that have been configured automatically.
You don’t want to scare people away at this stage of the process.