1. Trang chủ
  2. » Công Nghệ Thông Tin

SQL VISUAL QUICKSTART GUIDE- P30 ppsx

10 179 0

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 175,98 KB

Nội dung

Using Subqueries as Column Expressions In Chapters 4, 5, and 6, you learned that the items in a SELECT -clause list can be literals, column names, or more-complex expressions. SQL also lets you to embed a subquery in a SELECT -clause list. A subquery that’s used as a column expres- sion must be a scalar subquery. Recall from Table 8.1 in “Subquery Syntax” earlier in this chapter that a scalar subquery returns a single value (that is, a one-row, one-column result). In most cases, you’ll have to use an aggregate function or restrictive WHERE conditions in the subquery to guarantee that the subquery returns only one row. The syntax for the SELECT -clause list is the same as you’ve been using all along, except that you can specify a parenthesized sub- query as one of the column expressions in the list, as the following examples show. Listing 8.17 uses two simple subqueries as column expressions to list each biography, its price, the average price of all books (not just biographies), and the difference between the price of the biography and the average price of all books. The aggregate function AVG() guarantees that each subquery returns a single value. See Figure 8.17 for the result. Remember that AVG() ignores nulls when computing an average; see “Calculating an Average with AVG() ” in Chapter 6. 270 Chapter 8 Using Subqueries as Column Expressions Listing 8.17 List each biography, its price, the average price of all books, and the difference between the price of the biography and the average price of all books. See Figure 8.17 for the result. SELECT title_id, price, (SELECT AVG(price) FROM titles) AS "AVG(price)", price - (SELECT AVG(price) FROM titles) AS "Difference" FROM titles WHERE type='biography'; Listing title_id price AVG(price) Difference T06 19.95 18.3875 1.5625 T07 23.95 18.3875 5.5625 T10 NULL 18.3875 NULL T12 12.99 18.3875 -5.3975 Figure 8.17 Result of Listing 8.17. Listing 8.18 uses correlated subqueries to list all the authors of each book in one row, as you’d view them in a report or spreadsheet. See Figure 8.18 for the result. Note that in each WHERE clause, SQL qualifies title_id implicitly with the table alias ta referenced in the subquery’s FROM clause; see “Qualifying Column Names in Subqueries” earlier in this chapter. For a more efficient way to imple- ment this query, see the Tips in this section. See Listing 15.8 in Chapter 15 for the reverse of this query. 271 Subqueries Using Subqueries as Column Expressions Listing 8.18 List all the authors of each book in one row. See Figure 8.18 for the result. SELECT title_id, (SELECT au_id FROM title_authors ta WHERE au_order = 1 AND title_id = t.title_id) AS "Author 1", (SELECT au_id FROM title_authors ta WHERE au_order = 2 AND title_id = t.title_id) AS "Author 2", (SELECT au_id FROM title_authors ta WHERE au_order = 3 AND title_id = t.title_id) AS "Author 3" FROM titles t; Listing title_id Author 1 Author 2 Author 3 T01 A01 NULL NULL T02 A01 NULL NULL T03 A05 NULL NULL T04 A03 A04 NULL T05 A04 NULL NULL T06 A02 NULL NULL T07 A02 A04 NULL T08 A06 NULL NULL T09 A06 NULL NULL T10 A02 NULL NULL T11 A06 A03 A04 T12 A02 NULL NULL T13 A01 NULL NULL Figure 8.18 Result of Listing 8.18. In Listing 8.19, I revisit Listing 7.30 in “Creating Outer Joins with OUTER JOIN ” in Chapter 7, but this time, I’m using a corre- lated subquery instead of an outer join to list the number of books that each author wrote (or cowrote). See Figure 8.19 for the result. Listing 8.20 uses a correlated subquery to list each author and the latest date on which he or she published a book. You should qualify every column name explicitly in a subquery that contains a join to make it clear which table is referenced (even when qualifiers are unnecessary). See Figure 8.20 for the result. 272 Chapter 8 Using Subqueries as Column Expressions Listing 8.19 List the number of books that each author wrote (or cowrote), including authors who have written no books. See Figure 8.19 for the result. SELECT au_id, (SELECT COUNT(*) FROM title_authors ta WHERE ta.au_id = a.au_id) AS "Num books" FROM authors a ORDER BY au_id; Listing au_id Num books A01 3 A02 4 A03 2 A04 4 A05 1 A06 3 A07 0 Figure 8.19 Result of Listing 8.19. Listing 8.20 List each author and the latest date on which he or she published a book. See Figure 8.20 for the result. SELECT au_id, (SELECT MAX(pubdate) FROM titles t INNER JOIN title_authors ta ON ta.title_id = t.title_id WHERE ta.au_id = a.au_id) AS "Latest pub date" FROM authors a; Listing au_id Latest pub date A01 2000-08-01 A02 2000-08-31 A03 2000-11-30 A04 2001-01-01 A05 2000-09-01 A06 2002-05-31 A07 NULL Figure 8.20 Result of Listing 8.20. Listing 8.21 uses a correlated subquery to compute the running total of all book sales. A running total, or running sum, is a com- mon calculation: For each book, I want to compute the sum of all sales of the books that precede the book. Here, I’m defining precede to mean those books whose title_id comes before the current book’s title_id alphabetically. Note the use of table aliases to refer to the same table in two contexts. The subquery returns the sum of sales for all books preceding the current book, which is denoted by t1.title_id . See Figure 8.21 for the result. See also “Calculating Running Statistics” in Chapter 9. ✔ Tips ■ You also can use a subquery in a FROM clause. In the Tips in “Aggregating Distinct Values with DISTINCT ” in Chapter 6, I used a FROM subquery to replicate a distinct aggregate function. Listing 8.22 uses a FROM subquery to calculate the greatest number of titles written (or cowritten) by any author. See Figure 8.22 for the result. Note that the outer query uses a table alias ( ta ) and column label ( count_titles ) to reference the inner query’s result. See also the “Column Aliases and WHERE ” sidebar in “Filtering Rows with WHERE ” in Chapter 4. ■ You also can use a subquery as a column expression in UPDATE , INSERT , and DELETE statements (see Chapter 10) but not in an ORDER BY list. continues on next page 273 Subqueries Using Subqueries as Column Expressions Listing 8.21 Compute the running sum of all book sales. See Figure 8.21 for the result. SELECT t1.title_id, t1.sales, (SELECT SUM(t2.sales) FROM titles t2 WHERE t2.title_id <= t1.title_id) AS “Running total” FROM titles t1; Listing title_id sales Running total T01 566 566 T02 9566 10132 T03 25667 35799 T04 13001 48800 T05 201440 250240 T06 11320 261560 T07 1500200 1761760 T08 4095 1765855 T09 5000 1770855 T10 NULL 1770855 T11 94123 1864978 T12 100001 1964979 T13 10467 1975446 Figure 8.21 Result of Listing 8.21. Listing 8.22 Calculate the greatest number of titles written (or cowritten) by any author. See Figure 8.22 for the result. SELECT MAX(ta.count_titles) AS “Max titles” FROM (SELECT COUNT(*) AS count_titles FROM title_authors GROUP BY au_id) ta; Listing Max titles 4 Figure 8.22 Result of Listing 8.22. ■ Use CASE expressions instead of correlated subqueries to implement Listing 8.18 more efficiently (see “Evaluating Conditional Values with CASE ” in Chapter 5): SELECT title_id, MIN(CASE au_order WHEN 1 THEN au_id END) AS “Author 1”, MIN(CASE au_order WHEN 2 THEN au_id END) AS “Author 2”, MIN(CASE au_order WHEN 3 THEN au_id END) AS “Author 3” FROM title_authors GROUP BY title_id ORDER BY title_id ASC; ■ MySQL 4.0 and earlier don’t support subqueries; see the DBMS Tip in “Understanding Subqueries” earlier in this chapter. In Microsoft Access, you must increase the precision of the average-price calcula- tion in Listing 8.17. Use the type-conversion function CDbl() to coerce the average price to a double-precision floating-point number; see the DBMS Tip in “Converting Data Types with CAST() ” in Chapter 5. To run Listing 8.17, change both occurrences of AVG(price) to CDbl(AVG(price)) . 274 Chapter 8 Using Subqueries as Column Expressions Comparing a Subquery Value by Using a Comparison Operator You can use a subquery as a filter in a WHERE clause or HAVING clause by using one of the comparison operators ( = , <> , < , <= , > , or >= ). The important characteristics of a subquery comparison test are: ◆ The comparison operators work the same way as they do in other compar- isons (refer to Table 4.2 in Chapter 4). ◆ The subquery can be simple or correlated (see “Simple and Correlated Subqueries” earlier in this chapter). ◆ The subquery’s SELECT -clause list can include only one expression or column name. ◆ The compared values must have the same data type or must be implicitly convertible to the same type (see “Converting Data Types with CAST() ” in Chapter 5). ◆ String comparisons are case insensitive or case sensitive, depending on your DBMS; see the DBMS Tip in “Filtering Rows with WHERE ” in Chapter 4. ◆ The subquery must return a single value (a one-row, one-column result). A sub- query that returns more than one value will cause an error. ◆ If the subquery result contains zero rows, the comparison test will evaluate to false. 275 Subqueries Comparing a Subquery Value The hard part of writing these statements is getting the subquery to return one value, which you can guarantee several ways: ◆ Using an aggregate function on an ungrouped table always returns a single value (see Chapter 6). ◆ Using a join with the outer query based on a key always returns a single value. To compare a subquery value: ◆ In the WHERE clause of a SELECT state- ment, type: WHERE test_expr op (subquery) test_expr is a literal value, a column name, an expression, or a subquery that returns a single value; op is a comparison operator ( = , <> , < , <= , > , or >= ); and subquery is a scalar subquery that returns exactly one column and zero or one rows. If the value returned by subquery satisfies the comparison to test_expr, the compar- ison condition evaluates to true. The comparison condition is false if the sub- query value doesn’t satisfy the condition, the subquery value is null, or the subquery result is empty (has zero rows). The same syntax applies to a HAVING clause: HAVING test_expr op (subquery) Listing 8.23 tests the result of a simple subquery for equality to list the authors who live in the state in which Tenterhooks Press is located. Only one publisher is named Tenterhooks Press, so the inner WHERE condition guarantees that the inner query returns a single-valued result. See Figure 8.23 for the result. 276 Chapter 8 Comparing a Subquery Value Listing 8.23 List the authors who live in the state in which the publisher Tenterhooks Press is located. See Figure 8.23 for the result. SELECT au_id, au_fname, au_lname, state FROM authors WHERE state = (SELECT state FROM publishers WHERE pub_name = 'Tenterhooks Press'); Listing au_id au_fname au_lname state A03 Hallie Hull CA A04 Klee Hull CA A06 Kellsey CA Figure 8.23 Result of Listing 8.23. Listing 8.24 List the authors who live in the state in which the publisher XXX is located. See Figure 8.24 for the result. SELECT au_id, au_fname, au_lname, state FROM authors WHERE state = (SELECT state FROM publishers WHERE pub_name = 'XXX'); Listing au_id au_fname au_lname state Figure 8.24 Result of Listing 8.24 (an empty table). Listing 8.24 is the same as Listing 8.23 except for the name of the publisher. No publisher named XXX exists, so the sub- query returns an empty table (zero rows). The comparison evaluates to null, so the final result is empty. See Figure 8.24 for the result. Listing 8.25 lists the books with above- average sales. Subqueries introduced with comparison operators often use aggregate functions to return a single value. See Figure 8.25 for the result. To list the authors of the books with above- average sales, I’ve added an inner join to Listing 8.25 (Listing 8.26 and Figure 8.26). 277 Subqueries Comparing a Subquery Value Listing 8.25 List the books with above-average sales. See Figure 8.25 for the result. SELECT title_id, sales FROM titles WHERE sales > (SELECT AVG(sales) FROM titles); Listing title_id sales T05 201440 T07 1500200 Figure 8.25 Result of Listing 8.25. Listing 8.26 List the authors of the books with above- average sales by using a join and a subquery. See Figure 8.26 for the result. SELECT ta.au_id, ta.title_id FROM titles t INNER JOIN title_authors ta ON ta.title_id = t.title_id WHERE sales > (SELECT AVG(sales) FROM titles) ORDER BY ta.au_id ASC, ta.title_id ASC; Listing au_id title_id A02 T07 A04 T05 A04 T07 Figure 8.26 Result of Listing 8.26. Recall from the introduction to this chapter that you can use a subquery almost any- where an expression is allowed, so this syntax is valid: WHERE (subquery) op (subquery) The left subquery must return a single value. Listing 8.27 is equivalent to Listing 8.26, but I’ve removed the inner join and instead placed a correlated subquery to the left of the comparison operator. See Figure 8.27 for the result. You can include GROUP BY or HAVING clauses in a subquery if you know that the GROUP BY or HAVING clause itself returns a single value. Listing 8.28 lists the books priced higher than the highest-priced biography. See Figure 8.28 for the result. 278 Chapter 8 Comparing a Subquery Value Listing 8.27 List the authors of the books with above-average sales by using two subqueries. See Figure 8.27 for the result. SELECT au_id, title_id FROM title_authors ta WHERE (SELECT AVG(sales) FROM titles t WHERE ta.title_id = t.title_id) > (SELECT AVG(sales) FROM titles) ORDER BY au_id ASC, title_id ASC; Listing au_id title_id A02 T07 A04 T05 A04 T07 Figure 8.27 Result of Listing 8.27. Listing 8.28 List the books priced higher than the highest-priced biography. See Figure 8.28 for the result. SELECT title_id, price FROM titles WHERE price > (SELECT MAX(price) FROM titles GROUP BY type HAVING type = 'biography'); Listing title_id price T03 39.95 T13 29.99 Figure 8.28 Result of Listing 8.28. Listing 8.29 uses a subquery in a HAVING clause to list the publishers whose average sales exceed overall average sales. Again, the subquery returns a single value (the average of all sales). See Figure 8.29 for the result. Listing 8.30 uses a correlated subquery to list authors whose royalty share is less than the highest royalty share of any coauthor of a book. The outer query selects the rows of title_authors (that is, of ta1 ) one by one. The subquery calculates the highest royalty share for each book being considered for selection in the outer query. For each possible value of ta1 , the DBMS evaluates the sub- query and puts the row being considered in the result if the royalty share is less than the calculated maximum. See Figure 8.30 for the result. 279 Subqueries Comparing a Subquery Value Listing 8.29 List the publishers whose average sales exceed the overall average sales. See Figure 8.29 for the result. SELECT pub_id, AVG(sales) AS "AVG(sales)" FROM titles GROUP BY pub_id HAVING AVG(sales) > (SELECT AVG(sales) FROM titles); Listing pub_id AVG(sales) P03 506744.33 Figure 8.29 Result of Listing 8.29. Listing 8.30 List authors whose royalty share is less than the highest royalty share of any coauthor of a book. See Figure 8.30 for the result. SELECT ta1.au_id, ta1.title_id, ta1.royalty_share FROM title_authors ta1 WHERE ta1.royalty_share < (SELECT MAX(ta2.royalty_share) FROM title_authors ta2 WHERE ta1.title_id = ta2.title_id); Listing au_id title_id royalty_share A04 T04 0.40 A03 T11 0.30 A04 T11 0.30 Figure 8.30 Result of Listing 8.30. . the items in a SELECT -clause list can be literals, column names, or more-complex expressions. SQL also lets you to embed a subquery in a SELECT -clause list. A subquery that’s used as a column. them in a report or spreadsheet. See Figure 8.18 for the result. Note that in each WHERE clause, SQL qualifies title_id implicitly with the table alias ta referenced in the subquery’s FROM clause;. 3 THEN au_id END) AS “Author 3” FROM title_authors GROUP BY title_id ORDER BY title_id ASC; ■ MySQL 4.0 and earlier don’t support subqueries; see the DBMS Tip in “Understanding Subqueries” earlier

Ngày đăng: 05/07/2014, 05:20

TỪ KHÓA LIÊN QUAN