Upcoming SlideShare
×

# Slide 1 ACS 378 Spring 2001

407 views

Published on

0 Likes
Statistics
Notes
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Be the first to comment

• Be the first to like this

Views
Total views
407
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
16
0
Likes
0
Embeds 0
No embeds

No notes for slide

### Slide 1 ACS 378 Spring 2001

1. 1. Sub Queries (Nested Queries) in SQL
2. 2. More Complex Queries <ul><li>Proposed Solution: </li></ul><ul><ul><li>SELECT DESCRIP, PRICE </li></ul></ul><ul><ul><li>FROM PRODUCT </li></ul></ul><ul><ul><li>WHERE PRICE > AVG(PRICE) </li></ul></ul>List the description and price for products whose price is above average, that is, more than the average price of all products . Consider the following problem:
3. 3. Invalid SQL Syntax!! <ul><li>SQL does not allow us to include a column function (like AVG, SUM, MAX, MIN) in the WHERE clause. </li></ul><ul><li>The WHERE clause condition must be answerable on the basis of a single row of the PRODUCT table cited in the FROM clause </li></ul>SQLCODE = -120, ERROR: A WHERE CLAUSE OR SET CLAUSE INCLUDES A COLUMN FUNCTION <ul><li>We get the following error message: </li></ul>
4. 4. Two Step Solution <ul><li>We could do this in 2 steps: </li></ul><ul><li>Step 1: Find the average </li></ul><ul><ul><li>SELECT AVG( PRICE) </li></ul></ul><ul><ul><li>FROM PRODUCT </li></ul></ul><ul><li>The result: </li></ul>------------------ 1128.6250000000
5. 5. Two Step Solution <ul><li>Step 2: Use answer to Step 1 in another query: </li></ul><ul><li>SELECT DESCRIP, PRICE </li></ul><ul><ul><li>FROM PRODUCT </li></ul></ul><ul><ul><li>WHERE PRICE > 1228.625 </li></ul></ul>DESCRIP PRICE --------------- ---------- STILL VIDEO CAM 1500.00 486 DX/33 1400.00 LASER PRINTER 3500.00
6. 6. Limitation of This Solution <ul><li>Each time we want this question answered: </li></ul><ul><ul><li>We run first query again </li></ul></ul><ul><ul><li>Transfer answer to second query </li></ul></ul><ul><ul><li>Run modified second query </li></ul></ul><ul><li>We would like to automatically transfer the answer from first query into the second query. </li></ul>
7. 7. Nested Query Solution <ul><li>Replace the constant value (the average) given in the second query with the first query (which gives this value) </li></ul><ul><ul><li>SELECT DESCRIP, PRICE </li></ul></ul><ul><ul><li>FROM PRODUCT </li></ul></ul><ul><ul><li>WHERE PRICE > </li></ul></ul><ul><ul><li>(SELECT AVG(PRICE) </li></ul></ul><ul><ul><li> FROM PRODUCT) </li></ul></ul><ul><li>Called a Nested Query or a Subquery </li></ul>Outer query Inner query
8. 8. Sub-Query Yielding Multiple Values <ul><li>Problem: List the names and phones of customers who placed orders thru sales rep with id JMH during the month of January 2000. </li></ul><ul><li>Step 1: Find orders which meet the desired criteria. List their account numbers </li></ul><ul><li>SELECT ACCTNO </li></ul><ul><li>FROM ORDER </li></ul><ul><li> WHERE ORDER_DATE </li></ul><ul><ul><ul><li> BETWEEN ’01/01/2001’ AND ’01/31/2001’ </li></ul></ul></ul><ul><ul><ul><li> AND ORDREP = ‘JMH’ </li></ul></ul></ul>
9. 9. Sub-Query Yielding Multiple Values <ul><li>This gives us a list of account numbers, e.g.: </li></ul><ul><ul><ul><li>1111, 1456, 2345,  ,6789, 7012 </li></ul></ul></ul><ul><li>Step 2: Use this list to find the account names and phones </li></ul><ul><ul><li>SELECT ACCTNAME, PHONE </li></ul></ul><ul><ul><li>FROM ACCOUNT </li></ul></ul><ul><ul><li>WHERE ACCTNO IN (1111,1456, 2345,  ,6789, 7012) </li></ul></ul>
10. 10. Subquery Version <ul><ul><li>SELECT ACCTNAME, PHONE </li></ul></ul><ul><ul><li>FROM ACCOUNT </li></ul></ul><ul><ul><li>WHERE ACCTNO IN </li></ul></ul><ul><ul><li>(SELECT ACCTNO </li></ul></ul><ul><ul><li>FROM ORDER </li></ul></ul><ul><ul><li>WHERE ORDER_DATE </li></ul></ul><ul><ul><li> BETWEEN ’01/01/2001’ AND ’01/31/2001’ </li></ul></ul><ul><ul><li> AND ORDREP = ‘JMH’) </li></ul></ul><ul><li>Note the data to be retrieved only comes from the table named in the outer query </li></ul>1 st Query replaces list
11. 11. When to use Subquery? <ul><li>If answer data is from one table, but criteria from different table (but related), then subquery may be valid approach </li></ul><ul><li>In our example: </li></ul><ul><ul><li>Subquery is on ORDER table </li></ul></ul><ul><ul><ul><li>Criteria on this table </li></ul></ul></ul><ul><ul><li>Outer query on ACCOUNT table </li></ul></ul><ul><ul><ul><li>Only need output from this table </li></ul></ul></ul>
12. 12. JOIN Alternative to Subquery <ul><ul><li>SELECT ACCTNAME, PHONE </li></ul></ul><ul><ul><li>FROM ACCOUNT A </li></ul></ul><ul><ul><li>INNER JOIN ORDER O </li></ul></ul><ul><ul><li>ON O.ACCTNO = A.ACCTNO </li></ul></ul><ul><ul><li>WHERE ORDER_DATE </li></ul></ul><ul><ul><li> BETWEEN ’01/01/2001’ AND ’01/31/2001’ </li></ul></ul><ul><ul><li>AND ORDREP = ‘JMH’) </li></ul></ul><ul><li>This problem could also be done with a JOIN: </li></ul><ul><li>Would HAVE to use JOIN if wanted Orderno or Orderdate, for example, in answer </li></ul>
13. 13. Sub-Query for Matching rows <ul><li>List product numbers, descriptions for products that have been ordered </li></ul><ul><li>Subquery method: </li></ul><ul><ul><li>SELECT PRODNO, DESCRIP </li></ul></ul><ul><ul><li>FROM PRODUCT </li></ul></ul><ul><ul><li>WHERE PRODNO IN </li></ul></ul><ul><ul><li>(SELECT PRODNO </li></ul></ul><ul><ul><li>FROM ORDERLINE) </li></ul></ul><ul><li>Could be done with JOIN, also </li></ul>
14. 14. Sub-Query for Non-matching Rows <ul><li>List product numbers, descriptions for products that have NOT been ordered </li></ul><ul><ul><li>SELECT PRODNO, DESCRIP </li></ul></ul><ul><ul><li>FROM PRODUCT </li></ul></ul><ul><ul><li>WHERE PRODNO NOT IN </li></ul></ul><ul><ul><li>(SELECT PRODNO </li></ul></ul><ul><ul><li>FROM ORDERLINE) </li></ul></ul><ul><li>Can’t be done </li></ul><ul><li>with JOIN </li></ul>PRODNO DESCRIP ------ --------------- 3276 LASER PRINTER
15. 15. Incorrect Solution <ul><li>The following is NOT a solution to this problem: </li></ul><ul><ul><li>SELECT PRODNO, DESCRIP </li></ul></ul><ul><ul><li>FROM PRODUCT P, ORDERLINE O </li></ul></ul><ul><ul><li>WHERE NOT P.PRODNO = O.PRODNO </li></ul></ul><ul><li>This produces: </li></ul><ul><ul><ul><li>Pairs of orderline rows with every product EXCEPT the one in the orderline </li></ul></ul></ul>
16. 16. Details that go with Maximums <ul><li>Problem: list the product numbers, descriptions of the highest-priced product </li></ul><ul><li>INCORRECT SOLUTION: </li></ul><ul><ul><li>SELECT PRODNO, DESCRIP, MAX(PRICE) </li></ul></ul><ul><ul><li>FROM PRODUCT </li></ul></ul><ul><li>SQL Rules: cannot have MAX, SUM, etc on same SELECT as non-summarized field names </li></ul>
17. 17. Correct Solution <ul><li>SELECT PRODNO, DESCRIP, PRICE </li></ul><ul><li>FROM PRODUCT </li></ul><ul><li>WHERE PRICE IN </li></ul><ul><li>(SELECT MAX(PRICE) </li></ul><ul><li>FROM PRODUCT) </li></ul><ul><li>Inner query gets maximum </li></ul><ul><li>Outer query gets detail row data that matches </li></ul>Could also use =
18. 18. Multiple Levels of Nesting in Queries <ul><li>Find all orders placed for items with above average prices </li></ul><ul><ul><li>Step 1 Find the average price </li></ul></ul><ul><ul><ul><li>SELECT AVG(PRICE) </li></ul></ul></ul><ul><ul><ul><li> FROM PRODUCT </li></ul></ul></ul><ul><ul><li>Step 2 Find items with above average prices </li></ul></ul><ul><ul><ul><li>SELECT PRODNO </li></ul></ul></ul><ul><ul><ul><li>FROM PRODUCT </li></ul></ul></ul><ul><ul><ul><li> WHERE PRICE > (average price) </li></ul></ul></ul>
19. 19. Building on Earlier Steps <ul><ul><li>Step 3 Find order numbers which include these items </li></ul></ul><ul><ul><ul><li>SELECT ORDERNO </li></ul></ul></ul><ul><ul><ul><li> FROM ORDERLINE </li></ul></ul></ul><ul><ul><ul><li> WHERE PRODNO IN (list of product numbers) </li></ul></ul></ul><ul><ul><li>Step 4 Find orders which include such items </li></ul></ul><ul><ul><ul><li>SELECT ORDERNO, ORDERDATE </li></ul></ul></ul><ul><ul><ul><li> FROM ORDER </li></ul></ul></ul><ul><ul><ul><li> WHERE ORDERNO IN (list of order numbers) </li></ul></ul></ul>
20. 20. Multiple Levels of Nesting <ul><li>SELECT ORDERNO, ORDERDATE </li></ul><ul><li>FROM ORDER </li></ul><ul><li>WHERE ORDERNO IN </li></ul><ul><li> (SELECT ORDERNO </li></ul><ul><li>FROM ORDERLINE </li></ul><ul><li> WHERE PRODNO IN </li></ul><ul><li> (SELECT PRODNO </li></ul><ul><li> FROM PRODUCT </li></ul><ul><li>WHERE PRICE > </li></ul><ul><li> (SELECT AVG(PRICE) </li></ul><ul><li>FROM PRODUCT))) </li></ul>
21. 21. Alternate Solution: Joins and Subquery <ul><li>This problem can also be solved using combination of joins and subqueries For example: </li></ul><ul><li>SELECT ORDERNO, ORDERDATE </li></ul><ul><li> FROM ORDER R INNER JOIN ORDERLINE L </li></ul><ul><li> ON R.ORDERNO = L.ORDERNO </li></ul><ul><li>INNER JOIN PRODUCT P </li></ul><ul><li> ON L.PRODNO = P.PRODNO </li></ul><ul><li> WHERE PRICE > </li></ul><ul><li>(SELECT AVG(PRICE) </li></ul><ul><li> FROM PRODUCT)) </li></ul>
22. 22. Finding the Last 10 Orders <ul><li>We have seen how to get orders from last four dates, but how to get the last 10 orders (for example, if 4 on last date, just want those) </li></ul><ul><li>SELECT O1.ORDERNO, O1.ORDERDATE </li></ul><ul><li>FROM ORDER O1 </li></ul><ul><li>WHERE 10 > </li></ul><ul><li>(SELECT COUNT(*) </li></ul><ul><li>FROM ORDER O2 </li></ul><ul><li>WHERE O1.ORDERDATE > O2.ORDERDATE </li></ul><ul><li>This will always include last 10 and ties </li></ul>
23. 23. Subquery in SELECT clause <ul><li>SELECT P.PROJNO, (SELECT SUM(HRS) FROM TASK T WHERE T.PROJNO = P.PROJNO) TOTAL_HRS </li></ul><ul><li>FROM PROJECT P </li></ul>
24. 24. Correlated Subqueries
25. 25. Correlated Subqueries <ul><li>Sometimes, need to restrict subquery to rows that match each row of outer query </li></ul><ul><li>Find all products whose price exceeds their vendor’s average price. </li></ul><ul><ul><li>SELECT PRODNO, DESCRIP, VENDCODE </li></ul></ul><ul><ul><li> FROM PRODUCT P1 </li></ul></ul><ul><ul><li> WHERE PRICE > </li></ul></ul><ul><ul><li> (SELECT AVG(PRICE) </li></ul></ul><ul><ul><li> FROM PRODUCT P2 </li></ul></ul><ul><ul><li> WHERE P1.VENDCODE = P2.VENDCODE) </li></ul></ul><ul><li>Here the inner query is evaluated separately for each row of the outer query table. </li></ul>
26. 26. Revisiting a Previous Problem <ul><li>Find all products that have had orders placed. </li></ul><ul><li>Solution 1: Using JOIN </li></ul><ul><li>SELECT DISTINCT PRODNO, DESCRIP, </li></ul><ul><li>VENDCODE </li></ul><ul><li>FROM PRODUCT P INNER JOIN ORDERLINE L </li></ul><ul><li>ON P.PRODNO = L.PRODNO </li></ul><ul><li>Retrieves many rows (thousands?) for each product </li></ul>
27. 27. Previous Problem <ul><li>Solution 2: Using IN </li></ul><ul><li>SELECT PRODNO, DESCRIP, VENDCODE </li></ul><ul><li> FROM PRODUCT P </li></ul><ul><li>WHERE PRODNO IN </li></ul><ul><li>(SELECT PRODNO FROM ORDERLINE) </li></ul>
28. 28. Correlated Subquery with EXISTS <ul><li>Solution 3, a new alternative: </li></ul><ul><li>SELECT PRODNO, DESCRIP, VENDCODE </li></ul><ul><li>FROM PRODUCT P </li></ul><ul><li>WHERE EXISTS </li></ul><ul><li> (SELECT * FROM ORDERLINE L </li></ul><ul><ul><li> WHERE P.PRODNO = L.PRODNO) </li></ul></ul><ul><li>Might be more efficient to execute than join query, maybe even the IN query. Inner query stops when the first matching row is found. </li></ul>
29. 29. Using NOT EXISTS <ul><li>Find all sales reps that do not have any orders placed. </li></ul><ul><ul><li>SELECT FNAME, LNAME </li></ul></ul><ul><ul><li> FROM SALESREP S </li></ul></ul><ul><ul><li>WHERE NOT EXISTS </li></ul></ul><ul><ul><li> (SELECT * </li></ul></ul><ul><ul><li> FROM ORDER </li></ul></ul><ul><ul><li> WHERE ORDREP = S.REPID) </li></ul></ul><ul><li>This is an alternative to subquery using NOT IN </li></ul><ul><li>NOT EXISTS, EXISTS may be more efficient </li></ul>
30. 30. NOT EXISTS for finding items at maximum <ul><li>SELECT ACCTNO, ORDERNO, ORDERDATE </li></ul><ul><li>FROM ORDER A </li></ul><ul><li>WHERE NOT EXISTS </li></ul><ul><ul><li>(SELECT * </li></ul></ul><ul><ul><li>FROM ORDER B </li></ul></ul><ul><ul><li>WHERE A.ACCTNO = B.ACCTNO </li></ul></ul><ul><ul><li>AND A.ORDERDATE < B.ORDERDATE) </li></ul></ul>Find the most recent order for each account <ul><li>If multiple orders on most recent date (for a given account) number, returns all of them </li></ul>