result1, result2, ..., resultN are expressions returned when the corresponding value matches the expression comparison_value.. result1, result2, ..., resultN are expressions returned whe
Trang 1In Microsoft SQL Server, use +to
concate-nate strings (Listing 5.28):
‘<’ + CAST(price AS CHAR(8)) + ‘>’
and (Listing 5.29):
CAST(sales AS CHAR(8))
➝ + ‘ copies sold of ‘
➝ + CAST(title_name AS CHAR(20))
Oracle doesn’t allow character conversions
toCHAR(length) if length is shorter than the
source string Instead, use SUBSTR()to
trun-cate strings; see the DBMS Tip in “Extracting
a Substring with SUBSTRING()” earlier in this
chapter To run Listing 5.29, change the CAST()
expression to:
CAST(sales AS CHAR(8))
➝ || ‘ copies sold of ‘
➝ || SUBSTR(title_name, 1, 20)
In MySQL, use SIGNEDinstead of INTEGERfor
data_type, and use CONCAT()to concatenate
strings To run Listings 5.28 and 5.29, change
the CAST()expressions to (Listing 5.28):
CAST(price AS SIGNED)
CONCAT(‘<’, CAST(price AS CHAR(8)),
➝ ’>’)
and (Listing 5.29):
CONCAT(
➝ CAST(sales AS CHAR(8)),
➝ ’ copies sold of ‘,
➝ CAST(title_name AS CHAR(20)))
Oracle treats an empty string as null:
CAST(‘’ AS CHAR)returns null See the DBMS Tip in “Nulls” in Chapter 3
In older PostgreSQL versions, to compare a
value in a NUMERICorDECIMALcolumn with
a real (floating-point) number, you must convert the real number to NUMERICor
DECIMALexplicitly The following statement, for example, fails in older PostgreSQL ver-sions, because the data type of the column
priceisDECIMAL(5,2):
SELECT price FROM titles WHERE price < 20.00;
This statement fixes the problem:
SELECT price FROM titles WHERE price < CAST(20.00 AS DECIMAL);
DBMSs have additional conversion and formatting functions Some examples:
CONVERT()in Microsoft SQL Server and MySQL;TO_CHAR(),TO_DATE(),
TO_TIMESTAMP(), and TO_NUMBER()in
Oracle and PostgreSQL; and TO_CHAR()
andTO_DATE()in DB2 Search your DBMS
documentation for conversion, cast, or
formatting functions.
Trang 2Evaluating Conditional
TheCASEexpression and its shorthand equiv-alents, COALESCE()andNULLIF(), let you take actions based on a condition’s truth value
(true, false, or unknown) The CASE
expres-sion’s important characteristics are:
◆ If you’ve programmed before, you’ll
recognize that CASEprovides SQL the
equivalent of the if-then-else,case, or
switchstatements used in procedural
languages, except that CASEis an expres-sion, not a statement
◆ CASEis used to evaluate several
condi-tions and return a single value for the
first true condition
◆ CASEallows you to display an alternative value to the actual value in a column
CASEmakes no changes to the
underly-ing data
◆ A common use of CASEis to replace codes
or abbreviations with more-readable
values If the column marital_status
contains the integer codes 1, 2, 3, or 4—
meaning single, married, divorced, or
widowed—your human readers will pre-fer to see explanatory text rather than
cryptic codes (Some database designers prefer to use codes, because it’s more effi-cient to store and manage abbreviated
codes than explanatory text.)
◆ CASEhas two formats: simple and
searched The simpleCASEexpression
compares an expression to a set of
sim-ple expressions to determine the result
The searchedCASEexpression evaluates
a set of logical (Boolean) expressions to
determine the result
◆ CASEreturns an optional ELSEresult as the default value if no test condition is true
Trang 3To use a simple CASEexpression:
◆ Type:
CASE comparison_value
WHEN value1 THEN result1
WHEN value2 THEN result2
WHEN valueN THEN resultN
[ELSE default_result]
END
value1, value2, , valueN are expressions.
result1, result2, , resultN are expressions
returned when the corresponding value
matches the expression
comparison_value All expressions must
be of the same type or must be implicitly
convertible to the same type
Each value is compared to comparison_
value in order First, value1 is compared.
If it matches comparison_value, then
result1 is returned; otherwise, value2 is
compared to comparison_value If value2
matches comparison_value, then result2
is returned, and so on If no matches
occur, default_ result is returned If ELSE
default_resultis omitted, ELSE NULLis
assumed (Listing 5.30 and Figure 5.30).
Listing 5.30 Raise the price of history books by 10
percent and psychology books by 20 percent, and leave the prices of other books unchanged See Figure 5.30 for the result.
SELECT title_id, type, price, CASE type WHEN 'history' THEN price * 1.10 WHEN 'psychology' THEN price * 1.20 ELSE price END
AS "New price"
FROM titles ORDER BY type ASC, title_id ASC;
Listing
title_id type price New price - - - -T06 biography 19.95 19.95 T07 biography 23.95 23.95 T10 biography NULL NULL T12 biography 12.99 12.99 T08 children 10.00 10.00 T09 children 13.95 13.95 T03 computer 39.95 39.95 T01 history 21.99 24.19 T02 history 19.95 21.95 T13 history 29.99 32.99 T04 psychology 12.99 15.59 T05 psychology 6.95 8.34 T11 psychology 7.99 9.59
Figure 5.30 Result of Listing 5.30.
Trang 4To use a searched CASEexpression:
◆ Type:
CASE
WHEN condition1 THEN result1 WHEN condition2 THEN result2
WHEN conditionN THEN resultN [ELSE default_result]
END
condition1, condition2, , conditionN are
search conditions (Search conditions have one or more logical expressions, with multiple expressions linked by AND
orOR; see “Filtering Rows with WHERE” in
Chapter 4.) result1, result2, , resultN are
expressions returned when the corre-sponding condition evaluates to true
All expressions must be of the same type
or must be implicitly convertible to the same type
Each condition is evaluated in order
First, condition1 is evaluated If it’s true,
result1 is returned; otherwise, condition2
is evaluated If condition2 is true, result2
is returned, and so on If no conditions
are true, default_result is returned If
ELSE default_resultis omitted, ELSE NULLis assumed (Listing 5.31 and
Figure 5.31).
✔ Tips
■ You can use CASEinSELECT,WHERE, and
ORDER BYclauses or anywhere an expres-sion is allowed
■ When a result is returned, CASEmay or may not evaluate the expressions in any remainingWHENclauses, depending on the DBMS For this reason, you should watch for undesirable side effects, such
as the evaluation of any expression resulting in a division-by-zero error
continues on next page
Listing 5.31 List the books categorized by different
sales ranges, sorted by ascending sales See
Figure 5.31 for the result.
SELECT
title_id,
CASE
WHEN sales IS NULL
THEN 'Unknown'
WHEN sales <= 1000
THEN 'Not more than 1,000'
WHEN sales <= 10000
THEN 'Between 1,001 and 10,000'
WHEN sales <= 100000
THEN 'Between 10,001 and 100,000'
WHEN sales <= 1000000
THEN 'Between 100,001 and 1,000,000'
ELSE 'Over 1,000,000'
END
AS "Sales category"
FROM titles
ORDER BY sales ASC;
Listing
title_id Sales category
-
-T10 Unknown
T01 Not more than 1,000
T08 Between 1,001 and 10,000
T09 Between 1,001 and 10,000
T02 Between 1,001 and 10,000
T13 Between 10,001 and 100,000
T06 Between 10,001 and 100,000
T04 Between 10,001 and 100,000
T03 Between 10,001 and 100,000
T11 Between 10,001 and 100,000
T12 Between 100,001 and 1,000,000
T05 Between 100,001 and 1,000,000
T07 Over 1,000,000
Figure 5.31 Result of Listing 5.31.
Trang 5■ This CASEexpression can help you
pre-vent division-by-zero errors:
CASE
WHEN n <> 0 THEN expr/n
ELSE NULL
END
■ You can use CASEto omit identical
func-tion calls
WHERE some_function(col1) = 10
OR some_function(col1) = 20
is equivalent to
WHERE 1 =
CASE some_function(col1)
WHEN 10 THEN 1
WHEN 20 THEN 1
END
Some DBMS optimizers will run the
CASEform faster
■ The simple CASEexpression is just
short-hand for this searched CASEexpression:
CASE
WHEN comparison_value = value1
THEN result1
WHEN comparison_value = value2
THEN result2
WHEN comparison_value = valueN
THEN resultN
[ELSE default_result]
END
■ Microsoft Access doesn’t
support CASE; instead, use the function Switch(condition1, result1,
condition2, result2, ) To run
Listings 5.30 and 5.31, change the CASE
expressions to (Listing 5.30):
Switch(
➝ type IS NULL, NULL,
➝ type = ‘history’, price * 1.10,
➝ type = ‘psychology’, price *1.20,
➝ type IN (‘biography’,
➝ ’children’, ‘computer’), price)
and (Listing 5.31):
Switch(
➝ sales IS NULL,
➝ ’Unknown’,
➝ sales <= 1000,
➝ ’Not more than 1,000’,
➝ sales <= 10000,
➝ ’Between 1,001 and 10,000’,
➝ sales <= 100000,
➝ ’Between 10,001 and 100,000’,
➝ sales <= 1000000,
➝ ’Between 100,001 and 1,000,000’,
➝ sales > 1000000,
➝ ’Over 1,000,000’)
Oracle 9i and later will run Listings 5.30
and 5.31 To run Listing 5.30 in Oracle 8i,
translate the simple CASEexpression to
a searched CASEexpression, or use the function DECODE(comparison_value,
value1, result1, value2, result2, , default_result):
DECODE(type,
➝ NULL, NULL,
➝ ’history’, price * 1.10,
➝ ’psychology’, price * 1.20,
➝ price)
In older PostgreSQL versions, convert the
floating-point numbers in Listing 5.30
toDECIMAL; see “Converting Data Types with CAST()” earlier in this chapter To run Listing 5.30, change new-price calcula-tions in the CASEexpression to:
price * CAST((1.10) AS DECIMAL) price * CAST((1.20) AS DECIMAL)
Trang 6Checking for Nulls
The function COALESCE()returns the first
non-null expression among its arguments
COALESCE()often is used to display a
specif-ic value instead of a null in a result, whspecif-ich is
helpful if your users find nulls confusing
COALESCE()is just shorthand for a common
form of the searched CASEexpression
COALESCE(expr1, expr2, expr3)
is equivalent to:
CASE
WHEN expr1 IS NOT NULL THEN expr1
WHEN expr2 IS NOT NULL THEN expr2
ELSE expr3
END
To return the first non-null value:
◆ Type:
COALESCE(expr1, expr2, )
expr1, expr2, , represent one or more
comma-separated expressions All
expressions must be of the same type or
must be implicitly convertible to the
same type Each expression is evaluated
in order (left to right) until one evaluates
to non-null and is returned If all the
expressions are null, COALESCE()returns
null (Listing 5.32 and Figure 5.32).
✔ Tips
■ You can use COALESCE()inSELECT,WHERE, andORDER BYclauses or anywhere an expression is allowed
■ Be aware that you can get a null from a column that doesn’t allow nulls; see Figure 3.3 in Chapter 3, for example
■ Microsoft Access doesn’t
support COALESCE(); instead, use the function Switch() To run Listing 5.32, change the COALESCE()
expression to:
Switch(state IS NOT NULL, state,
➝ state IS NULL, ‘N/A’)
Oracle 9i and later will run Listing 5.32.
Oracle 8i doesn’t support COALESCE(); instead, use the function NVL(expr1,
expr2).NVL()takes only two expressions; useCASEfor three or more expressions
To run Listing 5.32 in Oracle 8i, change
the COALESCE()expression to:
NVL(state, ‘N/A’)
Listing 5.32 List the publishers’ locations If the state
is null, print N/A See Figure 5.32 for the result.
SELECT pub_id, city, COALESCE(state, 'N/A') AS "state", country
FROM publishers;
Listing
pub_id city state country - - - -P01 New York NY USA P02 San Francisco CA USA P03 Hamburg N/A Germany P04 Berkeley CA USA
Figure 5.32 Result of Listing 5.32.
Trang 7Comparing Expressions
The function NULLIF()compares two
expressions and returns null if they are
equal or the first expression otherwise
NULLIF()typically is used to convert a
user-defined missing, unknown, or inapplicable
value to null
Rather than use a null, some people prefer to
represent a missing value with, say, the
num-ber –1 or –99, or the string ‘N/A’, ‘Unknown’,
or ‘Missing’ DBMSs have clear rules for
operations that involve nulls, so it’s
some-times desirable to convert user-defined
missing values to nulls If you want to
calcu-late the average of the values in a column, for
example, you’d get the wrong answer if you had
–1 values intermingled with the real,
non-missing values Instead, you can use NULLIF()
to convert the –1 values to nulls, which your
DBMS will ignore during calculations
NULLIF()is just shorthand for a common
form of the searched CASEexpression
NULLIF(expr1, expr2)
is equivalent to:
CASE
WHEN expr1 = expr2 THEN NULL
ELSE expr1
END
Avoiding Division by Zero
Suppose you want to calculate the male–female ratios for various school clubs, but you discover that the following query fails and issues a divide-by-zero error when it tries to calculate ratiofor the Lord of the Rings Club, which has
no women:
SELECT club_id, males, females, males/females AS ratio FROM school_clubs;
You can use NULLIFto avoid division by zero Rewrite the query as:
SELECT club_id, males, females, males/NULLIF(females,0)
AS ratio FROM school_clubs;
Any number divided by NULLgives NULL, and no error is generated
Trang 8To return a null if two expressions are equivalent:
◆ Type:
NULLIF(expr1, expr2) expr1 and expr2 are expressions
NULLIF()compares expr1 and expr2.
If they are equal, the function returns null If they’re unequal, the function
returns expr1 You can’t specify the
literal NULLfor expr1 (Listing 5.33 and
Figure 5.33).
✔ Tips
■ You can use NULLIF()inSELECT,WHERE, andORDER BYclauses or anywhere an expression is allowed
■ Microsoft Access doesn’t
sup-portNULLIF(); instead, use the expression IIf(expr1 = expr2, NULL,
expr1) To run Listing 5.33, change the
NULLIF()expression to:
IIf(contract = 0, NULL, contract)
Oracle 9i and later will run Listing 5.33.
Oracle 8i doesn’t support NULLIF(); instead, use CASE To run Listing 5.33
in Oracle 8i, change the NULLIF()
expression to:
CASE WHEN contract = 0 THEN NULL ELSE contract
END
Listing 5.33 In the table titles , the column contract
contains zero if no book contract exists This query
changes the value zero to null Nonzero values aren’t
affected See Figure 5.33 for the result.
SELECT
title_id,
contract,
NULLIF(contract, 0) AS "Null contract"
FROM titles;
Listing
title_id contract Null contract
- -
-T01 1 1
T02 1 1
T03 1 1
T04 1 1
T05 1 1
T06 1 1
T07 1 1
T08 1 1
T09 1 1
T10 0 NULL T11 1 1
T12 1 1
T13 1 1
Figure 5.33 Result of Listing 5.33.
Trang 10The preceding chapter described scalar
functions, which operate on individual row
values This chapter introduces SQL’s
aggre-gate functions, or set functions, which
oper-ate on a group of values to produce a single, summarizing value You apply an aggregate
to a set of rows, which can be:
◆ All the rows in a table
◆ Only those rows specified by a WHERE
clause
◆ Those rows created by a GROUP BYclause
AGROUP BYclause, which groups rows, often
is used with a HAVINGclause, which filters groups No matter how many rows the input set contains, an aggregate function returns a single statistic: a sum, minimum, or average, for example
The main difference between queries with and without aggregate functions is that nonaggre-gate queries process the rows one by one
Each row is processed independently and put into the result (ORDER BYandDISTINCT
make the DBMS look at all the rows, but they’re essentially postprocessing operations.) Aggregate queries do something completely different: They take a table as a whole and construct new rows from it
Summarizing
and Grouping Data
6