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

SQL VISUAL QUICKSTART GUIDE- P30 ppsx

10 181 0
Tài liệu đã được kiểm tra trùng lặp

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

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Using Subqueries As Column Expressions
Thể loại Hướng dẫn nhanh
Định dạng
Số trang 10
Dung lượng 175,98 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

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

Trang 1

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 WHEREconditions 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

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.

Trang 2

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

eachWHEREclause, SQL qualifies title_id

implicitly with the table alias tareferenced in the subquery’s FROMclause; 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

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

Trang 3

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.

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.

Trang 4

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

aFROMsubquery to replicate a distinct

aggregate function Listing 8.22 uses a

FROMsubquery 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

anORDER BYlist

continues on next page

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

Listing

Trang 5

■ Use CASEexpressions 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;

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

ofAVG(price)toCDbl(AVG(price))

Trang 6

Comparing a Subquery

Value by Using a

Comparison Operator

You can use a subquery as a filter in a WHERE

clause or HAVINGclause 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

Trang 7

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 WHEREclause 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 HAVINGclause:

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

WHEREcondition guarantees that the inner

query returns a single-valued result See

Figure 8.23 for the result.

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).

Trang 8

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).

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

Trang 9

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 BYorHAVINGclauses

in a subquery if you know that the GROUP BY

orHAVINGclause 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.

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

Trang 10

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

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

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

TỪ KHÓA LIÊN QUAN