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

oracle 9i the complete reference phần 4 ppsx

103 429 0

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

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Advanced Use of Functions and Variables
Tác giả Loney, Koch
Trường học Unknown
Chuyên ngành Database Management
Thể loại Thesis
Năm xuất bản 2002
Thành phố Unknown
Định dạng
Số trang 103
Dung lượng 1,69 MB

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

Nội dung

For example, selecting the category names from BOOKSHELF yields: select distinct CategoryName from BOOKSHELF; you could avoid the join to the CATEGORY table and perform the replacement v

Trang 1

AS Graph from BOOKSHELF_CHECKOUT

group by Name

order by AVG(ReturnedDate-CheckOutDate);

Day

1 2 3 4 5 6 7 NAME DAYSOUT 0 0 0 0 0 0 0

- -

-DORAH TALBOT 13 ooooooo

EMILY TALBOT 14 ooooooo

JED HOPKINS 18 ooooooooo

GERHARDT KENTGEN 19 ooooooooo

PAT LAVAY 21 oooooooooo

FRED FULLER 24 oooooooooooo

ROLAND BRANDT 52 oooooooooooooooooooooooooo

7 rows selected.

This use of LPAD is similar to what was done in Chapter 13, where the cows and bulls

were shown in their family tree Basically, a lowercaseo is the column here, and it is padded

on the left with a number of additional lowercaseo’s, to the maximum width determined by

AS Graph from BOOKSHELF_CHECKOUT

group by Name

order by AVG(ReturnedDate-CheckOutDate);

Day

1 2 3 4 5 6 7 NAME DAYSOUT 0 0 0 0 0 0 0

Trang 2

300 Part II: SQL and SQL*Plus

Another way to graph the data is by its distribution rather than by person First, a view iscreated that puts each number of days out into its decile Thus 13, 14, 18, and 19 become 10;

20 through 29 become 20; 30 through 39 become 30; and so on:

create or replace view DaysOutRange as

select ROUND((ReturnedDate-CheckOutDate),-1) Decile,

COUNT(*) Counter from BOOKSHELF_CHECKOUT

column Graph format a15

The next SQL determines the count of values that are represented in each decile

select Decile, Counter,

LPAD('o',Counter,'o') AS Graph from DAYSOUTRANGE;

Count

1 1 DECILE COUNTER 5 0 5 - - -

If one of the dates were NULL, the group by output would include a NULL group, with a

count and display similar to those shown in this listing If you want to customize how Oracle

handles books with NULL ReturnedDate values, you can use the NVL function to replace the

NULL value with one of your choosing (such as SysDate) For more complex data replacement

logic, you can use DECODE and CASE, as introduced later in this chapter and more fully

described in Chapter 17

Using TRANSLATE

TRANSLATE converts characters in a string into different characters, based on a substitution plan

you give it, fromif to then:

TRANSLATE(string,if,then)

Trang 3

Chapter 16: Advanced Use of Functions and Variables 301

In the following SQL, the letters in a sentence are replaced Any time an uppercaseT isdetected, it is replaced by an uppercaseT In effect, nothing changes Any time an uppercase

vowel is detected, however, it is replaced by a lowercase version of the same vowel Any

letter not in the TAEIOU string is left alone When a letter is found in TAEIOU, its position is

checked in the TAEIOU string, and the letter there is substituted Thus, the letterE, at position

3 in TAEIOU, is replaced bye, in position 3 of Taeiou:

select TRANSLATE('NOW VOWELS ARE UNDER ATTACK','TAEIOU','Taeiou')

Extending this logic, what happens if theif string is TAEIOU and the then string is only T ?

Checking for the letterE (as in the word VOWELS) finds it in position 3 of TAEIOU There is

no position 3 in thethen string (which is just the letter T ), so the value in position 3 is nothing

SoE is replaced by nothing This same process is applied to all of the vowels They appear in

theif string, but not in the then string As a result, they disappear, as shown here:

select TRANSLATE('NOW VOWELS ARE UNDER ATTACK','TAEIOU','T')

from DUAL;

TRANSLATE('NOWVOWE

-NW VWLS R NDR TTCK

This feature of TRANSLATE, the ability to eliminate characters from a string, can prove very

useful in cleaning up data Recall the magazine titles in Chapter 7:

select Title from MAGAZINE;

TITLE

-THE BARBERS WHO SHAVE -THEMSELVES.

"HUNTING THOREAU IN NEW HAMPSHIRE"

THE ETHNIC NEIGHBORHOOD

RELATIONAL DESIGN AND ENTHALPY

"INTERCONTINENTAL RELATIONS."

The method used in Chapter 7 to clean out the periods and double quotes was a nested

combination of LTRIM and RTRIM:

select LTRIM( RTRIM(Title,'."') ,'"') from MAGAZINE;

Trang 4

The same goal can be accomplished with a single use of TRANSLATE:

select TRANSLATE(Title,'T".','T') AS TITLE

from MAGAZINE;

TITLE

-THE BARBERS WHO SHAVE -THEMSELVES

HUNTING THOREAU IN NEW HAMPSHIRE

THE ETHNIC NEIGHBORHOOD

RELATIONAL DESIGN AND ENTHALPY

INTERCONTINENTAL RELATIONS

In the listing, you have to include one character in thethen string—in this case, the letter T

translates to the letterT All other characters in the if set are eliminated

Complex Cut and Paste

The NAME table contains a list of names as you might receive them from a mailing list company

or another application First name, last name, and initials are all in one column:

column Name format a25

select Name from NAME;

involved using INSTR to locate a space, and using the number it returns in a SUBSTR to clip

out the portion up to that space Here’s an attempt to do just that for the first name:

Trang 5

Chapter 16: Advanced Use of Functions and Variables 303

VALDO has vanished! The problem is that these names are not as consistent as the authors’

names were in Chapter 7 One of these names (probably a magician) is only one name long, so

there is no space for the INSTR to find When INSTR has an unsuccessful search, it returns a 0.

The SUBSTR of the name VALDO, starting at position 1 and going for 0 positions, is nothing, so

he disappears This is solved with DECODE In place of this:

In the preceding example, DECODE tests the value of INSTR(Name, ‘ ‘) If it is equal to 0,

DECODE substitutes 99; otherwise, it returns the default value, which is also INSTR(Name, ‘ ‘).

The choice of 99 as a substitute is arbitrary It will create an effective SUBSTR function for

VALDO that looks like this:

Trang 6

304 Part II: SQL and SQL*Plus

either the location where it found a space or a 0 if it didn’t find any In a name with only one

space, the second and third INSTRs will both return 0 The GREATEST function, therefore, will

pick the number returned by the INSTR that found the space furthest into the name:

select SUBSTR(Name,

GREATEST(INSTR(Name,' '),INSTR(Name,' ',1,2),

INSTR(Name,' ',1,3)) +1) from NAME;

The -1 in the INSTR tells it to start its search in the final position and gobackward, or right

to left, in the Name column When it finds the space, INSTR returns its position, counting from

the left as usual The -1 simply makes INSTR start searching from the end rather than from the

beginning A -2 would make it start searching from the second position from the end, and so on

The +1 in the SUBSTR command has the same purpose as in the previous example: Once the space is found, SUBSTR has to move one position to the right to begin clipping out the Name If

no space is found, the INSTR returns 0, and SUBSTR therefore starts with position 1 That’s why

VALDO made the list

Trang 7

How do you get rid of VALDO? Add an ending position to the SUBSTR instead of its default

(which goes automatically all the way to the end) The ending position is found by using this:

DECODE(INSTR(Name,' '),0,0,LENGTH(Name))

which says, “Find the position of a space in the Name If the position is 0, return 0; otherwise,

return the LENGTH of the Name.” For VALDO, the DECODE produces 0 as the ending position

for SUBSTR, so nothing is displayed For any other name, because there is a space somewhere,

the LENGTH of the Name becomes the ending position for the SUBSTR, so the whole last name

is displayed

This is similar to the DECODE used to extract the first name, except that the value 99 used there has been replaced by LENGTH(Name), which will always work, whereas 99 would fail

for a name longer than 99 characters This won’t matter here, but in other uses of DECODE and

SUBSTR, it could be important:

select SUBSTR(Name,

INSTR(Name,' ',-1)+1, DECODE(INSTR(Name,' '), 0, 0, LENGTH(Name))) from NAME;

A third method to accomplish the same end uses RTRIM Remember that RTRIM eliminates

everything specified in itsset from the right side of a string until it encounters any character not

in itsset The RTRIM here effectively erases all the letters on the right until it hits the first space

(just before the last name) or reaches the beginning of the string:

select

SUBSTR(Name,LENGTH(RTRIM(NAME,'ABCDEFGHIJKLMNOPQRSTUVWXYZ'))

+1) from NAME;

Trang 8

JOSEPHUS

GAMMIERE

LENGTH then measures the resulting string (with the last name erased) This tells you the

position of the space before the last name Add 1 to this number, do a SUBSTR starting there,

and you’ll get just the last name Let’s create a table with FirstName and LastName columns

(you’ll see complete details on creating tables in Chapter 18):

create table TWONAME(

FirstName VARCHAR2(25),

LastName VARCHAR2(25)

);

Table created.

Now, use an insert with a subquery to load the table data with the first and last names from

the NAME table:

insert into TWONAME (FirstName, LastName)

select

SUBSTR(Name,1,DECODE(INSTR(Name,' '),0,99,INSTR(Name,' '))),

SUBSTR(Name,LENGTH(RTRIM(NAME,'ABCDEFGHIJKLMNOPQRSTUVWXYZ'))+1)

from NAME;

Check the contents of the TWONAME table:

select * from TWONAME;

functions work and some thoughtfulness to avoid the kinds of difficulties shown in the examples

so far in this chapter

306 Part II: SQL and SQL*Plus

Trang 9

Chapter 16: Advanced Use of Functions and Variables 307

Counting String Occurrences

Within Larger Strings

You can use a combination of the LENGTH and REPLACE functions to determine how many

times a string (such as ABC) occurs within a larger string (such as ABCDEFABC) The REPLACE

function replaces a character or characters in a string with zero or more characters Thus,

REPLACE('ADAH', 'A', 'BLAH')

will evaluate the string ADAH Everywhere anA is found, it will be replaced with the string

BLAH Thus, the function shown in this example will return the string BLAHDBLAHH

You can use the REPLACE function to eliminate characters from strings For example, you can replace the character string you’re searching for with NULL values Thus,

REPLACE('GEORGE', 'GE', NULL)

returns a value of OR The two separate occurrences of GE in GEORGE were each set to NULL.

You can use the REPLACE function to determine how many times a string (like GE) is found

in a larger string (like GEORGE) First, replace the string with NULL values:

select REPLACE('GEORGE', 'GE', NULL)

More importantly, the LENGTH of the result of that query will provide information about

how many times the string was found The following query will tell you how long the resulting

Trang 10

Now you can tell how many times the string was found If you subtract the length of theshortened string from the original string and divide that difference by the length of the search

string, the result will be the number of times the search string was found:

2This example uses strings instead of character columns in order to be simpler to understand;

in real applications, you would replace the original string (GEORGE) with your column name

The length of the string GEORGE is six characters The length of GEORGE after GE is replaced

with NULL is two characters Therefore, the difference in the lengths of the original and

shortened strings is four characters Dividing four characters by the length of the search string

(two characters) tells you that the string was found twice

The only problem with this method occurs when the search string is zero characters in length(since you cannot divide by zero) Searching for a zero-length string may indicate a problem with

the application logic that initiated the search

Additional Facts About Variables

The command accept forces SQLPLUS to define the variable as equal to the entered value,

and it can do this with a text message, with control over the datatype entered, and even with

the response blanked out from viewing (such as for passwords; see the entry for accept in the

Alphabetical Reference)

You can pass arguments to a start file when it is started by embedding numbered variables

in the select statements (rather than variables with names).

To select all of the checkout records between one date and another, the select statement

might look like this:

select * from BOOKSHELF_CHECKOUT

where CheckOutDate BETWEEN '&1' AND '&2';

That query can be saved as a file (such as checkout.sql) and started from within SQLPLUS:

start checkout.sql 01-JAN-02 31-JAN-02

The start file checkout.sql would begin, with 01-JAN-02 substituted for &1, and 31-JAN-02substituted for &2 As with other variables, character and DATE datatypes must be enclosed

in single quotation marks in the SQL statement One limitation of this is that each argument

following the word start must be a single word without spaces.

Variable substitutions are not restricted to the SQL statement The start file also may usevariables for such things as SQLPLUS commands

308 Part II: SQL and SQL*Plus

Trang 11

Variables can be concatenated simply by pushing them together You can concatenate avariable with a constant by using a period:

select * from BOOKSHELF_CHECKOUT

where CheckOutDate BETWEEN '01-&StartMonth.-02' AND '01-&EndMonth.-02';

This select statement will query for a starting month and an ending month, then build the two

dates using a period as a concatenation operator

NOTE

No period is necessary before the variable—only after it Theampersand (&) tells SQLPLUS that a variable is beginning

Related set Commands

Normally, the ampersand denotes a variable This can be changed with set define followed by

the single symbol that you’d prefer to use to denote a variable

set escape defines a character you can place just in front of the ampersand (or other defined

symbol) so that SQLPLUS will treat the symbol as a literal, not as denoting a variable

set concat can change the default concatenation operator for variables, which is the period,

to another single symbol This variable concatenation is used in addition to, and separately from,

the SQL concatenation operator, which is usually two vertical bars (||)

set scan turns variable substitution off or on for the SQL statement If scan is off, any variable

in a select statement is treated as a literal—for example, &Test is treated as the literal word

&Test, not as the value it is defined as Variables used in SQLPLUS commands, however, are

still substituted as before

As of Oracle9i, set scan on/off is deprecated—use set define in place of set scan.

See the set command in the Alphabetical Reference for additional environment

configuration options

Chapter 16: Advanced Use of Functions and Variables 309

Trang 13

17

DECODE and CASE:

if, then, and else in SQL

Trang 14

T he DECODE function is without doubt one of the most powerful in Oracle’s SQL.It is one of several extensions Oracle added to the standard SQL language This

chapter will explore a number of ways that DECODE can be used, including the generation of “cross-tab” reports As of Oracle9i, you can also use the CASE function and the COALESCE function to execute complex logical tests within

your SQL statements

This is an advanced and often difficult chapter Most of what is illustrated here is unnecessaryfor the vast majority of reporting; don’t be concerned if it seems beyond your needs Its real value

is more for sophisticated reporting and programming

if, then, else

In programming and logic, a common construction of a problem is in the patternif, then, else

For example,if this day is a Saturday, then Adah will play at home; if this day is a Sunday, then

Adah will go to her grandparent’s home;if this day is a holiday, then Adah will go over to Aunt

Dora’s;else Adah will go to school In each case, “this day” was tested, and if it was one of a

list of certain days, then a certain result followed, or else (if it was none of those days) another

result followed DECODE follows this kind of logic Chapter 10 provided an introduction that

demonstrated the basic structure and usage of DECODE.

This is DECODE’s format:

DECODE(value,if1,then1,if2,then2,if3,then3, ,else)

value represents any column in a table (regardless of datatype) or any result of a computation,

such as one date minus another, a SUBSTR of a character column, one number times another,

and so on.value is tested for each row If value equals if1, then the result of the DECODE is

then1; if value equals if2, then the result of the DECODE is then2; and so on, for virtually as

manyif/then pairs as you can construct If value equals none of the ifs, then the result of the

DECODE iselse Each of the ifs, thens, and the else also can be a column or the result of a

function or computation You can have up to 255 elements within the parentheses

Let’s consider the checkout history for the bookshelf, as recorded in the BOOKSHELF_

CHECKOUT table:

column Name format a16

column Title format a24 word_wrapped

set pagesize 60

select * from BOOKSHELF_CHECKOUT;

NAME TITLE CHECKOUTD RETURNEDD

- -

-JED HOPKINS INNUMERACY 01-JAN-02 22-JAN-02

GERHARDT KENTGEN WONDERFUL LIFE 02-JAN-02 02-FEB-02

DORAH TALBOT EITHER/OR 02-JAN-02 10-JAN-02

EMILY TALBOT ANNE OF GREEN GABLES 02-JAN-02 20-JAN-02

PAT LAVAY THE SHIPPING NEWS 02-JAN-02 12-JAN-02

ROLAND BRANDT THE SHIPPING NEWS 12-JAN-02 12-MAR-02

312 Part II: SQL and SQL*Plus

Trang 15

Chapter 17: DECODE and CASE: if, then, and else in SQL 313

ROLAND BRANDT THE DISCOVERERS 12-JAN-02 01-MAR-02

ROLAND BRANDT WEST WITH THE NIGHT 12-JAN-02 01-MAR-02

EMILY TALBOT MIDNIGHT MAGIC 20-JAN-02 03-FEB-02

EMILY TALBOT HARRY POTTER AND THE 03-FEB-02 14-FEB-02

GOBLET OF FIRE PAT LAVAY THE MISMEASURE OF MAN 12-JAN-02 12-FEB-02

DORAH TALBOT POLAR EXPRESS 01-FEB-02 15-FEB-02

DORAH TALBOT GOOD DOG, CARL 01-FEB-02 15-FEB-02

GERHARDT KENTGEN THE MISMEASURE OF MAN 13-FEB-02 05-MAR-02

FRED FULLER JOHN ADAMS 01-FEB-02 01-MAR-02

FRED FULLER TRUMAN 01-MAR-02 20-MAR-02

JED HOPKINS TO KILL A MOCKINGBIRD 15-FEB-02 01-MAR-02

DORAH TALBOT MY LEDGER 15-FEB-02 03-MAR-02

GERHARDT KENTGEN MIDNIGHT MAGIC 05-FEB-02 10-FEB-02

As you look through the checkout list, you realize that some of the books were checked out for a rather long time You can order by the number of days checked out to highlight the readers

who keep books for the longest time:

select Name, Title, ReturnedDate-CheckOutDate DaysOut

from BOOKSHELF_CHECKOUT

order by DaysOut desc;

NAME TITLE DAYSOUT

-

-ROLAND BRANDT THE SHIPPING NEWS 59

ROLAND BRANDT THE DISCOVERERS 48

ROLAND BRANDT WEST WITH THE NIGHT 48

GERHARDT KENTGEN WONDERFUL LIFE 31

PAT LAVAY THE MISMEASURE OF MAN 31

FRED FULLER JOHN ADAMS 28

JED HOPKINS INNUMERACY 21

GERHARDT KENTGEN THE MISMEASURE OF MAN 20

FRED FULLER TRUMAN 19

EMILY TALBOT ANNE OF GREEN GABLES 18

DORAH TALBOT MY LEDGER 16

EMILY TALBOT MIDNIGHT MAGIC 14

DORAH TALBOT POLAR EXPRESS 14

DORAH TALBOT GOOD DOG, CARL 14

JED HOPKINS TO KILL A MOCKINGBIRD 14

EMILY TALBOT HARRY POTTER AND THE 11

GOBLET OF FIRE PAT LAVAY THE SHIPPING NEWS 10

DORAH TALBOT EITHER/OR 8

GERHARDT KENTGEN MIDNIGHT MAGIC 5

But is it specific readers who are the issue, or is it that there are certain categories of books that take longer to read? There are multiple variables involved, and looking at them in isolation

Trang 16

314 Part II: SQL and SQL*Plus

may lead to incorrect decisions What is the average number of days out for the books in each

category?

select B.CategoryName,

MIN(BC.ReturnedDate-BC.CheckOutDate) MinOut, MAX(BC.ReturnedDate-BC.CheckOutDate) MaxOut, AVG(BC.ReturnedDate-BC.CheckOutDate) AvgOut from BOOKSHELF_CHECKOUT BC, BOOKSHELF B

where BC.Title = B.Title

it will be easier to use if you create across-tab report The following listing generates a report

that shows the minimum, maximum, and average days out by person by category This query

uses the DECODE function to perform the calculations.

column CategoryName format a11

select B.CategoryName,

MAX(DECODE(BC.Name, 'FRED FULLER',

BC.ReturnedDate-BC.CheckOutDate,NULL)) MaxFF, AVG(DECODE(BC.Name, 'FRED FULLER',

BC.ReturnedDate-BC.CheckOutDate,NULL)) AvgFF, MAX(DECODE(BC.Name, 'DORAH TALBOT',

BC.ReturnedDate-BC.CheckOutDate,NULL)) MaxDT, AVG(DECODE(BC.Name, 'DORAH TALBOT',

BC.ReturnedDate-BC.CheckOutDate,NULL)) AvgDT, MAX(DECODE(BC.Name, 'GERHARDT KENTGEN',

BC.ReturnedDate-BC.CheckOutDate,NULL)) MaxGK, AVG(DECODE(BC.Name, 'GERHARDT KENTGEN',

BC.ReturnedDate-BC.CheckOutDate,NULL)) AvgGK from BOOKSHELF_CHECKOUT BC, BOOKSHELF B

where BC.Title = B.Title

Trang 17

Chapter 17: DECODE and CASE: if, then, and else in SQL 315

The output now shows the borrowers across the top—Fred Fuller’s maximum checkout time

is the MaxFF column, Dorah Talbot’s is the MaxDT column, and Gerhardt Kentgen’s is the

MaxGK column The output shows that the AdultNF category has the longest average checkout

time for each of the borrowers shown, and that in Gerhardt Kentgen’s case it is significantly longer

than the average checkout time in the other category he checked out

How was this report generated? In the query, the grouping is by CategoryName The MaxFFcolumn query is shown here:

select B.CategoryName,

MAX(DECODE(BC.Name, 'FRED FULLER',

BC.ReturnedDate-BC.CheckOutDate,NULL)) MaxFF,

DECODE is performing an if-then check on the data: If the BC.Name column value in a row

is ‘FRED FULLER’, then calculate the difference between the ReturnedDate and CheckOutDate,

else return a NULL That list of values is then evaluated and the maximum value is returned A

similar set of operations returns the average checkout time for Fred Fuller:

AVG(DECODE(BC.Name, 'FRED FULLER',

BC.ReturnedDate-BC.CheckOutDate,NULL)) AvgFF,

Replacing Values via DECODE

In the last example, DECODE was used to return values conditionally, depending on the Name

of the person who checked out a book You can also use DECODE to replace values in a list.

For example, selecting the category names from BOOKSHELF yields:

select distinct CategoryName from BOOKSHELF;

you could avoid the join to the CATEGORY table and perform the replacement via a DECODE

function, as shown in the following listing Note how DECODE supports multipleif-then

combinations within a single call

select distinct

DECODE(CategoryName,'ADULTFIC','Adult Fiction',

'ADULTNF','Adult Nonfiction',

Trang 18

316 Part II: SQL and SQL*Plus

'ADULTREF','Adult Reference', 'CHILDRENFIC','Children Fiction', 'CHILDRENNF','Children Nonfiction', 'CHILDRENPIC','Children Picturebook', CategoryName)

transaction processing systems in which you are trying to minimize the number of database calls

performed In this example, there is no database access required to change ‘ADULTNF’ to ‘Adult

Nonfiction’; the change occurs within the DECODE function call Note that if there are any other

categories found, theelse condition in the DECODE function returns the original CategoryName

column value

DECODE within DECODE

You can DECODE function calls within other DECODE function calls Let’s say you want to

charge late fees, with different late fee rates for different categories of books Adult category

books may be kept later, but the penalty for late days will be higher

Start with a basic flat rate charge of $0.20 per day for books checked out for more than

14 days:

column Name format a16

column Title format a20 word_wrapped

column DaysOut format 999.99 heading 'Days Out'

column DaysLate format 999.99 heading 'Days Late'

set pagesize 60

break on Name

select Name, Title, ReturnedDate,

ReturnedDate-CheckoutDate as DaysOut /*Count days*/, ReturnedDate-CheckoutDate -14 DaysLate,

(ReturnedDate-CheckoutDate -14)*0.20 LateFee from BOOKSHELF_CHECKOUT

where ReturnedDate-CheckoutDate > 14

order by Name, CheckoutDate;

Trang 19

Chapter 17: DECODE and CASE: if, then, and else in SQL 317

NAME TITLE RETURNEDD Days Out Days Late LATEFEE

- - - -

-DORAH TALBOT MY LEDGER 03-MAR-02 16.00 2.00 4

EMILY TALBOT ANNE OF GREEN GABLES 20-JAN-02 18.00 4.00 8

FRED FULLER JOHN ADAMS 01-MAR-02 28.00 14.00 2.8

TRUMAN 20-MAR-02 19.00 5.00 1 GERHARDT KENTGEN WONDERFUL LIFE 02-FEB-02 31.00 17.00 3.4

THE MISMEASURE OF 05-MAR-02 20.00 6.00 1.2 MAN

JED HOPKINS INNUMERACY 22-JAN-02 21.00 7.00 1.4

PAT LAVAY THE MISMEASURE OF 12-FEB-02 31.00 17.00 3.4

MAN ROLAND BRANDT THE SHIPPING NEWS 12-MAR-02 59.00 45.00 9

THE DISCOVERERS 01-MAR-02 48.00 34.00 6.8 WEST WITH THE NIGHT 01-MAR-02 48.00 34.00 6.8For books in the Adult categories, increase the allowed days late to 21 days This won’tchange the number of days out, but will change the DaysLate column calculation Since

CategoryName is not a column in BOOKSHELF_CHECKOUT, this modification also requires

the addition of the BOOKSHELF table to the from clause.

select BC.Name, BC.Title, BC.ReturnedDate,

BC.ReturnedDate-BC.CheckoutDate as DaysOut /*Count days*/, DECODE(SUBSTR(CategoryName,1,5), 'ADULT',

BC.ReturnedDate-BC.CheckoutDate -21, BC.ReturnedDate-BC.CheckoutDate -14 ) DaysLate, DECODE(SUBSTR(CategoryName,1,5), 'ADULT',

(BC.ReturnedDate-BC.CheckoutDate -21)*0.30, (BC.ReturnedDate-BC.CheckoutDate -14)*0.20 ) LateFee from BOOKSHELF_CHECKOUT BC, BOOKSHELF B

where BC.Title = B.Title

and BC.ReturnedDate-BC.CheckoutDate >

DECODE(SUBSTR(CategoryName,1,5), 'ADULT',21,14) order by BC.Name, BC.CheckoutDate;

NAME TITLE RETURNEDD Days Out Days Late LATEFEE

- - - -

-EMILY TALBOT ANNE OF GREEN GABLES 20-JAN-02 18.00 4.00 8

FRED FULLER JOHN ADAMS 01-MAR-02 28.00 7.00 2.1

GERHARDT KENTGEN WONDERFUL LIFE 02-FEB-02 31.00 10.00 3

PAT LAVAY THE MISMEASURE OF 12-FEB-02 31.00 10.00 3

MAN ROLAND BRANDT THE SHIPPING NEWS 12-MAR-02 59.00 38.00 11.4

THE DISCOVERERS 01-MAR-02 48.00 27.00 8.1 WEST WITH THE NIGHT 01-MAR-02 48.00 27.00 8.1

In the select clause, the query logic for the DaysLate column is

DECODE(SUBSTR(CategoryName,1,5), 'ADULT',

Trang 20

318 Part II: SQL and SQL*Plus

In DECODE’s if-then-else format, this says “If the first five characters of the CategoryName

column match the string ‘ADULT’, then subtract 21 from the number of days late; otherwise,

subtract 14 days.” The LateFee calculation uses similar logic The where clause uses a DECODE

to determine the limiting value for the rows returned—for ADULT category books, allow 21 days;

otherwise, allow 14:

and BC.ReturnedDate-BC.CheckoutDate >

DECODE(SUBSTR(CategoryName,1,5), 'ADULT',21,14)Now add an additional rule: For Adult fiction category books, the late fee will be double thelate fee for other Adult books From the last query, the calculation for LateFee is:

DECODE(SUBSTR(CategoryName,1,5), 'ADULT', (BC.ReturnedDate-BC.CheckoutDate –21)*0.30, (BC.ReturnedDate-BC.CheckoutDate -14)*0.20 ) LateFee

The new rule requires an additional category check within the DECODE already performed.

The new LateFee calculation is shown here:

DECODE(SUBSTR(CategoryName,1,5), 'ADULT', DECODE(SUBSTR(CategoryName,6,3),'FIC', (BC.ReturnedDate-BC.CheckoutDate –21)*0.60, (BC.ReturnedDate-BC.CheckoutDate –21)*0.30), (BC.ReturnedDate-BC.CheckoutDate -14)*0.20 ) LateFee

Reading through the preceding listing, the first DECODE function tells Oracle that if the first five letters of the CategoryName are ‘ADULT’, then perform the second DECODE function.

The second DECODE tells Oracle that if letters 6, 7, and 8 of the CategoryName are ‘FIC’, then

the late fee is $0.60 per day after the twenty-first day; otherwise, it is $0.30 per day after the

twenty-first day At that point, the inner DECODE function completes For the first DECODE

function, the else clause (for non-ADULT category books) then specifies the late fee calculation.

The query and result are shown in the following listing; you can see the impact by comparing

the LateFee column for ‘THE SHIPPING NEWS’ in this report and the last report

select BC.Name, BC.Title, BC.ReturnedDate,

BC.ReturnedDate-BC.CheckoutDate as DaysOut /*Count days*/, DECODE(SUBSTR(CategoryName,1,5), 'ADULT',

BC.ReturnedDate-BC.CheckoutDate -21, BC.ReturnedDate-BC.CheckoutDate -14 ) DaysLate, DECODE(SUBSTR(CategoryName,1,5), 'ADULT',

DECODE(SUBSTR(CategoryName,6,3),'FIC', (BC.ReturnedDate-BC.CheckoutDate -21)*0.60, (BC.ReturnedDate-BC.CheckoutDate -21)*0.30), (BC.ReturnedDate-BC.CheckoutDate -14)*0.20 ) LateFee from BOOKSHELF_CHECKOUT BC, BOOKSHELF B

where BC.Title = B.Title

and BC.ReturnedDate-BC.CheckoutDate >

Trang 21

Chapter 17: DECODE and CASE: if, then, and else in SQL 319

DECODE(SUBSTR(CategoryName,1,5), 'ADULT',21,14) order by BC.Name, BC.CheckoutDate;

NAME TITLE RETURNEDD Days Out Days Late LATEFEE

- - - -

-EMILY TALBOT ANNE OF GREEN GABLES 20-JAN-02 18.00 4.00 8

FRED FULLER JOHN ADAMS 01-MAR-02 28.00 7.00 2.1

GERHARDT KENTGEN WONDERFUL LIFE 02-FEB-02 31.00 10.00 3

PAT LAVAY THE MISMEASURE OF 12-FEB-02 31.00 10.00 3

MAN ROLAND BRANDT THE SHIPPING NEWS 12-MAR-02 59.00 38.00 22.8

THE DISCOVERERS 01-MAR-02 48.00 27.00 8.1 WEST WITH THE NIGHT 01-MAR-02 48.00 27.00 8.1

You can nest DECODEs within other DECODEs to support complex logic within your data processing For example, you may choose to print one column if it has a non-NULL value, and

a second column if the first is NULL With DECODE, that is a simple function call:

DECODE(Column1, NULL, Column2, Column1)

If Column1 is NULL, Column2 will be returned; otherwise, Column1’s non-NULL value will

be returned You could also use NVL or the Oracle9i COALESCE and NULLIF functions to

perform similar logic

COALESCE will return the first non-NULL value encountered in a list of values The last DECODE example could be rewritten as

COALESCE(Column1, Column2)

Since COALESCE is a new function and its name does not clearly convey its usage, be sure

to provide comments within your code to explain the logical tests performed

Greater Than and Less Than in DECODE

DECODE supports logic checks, but how do you do numeric comparisons in this format? The

simplest solution is often to use the SIGN function SIGN returns a 1 if the number is positive, 0

if it is 0, and –1 if the number is negative Because SIGN operates on numbers, you can evaluate

any function that returns a number, including date arithmetic

Let’s modify the LateFee business rule again Using the same base calculation, we’ll modifythe outcome so that we will not collect late fees that are less than or equal to $4.00 Here is the

original LateFee calculation:

DECODE(SUBSTR(CategoryName,1,5), 'ADULT', DECODE(SUBSTR(CategoryName,6,3),'FIC', (BC.ReturnedDate-BC.CheckoutDate –21)*0.60, (BC.ReturnedDate-BC.CheckoutDate –21)*0.30), (BC.ReturnedDate-BC.CheckoutDate -14)*0.20 ) LateFee

Trang 22

320 Part II: SQL and SQL*Plus

If that value is less than 4, we will return a 0; otherwise, we will return the calculated value

To implement this requirement, subtract 4 from the LateFee value; if the result is positive (its

SIGN value is 1), return that result; otherwise, return a 0.

DECODE(SIGN(

DECODE(SUBSTR(CategoryName,1,5), 'ADULT', DECODE(SUBSTR(CategoryName,6,3),'FIC', (BC.ReturnedDate-BC.CheckoutDate –21)*0.60, (BC.ReturnedDate-BC.CheckoutDate –21)*0.30), (BC.ReturnedDate-BC.CheckoutDate -14)*0.20 ) –4), 1,

DECODE(SUBSTR(CategoryName,1,5), 'ADULT', DECODE(SUBSTR(CategoryName,6,3),'FIC', (BC.ReturnedDate-BC.CheckoutDate –21)*0.60, (BC.ReturnedDate-BC.CheckoutDate –21)*0.30), (BC.ReturnedDate-BC.CheckoutDate -14)*0.20 ), 0) LateFee

Building from a simple foundation, this series of DECODE function calls allows you to perform very complex logic on the LateFee calculations The first DECODE evaluates the SIGN

of the next DECODE function result when 4 is subtracted from it If that number is positive, the

calculated late fee is returned; otherwise, a 0 is returned The following listing shows this

calculation and the output that results

select BC.Name, BC.Title, BC.ReturnedDate,

BC.ReturnedDate-BC.CheckoutDate as DaysOut /*Count days*/, DECODE(SUBSTR(CategoryName,1,5), 'ADULT',

BC.ReturnedDate-BC.CheckoutDate -21, BC.ReturnedDate-BC.CheckoutDate -14 ) DaysLate, DECODE(SIGN(

DECODE(SUBSTR(CategoryName,1,5), 'ADULT', DECODE(SUBSTR(CategoryName,6,3),'FIC', (BC.ReturnedDate-BC.CheckoutDate -21)*0.60, (BC.ReturnedDate-BC.CheckoutDate -21)*0.30), (BC.ReturnedDate-BC.CheckoutDate -14)*0.20 ) -4), 1,

DECODE(SUBSTR(CategoryName,1,5), 'ADULT', DECODE(SUBSTR(CategoryName,6,3),'FIC', (BC.ReturnedDate-BC.CheckoutDate -21)*0.60, (BC.ReturnedDate-BC.CheckoutDate -21)*0.30), (BC.ReturnedDate-BC.CheckoutDate -14)*0.20 ), 0) LateFee

from BOOKSHELF_CHECKOUT BC, BOOKSHELF B

where BC.Title = B.Title

and BC.ReturnedDate-BC.CheckoutDate >

DECODE(SUBSTR(CategoryName,1,5), 'ADULT',21,14) order by BC.Name, BC.CheckoutDate;

Trang 23

Chapter 17: DECODE and CASE: if, then, and else in SQL 321

NAME TITLE RETURNEDD Days Out Days Late LATEFEE

- - - -

-EMILY TALBOT ANNE OF GREEN GABLES 20-JAN-02 18.00 4.00 0

FRED FULLER JOHN ADAMS 01-MAR-02 28.00 7.00 0

GERHARDT KENTGEN WONDERFUL LIFE 02-FEB-02 31.00 10.00 0

PAT LAVAY THE MISMEASURE OF 12-FEB-02 31.00 10.00 0

MAN ROLAND BRANDT THE SHIPPING NEWS 12-MAR-02 59.00 38.00 22.8

THE DISCOVERERS 01-MAR-02 48.00 27.00 8.1 WEST WITH THE NIGHT 01-MAR-02 48.00 27.00 8.1You can eliminate the display of the first four rows (with $0 late fees) by making a similar

modification to the where clause.

Using CASE

As of Oracle9i, you can use the CASE function in place of DECODE The CASE function uses

the keywords when, then, else, and end to indicate the logic path followed, which may make

the resulting code easier to follow than an equivalent DECODE.

Consider this simple DECODE example from earlier in this chapter:

select distinct

DECODE(CategoryName,'ADULTFIC','Adult Fiction',

'ADULTNF','Adult Nonfiction', 'ADULTREF','Adult Reference', 'CHILDRENFIC','Children Fiction', 'CHILDRENNF','Children Nonfiction', 'CHILDRENPIC','Children Picturebook', CategoryName)

from BOOKSHELF;

The equivalent CASE function is

select distinct

CASE CategoryName when 'ADULTFIC' then 'Adult Fiction' when 'ADULTNF' then 'Adult Nonfiction' when 'ADULTREF' then 'Adult Reference' when 'CHILDRENFIC' then 'Children Fiction' when 'CHILDRENNF' then 'Children Nonfiction' when 'CHILDRENPIC' then 'Children Picturebook' else CategoryName

end from BOOKSHELF;

CASECATEGORYNAMEWHEN

-Adult Fiction

Trang 24

Children Fiction

Children Nonfiction

Children Picturebook

CASE evaluates the first when clause and returns a match if the limiting condition is met As

with DECODE, you can nest CASE function calls How would you perform the LateFee column

calculations using CASE?

The DECODE function began by calculating a higher rate for ADULT category books:

DECODE(SUBSTR(CategoryName,1,5), 'ADULT', (BC.ReturnedDate-BC.CheckoutDate –21)*0.30, (BC.ReturnedDate-BC.CheckoutDate -14)*0.20 ) LateFee

The CASE equivalent is

end else (BC.ReturnedDate-BC.CheckoutDate -14)*0.20 end

This is more complex, but the logic is very easy to follow, and will usually be simpler to

maintain than the equivalent DECODE clause Now consider the final condition: If the calculated

late fee is less than or equal to $4, return a 0 Since we are using the CASE function, we do not

need to use a SIGN function—we can just use a “<“ comparison as part of the command processing.

The following example shows how to add this check: An additional CASE function is added, and

the inner CASE function call is enclosed in parentheses The result is compared to $4:

CASE when

(CASE SUBSTR(CategoryName,1,5) when 'ADULT' then

CASE SUBSTR(CategoryName,6,3) when 'FIC' then (BC.ReturnedDate-BC.CheckoutDate –21)*0.60 else (BC.ReturnedDate-BC.CheckoutDate –21)*0.30

end else (BC.ReturnedDate-BC.CheckoutDate -14)*0.20 end)

< 4 then 0

322 Part II: SQL and SQL*Plus

Trang 25

Chapter 17: DECODE and CASE: if, then, and else in SQL 323

The else clause for this CASE function call is the same as the inner CASE execution—it calculates

the late fee

else

CASE SUBSTR(CategoryName,1,5) when 'ADULT' then

CASE SUBSTR(CategoryName,6,3) when 'FIC' then (BC.ReturnedDate-BC.CheckoutDate –21)*0.60 else (BC.ReturnedDate-BC.CheckoutDate –21)*0.30

end else (BC.ReturnedDate-BC.CheckoutDate -14)*0.20 end

end

The full query is shown in the following listing, along with its output

column LateFee format 999.99

select BC.Name, BC.Title, BC.ReturnedDate,

BC.ReturnedDate-BC.CheckoutDate as DaysOut /*Count days*/, DECODE(SUBSTR(CategoryName,1,5), 'ADULT',

BC.ReturnedDate-BC.CheckoutDate -21, BC.ReturnedDate-BC.CheckoutDate -14 ) DaysLate, CASE when

(CASE SUBSTR(CategoryName,1,5) when 'ADULT' then

CASE SUBSTR(CategoryName,6,3) when 'FIC' then (BC.ReturnedDate-BC.CheckoutDate -21)*0.60 else (BC.ReturnedDate-BC.CheckoutDate -21)*0.30

end else (BC.ReturnedDate-BC.CheckoutDate -14)*0.20 end)

< 4 then 0 else

CASE SUBSTR(CategoryName,1,5) when 'ADULT' then

CASE SUBSTR(CategoryName,6,3) when 'FIC' then (BC.ReturnedDate-BC.CheckoutDate -21)*0.60 else (BC.ReturnedDate-BC.CheckoutDate -21)*0.30

end else (BC.ReturnedDate-BC.CheckoutDate -14)*0.20 end

end AS LateFee

from BOOKSHELF_CHECKOUT BC, BOOKSHELF B

where BC.Title = B.Title

and BC.ReturnedDate-BC.CheckoutDate >

DECODE(SUBSTR(CategoryName,1,5), 'ADULT',21,14) order by BC.Name, BC.CheckoutDate;

Trang 26

NAME TITLE RETURNEDD Days Out Days Late LATEFEE

- -

-EMILY TALBOT ANNE OF GREEN GABLES 20-JAN-02 18.00 4.00 00

FRED FULLER JOHN ADAMS 01-MAR-02 28.00 7.00 00

GERHARDT KENTGEN WONDERFUL LIFE 02-FEB-02 31.00 10.00 00

PAT LAVAY THE MISMEASURE OF 12-FEB-02 31.00 10.00 00

MAN ROLAND BRANDT THE SHIPPING NEWS 12-MAR-02 59.00 38.00 22.80

THE DISCOVERERS 01-MAR-02 48.00 27.00 8.10 WEST WITH THE NIGHT 01-MAR-02 48.00 27.00 8.10

Comparing the CASE version to the DECODE version earlier in this chapter, you can see that the CASE command is six lines longer but is simpler to read and maintain For Oracle9i

databases, CASE offers a powerful alternative to DECODE—and both CASE and DECODE

provide solid solutions when you need to perform logic within your queries

324 Part II: SQL and SQL*Plus

Trang 27

18

Creating, Dropping, and Altering Tables

and Views

Trang 28

U ntil now, the emphasis of this book has been on using tables This chapter looksat creating, dropping, and changing tables, creating views, and options such as

index-organized or partitioned tables You’ve seen numerous create table

commands to this point; this chapter will reinforce those examples and showhow to use the latest options

Creating a Table

Consider the TROUBLE table This is similar to the COMFORT table discussed earlier in the book,

but is used to track cities with unusual weather patterns

describe TROUBLE

Name Null? Type

-

CITY NOT NULL VARCHAR2(13)

SAMPLEDATE NOT NULL DATE

NOON NUMBER(3,1)

MIDNIGHT NUMBER(3,1)

PRECIPITATION NUMBER

The columns in the TROUBLE table represent the three major datatypes in Oracle—

VARCHAR2, DATE, and NUMBER Here is the SQL that created this Oracle table:

create table TROUBLE (

City VARCHAR2(13) NOT NULL,

SampleDate DATE NOT NULL,

Noon NUMBER(3,1),

Midnight NUMBER(3,1),

Precipitation NUMBER

);

These are the basic elements of this command:

The words create table

■ The name of the table

■ An opening parenthesis

■ Column definitions

■ A closing parenthesis

■ A SQL terminatorThe individual column definitions are separated by commas There is no comma after the lastcolumn definition The table and column names must start with a letter of the alphabet, but may

include letters, numbers, and underscores Names may be 1 to 30 characters in length, must be

326 Part II: SQL and SQL*Plus

Trang 29

unique within the table, and cannot be an Oracle reserved word (see “Object Names” in the

Alphabetical Reference of this book)

If the names are not within double quotes, case does not matter in creating a table There are

no options for DATE datatypes Character datatypes must have their maximum length specified

NUMBERs may be either high-precision (up to 38 digits) or specified-precision, based on the

maximum number of digits and the number of places allowed to the right of the decimal (an

Amount field for U.S currency, for instance, would have only two decimal places)

NOTE

Do not enclose table and column names within double quotes, orcase will matter This can be disastrous for your users or developers

See Part IV of this book for additional create table options for object-relational features.

Character Width and NUMBER Precision

Specifying the maximum length for character (CHAR and VARCHAR2) columns and the precision

for NUMBER columns has consequences that must be considered during the design of the table

Improper decisions can be corrected later, using the alter table command, but the process can

be difficult

Deciding on a Proper Width

A character column that is not wide enough for the data you want to put in it will cause an insert

to fail and result in this error message:

ERROR at line 1: ORA-01401: inserted value too large for column

The maximum width for CHAR (fixed-length) columns is 2,000 characters VARCHAR2(varying-length character) columns can have up to 4,000 characters In assigning width to a

column, allot enough space to allow for all future possibilities A CHAR(15) for a city name,

for instance, is just going to get you in trouble later on You’ll have to either alter the table or

truncate or distort the names of some cities

NOTE

There is no penalty in Oracle for defining a wide VARCHAR2column Oracle is clever enough not to store blank spaces at theend of VARCHAR2 columns The city name SAN FRANCISCO, forexample, will be stored in 13 spaces even if you’ve defined the

column as VARCHAR2(50) And if a column has nothing in it (NULL),

Oracle will store nothing in the column, not even a blank space (itdoes store a couple of bytes of internal database control information,but this is unaffected by the size you specify for the column) Theonly effect that choosing a higher number will have is in the defaultSQLPLUS column formatting SQLPLUS will create a default headingthe same width as the VARCHAR2 definition

Chapter 18: Creating, Dropping, and Altering Tables and Views 327

Trang 30

328 Part II: SQL and SQL*Plus

Choosing NUMBER Precision

A NUMBER column with incorrect precision will have one of two consequences Oracle will

either reject the attempt to insert the row of data, or drop some of the data’s precision Here are

four rows of data about to be entered into Oracle:

insert into TROUBLE values

('PLEASANT LAKE','21-MAR-01', 39.99, -1.31, 3.6);

insert into TROUBLE values

('PLEASANT LAKE','22-JUN-01', 101.44, 86.2, 1.63);

insert into TROUBLE values

('PLEASANT LAKE','23-SEP-01', 92.85, 79.6, 1.00003);

insert into TROUBLE values

('PLEASANT LAKE','22-DEC-01', -17.445, -10.4, 2.4);

These are the results of this attempt:

insert into TROUBLE values ('PLEASANT LAKE',

ORA-01438: value larger than specified precision allows for this column

insert into TROUBLE values ('PLEASANT LAKE',

The 3 here indicates the maximum number of digits Oracle will store The 1 means that one of

those three digits is reserved for a position to the right of the decimal point Thus, 12.3 would be

a legitimate number, but 123.4 would not be

Trang 31

Note that the error here is caused by the 101, not the 44, because NUMBER(3,1) leaves onlytwo positions available to the left of the decimal point The 44 will not cause the “value larger

than specified precision” error It would simply be rounded to one decimal place This will be

demonstrated shortly, but first, look at the results of a query of the four rows we’ve attempted to insert:

select * from TROUBLE;

CITY SAMPLEDAT NOON MIDNIGHT PRECIPITATION

- - -

-PLEASANT LAKE 21-MAR-01 40 -1.3 3.6

PLEASANT LAKE 23-SEP-01 92.9 79.6 1.00003

PLEASANT LAKE 22-DEC-01 -17.4 -10.4 2.4

The three rows were successfully inserted; only the problematic row is missing Oracle automatically

backed out the single insert statement that failed.

Rounding During Insertion

If you correct the create table statement and increase the number of digits available for Noon

and Midnight, as shown here:

drop table TROUBLE;

create table TROUBLE (

City VARCHAR2(13) NOT NULL,

SampleDate DATE NOT NULL,

Noon NUMBER(4,1),

Midnight NUMBER(4,1),

Precipitation NUMBER

);

then the four insert statements will all be successful A query now will reveal this:

insert into TROUBLE values

('PLEASANT LAKE','21-MAR-01', 39.99, -1.31, 3.6);

insert into TROUBLE values

('PLEASANT LAKE','22-JUN-01', 101.44, 86.2, 1.63);

insert into TROUBLE values

('PLEASANT LAKE','23-SEP-01', 92.85, 79.6, 1.00003);

insert into TROUBLE values

('PLEASANT LAKE','22-DEC-01', -17.445, -10.4, 2.4);

select * from TROUBLE;

Chapter 18: Creating, Dropping, and Altering Tables and Views 329

Trang 32

CITY SAMPLEDAT NOON MIDNIGHT PRECIPITATION

- - -

-PLEASANT LAKE 21-MAR-01 40 -1.3 3.6

PLEASANT LAKE 22-JUN-01 101.4 86.2 1.63

PLEASANT LAKE 23-SEP-01 92.9 79.6 1.00003

PLEASANT LAKE 22-DEC-01 -17.4 -10.4 2.4

Look at the first insert statement The value for Noon is 39.99 In the query, it is rounded to

40 Midnight in the insert is -1.31 In the query it is -1.3 Oracle rounds the number based on the

digit just to the right of the allowed precision Table 18-1 shows the effects of precision in several

examples See Chapter 8 for examples of the ROUND function.

330 Part II: SQL and SQL*Plus

For precision of NUMBER(4,1)

Trang 33

Constraints in create table

The create table statement lets you enforce several different kinds of constraints on a table: candidate

keys, primary keys, foreign keys, and check conditions A constraint clause can constrain a single

column or group of columns in a table The point of these constraints is to get Oracle to do most

of the work in maintaining the integrity of your database The more constraints you add to a table

definition, the less work you have to do in applications to maintain the data On the other hand,

the more constraints there are in a table, the longer it takes to update the data

There are two ways to specify constraints: as part of the column definition (acolumn constraint)

or at the end of the create table statement (atable constraint) Clauses that constrain several

columns must be table constraints

The Candidate Key

Acandidate key is a combination of one or more columns, the values of which uniquely identify

each row of a table The following listing shows the creation of a UNIQUE constraint for the

TROUBLE table:

drop table TROUBLE;

create table TROUBLE (

City VARCHAR2(13) NOT NULL,

SampleDate DATE NOT NULL,

Chapter 18: Creating, Dropping, and Altering Tables and Views 331

Trang 34

The key of this table is the combination of City and SampleDate Notice that both columns

are also declared to be NOT NULL This feature allows you to prevent data from being entered

into the table without certain columns having data in them Clearly, temperature and precipitation

information is not useful without knowing where or when it was collected This technique is

common for columns that are the primary key of a table, but is also useful if certain columns are

critical for the row of data to be meaningful If NOT NULL isn’t specified, the column can have

NULL values.

The Primary Key

Theprimary key of a table is one of the candidate keys that you give some special characteristics

You can have only one primary key, and a primary key column cannot contain NULLs:

drop table TROUBLE;

create table TROUBLE (

This create table statement has the same effect as the previous one, except that you can have

several UNIQUE constraints but only one PRIMARY KEY constraint

For single-column primary or candidate keys, you can define the key on the column with acolumn constraint instead of a table constraint:

create table AUTHOR

(AuthorName VARCHAR2(50) primary key,

Comments VARCHAR2(100));

In this case, the AuthorName column is the primary key, and Oracle will generate a name for the

PRIMARY KEY constraint This is not recommended if you want to enforce a common naming

standard for keys, as discussed later in “Naming Constraints.”

Designating Index Tablespaces

UNIQUE and PRIMARY KEY constraints create indexes Unless you tell Oracle differently, those

indexes will be placed in your default tablespace (tablespaces are described fully in Chapter 20)

To specify a different tablespace, use the using index tablespace clause of the create table

command, as shown in the following listing:

create table AUTHOR2

(AuthorName VARCHAR2(50),

Comments VARCHAR2(100),

constraint AUTHOR_PK primary key (AuthorName)

using index tablespace USERS);

332 Part II: SQL and SQL*Plus

Trang 35

The index associated with the AUTHOR_PK primary key constraint will be placed in the USERS

tablespace See Chapter 20 for details on the use of tablespaces

NOTE

In a default installation, the USERS tablespace is created and is thedefault tablespace

The Foreign Key

Aforeign key is a combination of columns with values based on the primary key values from

another table A foreign key constraint, also known as areferential integrity constraint, specifies

that the values of the foreign key correspond to actual values of the primary key in the other

table In the BOOKSHELF table, for example, the CategoryName column refers to values for the

CategoryName column in the CATEGORY table:

create table BOOKSHELF

(Title VARCHAR2(100) primary key,

You can refer to a primary or unique key, even in the same table However, you can’t refer to

a table in a remote database in the references clause You can use the table form (which is used

here to create a PRIMARY KEY on the TROUBLE table) instead of the column form to specify

foreign keys with multiple columns

Sometimes you may want to delete these dependent rows when you delete the row theydepend on In the case of BOOKSHELF and CATEGORY, if you delete a CategoryName from

CATEGORY, you may want to make the matching BOOKSHELF CategoryName column values

NULL In another case, you might want to delete the whole row The clause on delete cascade

added to the references clause tells Oracle to delete the dependent row when you delete the

corresponding row in the parent table This action automatically maintains referential integrity

For more information on the clauses on delete cascade and references, consult “Integrity

Constraint” in the Alphabetical Reference of this book

The CHECK Constraint

Many columns must have values that are within a certain range or that satisfy certain conditions

With aCHECK constraint, you can specify an expression that must always be true for every row

in the table For example, the RATING table stores the valid ratings; to limit the available values

beyond the limits enforced by the column definition, you can use a CHECK constraint, as shown

in the following listing:

create table RATING_WITH_CHECK

(Rating VARCHAR2(2) CHECK (Rating <= 9),

RatingDescription VARCHAR2(50));

Chapter 18: Creating, Dropping, and Altering Tables and Views 333

Trang 36

A column-level CHECK constraint can’t refer to values in other rows; it can’t use the columns SysDate, UID, User, UserEnv, CurrVal, NextVal, Level, or RowNum You can use the

pseudo-table constraint form (as opposed to the column constraint form) to refer to multiple columns in

a CHECK constraint

Naming Constraints

You can name your constraints If you use an effective naming scheme for your constraint names,

you will be better able to identify and manage the constraints The name of a constraint should

identify the table it acts upon and the type of constraint it represents For example, the primary

key on the TROUBLE table could be named TROUBLE_PK

You can specify a name for a constraint when you create the constraint If you do not specify

a name for the constraint, then Oracle will generate a name Most of Oracle’s generated constraint

names are of the form SYS_C######; for example, SYS_C000145 Since the system-generated

constraint name does not tell you anything about the table or the constraint, you should name

your constraints

In the following example, the PRIMARY KEY constraint is created, and named, as part of the

create table command for the TROUBLE table Notice the constraint clause:

create table TROUBLE (

The constraint clause of the create table command names the constraint (in this case,

TROUBLE_PK) You may use this constraint name later when enabling or disabling constraints

Dropping Tables

Dropping tables is very simple You use the words drop table and the table name, as shown here:

drop table TROUBLE;

Table dropped.

You drop a table only when you no longer need it In Oracle, the truncate command lets you

remove all the rows in the table and reclaim the space for other uses without removing the table

definition from the database

Truncating is also very simple:

truncate table TROUBLE;

Table truncated.

334 Part II: SQL and SQL*Plus

Trang 37

Truncating can’t be rolled back If there are triggers that delete rows that depend on rows inthe table, truncating does not execute those triggers You should besure you really want to truncate

before doing it

Altering Tables

Tables can be altered in one of three ways: by adding a column to an existing table; by changing

a column’s definition; or by dropping a column Adding a column is straightforward, and similar

to creating a table Suppose you decide to add two new columns to the TROUBLE table: Condition,

which you believe should be NOT NULL, and Wind, for the wind speed The first attempt starts

by creating the table and populating it with a few records:

create table TROUBLE (

insert into TROUBLE values

('PLEASANT LAKE','22-JUN-01', 101.44, 86.2, 1.63);

insert into TROUBLE values

('PLEASANT LAKE','23-SEP-01', 92.85, 79.6, 1.00003);

insert into TROUBLE values

('PLEASANT LAKE','22-DEC-01', -17.445, -10.4, 2.4);

The first attempt at adding the new columns looks like this:

alter table TROUBLE add (

Condition VARCHAR2(9) NOT NULL,

Wind NUMBER(3)

);

alter table TROUBLE add (

* ERROR at line 1: ORA-01758: table must be empty to add

mandatory (NOT NULL) column

Chapter 18: Creating, Dropping, and Altering Tables and Views 335

Trang 38

336 Part II: SQL and SQL*Plus

You get an error message because you cannot add a column defined as NOT NULL—when

you try to add it, the column won’t have anything in it Each row in the table would have a new

empty column defined as NOT NULL.

The alter table command’s add clause will work with a NOT NULL column if the table is empty, but usually, it is impractical to empty a table of all its rows just to add a NOT NULL column And you

can’t use Export and Import if you add a column after Exporting but before Importing

The alternative is to first alter the table by adding the column without the NOT NULL restriction:

alter table TROUBLE add (

Condition VARCHAR2(9),

Wind NUMBER(3)

);

Table altered.

Then, fill the column with data for every row (either with legitimate data or a placeholder until

legitimate data can be obtained):

update TROUBLE set Condition = 'SUNNY';

Finally, alter the table again, and modify the column definition to NOT NULL:

alter table TROUBLE modify (

Condition VARCHAR2(9) NOT NULL,

-CITY NOT NULL VARCHAR2(17)

SAMPLEDATE NOT NULL DATE

The table contains the following:

select * from TROUBLE;

Trang 39

Chapter 18: Creating, Dropping, and Altering Tables and Views 337

CITY SAMPLEDAT NOON MIDNIGHT PRECIPITATION CONDITION WIND

- - - -

PLEASANT LAKE 21-MAR-99 40 -1.3 3.6 SUNNY

PLEASANT LAKE 22-JUN-99 101.4 86.2 1.63 SUNNY

PLEASANT LAKE 23-SEP-99 92.9 79.6 1.00003 SUNNY

PLEASANT LAKE 22-DEC-99 -17.4 -10.4 2.4 SUNNY

Here you see the effect of the changes City is now 17 characters wide instead of 13 Condition

has been added to the table as NOT NULL and is SUNNY (temporarily) WIND has been added,

The Rules for Adding or Modifying a Column

These are the rules for adding a column to a table:

You may add a column at any time if NOT NULL isn’t specified.

You may add a NOT NULL column in three steps:

1 Add the column without NOT NULL specified.

2. Fill every row in that column with data

3 Modify the column to be NOT NULL.

NOTE

If you use the default clause when adding a column, Oracle will

update each row with that default value when it adds the column;

these updates fire any AFTER UPDATE triggers defined on the table(see Chapter 28)

These are the rules for modifying a column:

■ You can increase a character column’s width at any time

■ You can increase the number of digits in a NUMBER column at any time

■ You can increase or decrease the number of decimal places in a NUMBER column

at any time

In addition, if a column is NULL for every row of the table, you can make any of these changes:

■ You can change the column’s datatype

■ You can decrease a character column’s width

Trang 40

You can only change the datatype of a column if the column is empty (NULL) in all rows of

the table

Exceptions for LONG-LOB Column Changes

There is one notable exception to the restrictions on datatype changes Oracle supports the changing

of LONG datatype columns to LOB datatypes even if there is data already in the LONG column

The following listing illustrates this functionality:

create table LONGTEST

As of Oracle8i, you can drop a column from a table Dropping a column is more complicated

than adding or modifying a column, because of the additional work that Oracle has to do Just

removing the column from the list of columns in the table—so it doesn’t show up when you

select * from the table—is easy It’s recovering the space that was actually taken up by the

column values that is more complex, and potentially very time-consuming for the database For

this reason, you can drop a column immediately or you can mark it as “unused,” to be dropped

at a later time If the column is dropped immediately, the action may impact performance If the

column is marked as unused, there will be no impact on performance The column can actually

be dropped at a later time when the database is less heavily used

To drop a column, use either the set unused clause or the drop clause of the alter table

command You cannot drop a pseudo-column, a column of a nested table, or a partition key column

In the following example, column Wind is dropped from the TROUBLE table:

338 Part II: SQL and SQL*Plus

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

TỪ KHÓA LIÊN QUAN