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

Oracle Database 10g The Complete Reference phần 3 pdf

135 395 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

Định dạng
Số trang 135
Dung lượng 557,84 KB

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

Nội dung

Type --- --- ---CITY NOT NULL VARCHAR213 SAMPLEDATE NOT NULL DATE NOON NUMBER3,1 MIDNIGHT NUMBER3,1 PRECIPITATION NUMBER To add a new row to this table, use this: insert into COMFORT va

Trang 1

A third option, full outer join, returns all rows from both tables Rows that do not satisfy the

on condition return NULL values In this example, there are no rows to satisfy this condition, so

the query returns the same 31 rows as the right outer join.

select B.Title, MAX(BC.ReturnedDate - BC.CheckoutDate)

"Most Days Out"

from BOOKSHELF_CHECKOUT BC full outer join BOOKSHELF B

on BC.Title = B.Title group by B.Title;

Prior to Oracle9i, you can generate the full outer join results by performing two separate

outer joins—using each table as the outer table—and using a union operation to combine the

results in a single query

Replacing NOT IN with an Outer Join

The various logical tests that can be done in a where clause all have their separate performance

measures A NOT IN test may force a full read of the table in the subquery select For example,

what books were not checked out? You could write a query like this:

select Title

from BOOKSHELF

where Title not in

(select Title from BOOKSHELF_CHECKOUT) order by Title;

TITLE

-BOX SOCIALS

CHARLOTTE'S WEB

COMPLETE POEMS OF JOHN KEATS

EMMA WHO SAVED MY LIFE

GOSPEL

JOURNALS OF LEWIS AND CLARK

KIERKEGAARD ANTHOLOGY

LETTERS AND PAPERS FROM PRISON

PREACHING TO HEAD AND HEART

RUNAWAY BUNNY

SHOELESS JOE

THE COST OF DISCIPLESHIP

THE GOOD BOOK

TRUMPET OF THE SWAN

UNDER THE EYE OF THE CLOCK

This is typically the way such a query would be written, even though experienced Oracleusers know it may be slow—you may be forcing Oracle to perform a time-intensive full table

scan on the BOOKSHELF_CHECKOUT table The optimizer may internally transform that NOT

IN to one of the following functionally identical approaches The following query uses an outer

Trang 2

join and produces the same result The difference is that this one will be efficient because the

optimizer can take advantage of indexes on the join columns:

select distinct B.Title

from BOOKSHELF_CHECKOUT BC right outer join BOOKSHELF B

on BC.Title = B.Title where BC.Title is NULL

COMPLETE POEMS OF JOHN KEATS

EMMA WHO SAVED MY LIFE

GOSPEL

JOURNALS OF LEWIS AND CLARK

KIERKEGAARD ANTHOLOGY

LETTERS AND PAPERS FROM PRISON

PREACHING TO HEAD AND HEART

RUNAWAY BUNNY

SHOELESS JOE

THE COST OF DISCIPLESHIP

THE GOOD BOOK

TRUMPET OF THE SWAN

UNDER THE EYE OF THE CLOCK

Why does it work and give the same results as the NOT IN? The outer join between the two

tables ensures that all rows are available for the test, including those titles for whom no checkout

records are listed in the BOOKSHELF_CHECKOUT table The line

where BC.Title is NULL

produces only those titles that don’t appear in the BOOKSHELF_CHECKOUT table (and are

therefore returned as NULL titles by Oracle) The logic here is obscure, but it works The best

way to use this technique is simply to follow the model

Replacing NOT IN with NOT EXISTS

A more common way of performing this type of query requires using the NOT EXISTS clause.

NOT EXISTS is typically used to determine which values in one table do not have matching

values in another table In usage, it is identical to the EXISTS clause; in the following example,

you’ll see the difference in the query logic and the records returned

NOT EXISTS allows you to use a correlated subquery to eliminate from a table all records

that may successfully be joined to another table For this example, that means you can eliminate

from the BOOKSHELF table all titles that are present in the Title column of the BOOKSHELF_

CHECKOUT table The following query shows how this is done:

select B.Title

from BOOKSHELF B

Trang 3

where not exists

(select 'x' from BOOKSHELF_CHECKOUT BC where BC.Title = B.Title)

COMPLETE POEMS OF JOHN KEATS

EMMA WHO SAVED MY LIFE

GOSPEL

JOURNALS OF LEWIS AND CLARK

KIERKEGAARD ANTHOLOGY

LETTERS AND PAPERS FROM PRISON

PREACHING TO HEAD AND HEART

RUNAWAY BUNNY

SHOELESS JOE

THE COST OF DISCIPLESHIP

THE GOOD BOOK

TRUMPET OF THE SWAN

UNDER THE EYE OF THE CLOCK

This query shows the books that have not been checked out, as previously shown via the NOT

IN and outer join methods How does this query work?

For each record in the BOOKSHELF table, the NOT EXISTS subquery is checked If the join of

that record to the BOOKSHELF_CHECKOUT table returns a row, then the results of the subquery

EXIST NOT EXISTS tells the query to reverse that return code; therefore, any row in BOOKSHELF

that can be successfully joined to BOOKSHELF_CHECKOUT will not be returned by the outer query

The only rows left are the BOOKSHELF rows that do not have a matching row in BOOKSHELF_

CHECKOUT

NOT EXISTS is a very efficient way to perform this type of query, especially when multiple columns are used for the join Because it uses a join, NOT EXISTS is frequently able to use

available indexes, whereas NOT IN may not be able to use those indexes The ability to use

indexes for this type of query can have a dramatic impact on the query’s performance

Natural and Inner Joins

You can use the natural keyword to indicate that a join should be performed based on all columns

that have the same name in the two tables being joined For example, what titles in BOOK_ORDER

match those already in BOOKSHELF?

Trang 4

The natural join returned the results as if you had typed in the following:

select BO.Title

from BOOK_ORDER BO, BOOKSHELF

where BO.Title = BOOKSHELF.Title

and BO.Publisher = BOOKSHELF.Publisher and BO.CategoryName = BOOKSHELF.CategoryName;

The join was performed based on the columns the two tables had in common

Support for inner join syntax was introduced in Oracle9i Inner joins are the default—theyreturn the rows the two tables have in common, and are the alternative to outer joins Note that

they support the on and using clauses, so you can specify your join criteria as shown in the following

UNION, INTERSECT, and MINUS

Sometimes you need to combine information of a similar type from more than one table A classic

example of this is merging two or more mailing lists prior to a mailing campaign Depending on the

purpose of a particular mailing, you might want to send letters to any of these combinations of people:

■ Everyone in both lists (while avoiding sending two letters to someone who happens to

be in both lists)

■ Only those people who are in both lists

■ Those people in only one of the lists

These three combinations of lists are known in Oracle as UNION, INTERSECT, and MINUS.

In the following examples, you will see how to use these three clauses to manage the results of

multiple queries The examples will compare the books on hand (BOOKSHELF) with those on

Trang 5

select Title from BOOK_ORDER;

If we UNION them together, how many rows are returned?

select Title from BOOKSHELF

Where did the extra record go? The problem is that one of the Title values in BOOK_ORDER

is already in the BOOKSHELF table To show the duplicates, use UNION ALL instead of UNION:

select Title from BOOKSHELF

Trang 6

The duplicate title is now listed twice.

In the following, the two lists of books are intersected This list contains only those namesthat are inboth underlying tables (note that the restriction on Title < ‘M%’ has been eliminated

for this example):

select Title from BOOKSHELF

Next, the list of new books (in BOOK_ORDER but not already in BOOKSHELF) is generated,

via the MINUS operator:

select Title from BOOK_ORDER

You could have also used MINUS to show which books had not been checked out:

select Title from BOOKSHELF

minus

Trang 7

select Title from BOOKSHELF_CHECKOUT;

TITLE

-BOX SOCIALS

CHARLOTTE'S WEB

COMPLETE POEMS OF JOHN KEATS

EMMA WHO SAVED MY LIFE

GOSPEL

JOURNALS OF LEWIS AND CLARK

KIERKEGAARD ANTHOLOGY

LETTERS AND PAPERS FROM PRISON

PREACHING TO HEAD AND HEART

RUNAWAY BUNNY

SHOELESS JOE

THE COST OF DISCIPLESHIP

THE GOOD BOOK

TRUMPET OF THE SWAN

UNDER THE EYE OF THE CLOCK

15 rows selected.

You’ve just learned the basics of UNION, INTERSECT, and MINUS Now let’s go into detail.

In combining two tables, Oracle does not concern itself with column names on either side of the

combination operator—that is, Oracle will require that each select statement be valid and have

valid columns for its own table(s), but the column names in the first select statement do not have

to be the same as those in the second Oracle does have these stipulations:

The select statements must have the same number of columns If the two tables being

queried have differing numbers of columns selected, you can select strings in place ofcolumns to make the two queries’ column lists match

The corresponding columns in the select statements must be the same datatype (they

needn’t be the same length)

When ordering the output, Oracle uses the column names from the first select statement in giving the query results Consequently, only column names from the first select statement can be

used in the order by.

You can use combination operators with two or more tables, but when you do, precedence

becomes an issue, especially if INTERSECT and MINUS appear Use parentheses to force the order

you want

IN Subqueries

Combination operators can be used in subqueries, but you must be careful with precedence

A query of the form

select ColA from TABLE_A

where ColA in

Trang 8

(select Col1 from TABLE_1)

union

(select Col2 from TABLE_2);

is poorly written and ambiguous Which will be performed first, the union of the two queries as

part of a single where clause, or the in clause based on the query of TABLE_1, followed by a union

of that result with TABLE_2? Use parentheses to clarify your meaning and enforce the proper

precedence of operations The in clause is always given a higher precedence than union, unless

you use parentheses to alter the way the query is executed If you want the union to have higher

precedence, use parentheses:

select ColA from TABLE_A

where ColA in

(select Col1 from TABLE_1

union

select Col2 from TABLE_2);

Restrictions on UNION, INTERSECT, and MINUS

Queries that use UNION, INTERSECT, or MINUS in their where clause must have the same

number and type of columns in their select list Note that the equivalent IN construction does

not have that limitation

The use of combination operators in place of IN, AND, and OR is a matter of personal style Most SQL users regard IN, AND, and OR as being clearer and easier to understand than

combination operators

Trang 9

14 Some Complex

Possibilities

Trang 10

T his chapter continues the study of the more complex Oracle functions and features.Of particular interest here is the creation of simple and group queries that can be

turned into views, the use of totals in calculations, and the creation of reports showing tree structure Like the techniques covered in Chapter 13, these techniques are not essential for most reporting needs If they look overly difficult, don’t be frightened off If you are new to Oracle and the use of its query facilities, it is enough to know

that these capabilities exist and you can turn to them if needed

Complex Groupings

Views can build upon each other In Chapter 12, you saw the concept of creating a view of a

grouping of rows from a table As shown in Chapter 12, you can easily join views to other views

and tables to produce additional views to simplify the tasks of querying and reporting

As your groupings grow more complex, you will find that views are invaluable to your coding efforts; they simplify the representation of data at different grouping levels within your application

They also make it easier to use the more advanced analytic functions available

Consider the CATEGORY_COUNT view, first encountered in Chapter 12:

create or replace view CATEGORY_COUNT as

select CategoryName, COUNT(*) as Counter

from BOOKSHELF

group by CategoryName;

select * from CATEGORY_COUNT;

CATEGORYNAME COUNTER

-ADULTFIC 6

ADULTNF 10

ADULTREF 6

CHILDRENFIC 5

CHILDRENNF 1

CHILDRENPIC 3

Let’s order the results by their Counter column values, with the highest first: select * from CATEGORY_COUNT order by Counter desc; CATEGORYNAME COUNTER

-ADULTNF 10

ADULTFIC 6

ADULTREF 6

CHILDRENFIC 5

CHILDRENPIC 3

CHILDRENNF 1

Trang 11

The output shows the ranking of the categories; the ADULTNF category ranks first in terms ofthe number of books Without displaying this list, you could determine where a different Counter

value would be in the rankings To do this, we’ll use the RANK function As shown in the following

listing, the RANK function takes a value as its input and has additional clauses—the within group

and order by clauses—that tell Oracle how to do the ranking Where would a Counter value of

3 rank?

select RANK(3) within group

(order by Counter desc)

from CATEGORY_COUNT;

RANK(3)WITHINGROUP(ORDERBYCOUNTERDESC)

-5

A Counter value of 3 would be the fifth-highest Counter value How about a Counter value of 8?

select RANK(8) within group

(order by Counter desc)

from CATEGORY_COUNT;

RANK(8)WITHINGROUP(ORDERBYCOUNTERDESC)

-2

Adding those five books to the category would move it up to second place From a percentile

perspective, what would the ranking for that category be?

select PERCENT_RANK(8) within group

(order by Counter desc)

from CATEGORY_COUNT;

PERCENT_RANK(8)WITHINGROUP(ORDERBYCOUNTERDESC)

-.166666667

As expected, it would be in the top one-sixth of the categories

With this technique of using both summary views and analytic functions, you can createviews and reports that include weighted average, effective yield, percentage of total, percentage

of subtotal, and many similar calculations There is no effective limit to how many views can be

built on top of each other, although even the most complex calculations seldom require more

than three or four levels of views built upon views Note that you can also create inline views in

the from clause, as shown in Chapter 12.

Using Temporary Tables

You can create a table that exists solely for your session or whose data persists for the duration of

your transaction You can use temporary tables to support specialized rollups or specific

application-processing requirements

Trang 12

To create a temporary table, use the create global temporary table command When you create a temporary table, you can specify whether it should last for the duration of your session (via the on

commit preserve rows clause) or whether its rows should be deleted when the transaction completes

(via the on commit delete rows clause).

Unlike a permanent table, a temporary table does not automatically allocate space when it iscreated Space will be dynamically allocated for the table as rows are inserted:

create global temporary table YEAR_ROLLUP (

Year NUMBER(4), Month VARCHAR2(9), Counter NUMBER)

on commit preserve rows;

You can see the duration of your data in YEAR_ROLLUP by querying the Duration column

of USER_TABLES for this table In this case, the value of Duration is SYS$SESSION If on commit

delete rows had been specified instead, the Duration value would be SYS$TRANSACTION.

Now that the YEAR_ROLLUP table exists, you can populate it, such as via an insert as select

command with a complex query You can then query the YEAR_ROLLUP table as part of a join

with other tables You may find this method simpler to implement than the methods shown earlier

Using ROLLUP, GROUPING, and CUBE

How can you perform grouping operations, such as totals, within a single SQL statement rather than

via SQL*Plus commands? You can use the ROLLUP and CUBE functions to enhance the grouping

actions performed within your queries Let’s see how this enables us to manage the data related to

book returns The book loaner program has become more popular, so the loan time is now limited

to 14 days, with a $0.20 fee per extra day The following report shows the late charges by person:

set headsep !

column Name format a20

column Title format a20 word_wrapped

column DaysOut format 999.99 heading 'Days!Out'

column DaysLate format 999.99 heading 'Days!Late'

break on Name skip 1 on report

compute sum of LateFee on Name

set linesize 80

set pagesize 60

set newpage 0

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 13

We can eliminate the DaysOut display and focus on the late fees, showing the fees due on each

of the return dates:

clear compute

clear break

select ReturnedDate, Name,

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

where ReturnedDate-CheckoutDate > 14

group by ReturnedDate, Name

order by ReturnedDate, Name;

Trang 14

RETURNEDD NAME LATEFEE

-

-20-JAN-02 EMILY TALBOT .8

22-JAN-02 JED HOPKINS 1.4

02-FEB-02 GERHARDT KENTGEN 3.4

12-FEB-02 PAT LAVAY 3.4

01-MAR-02 FRED FULLER 2.8

01-MAR-02 ROLAND BRANDT 13.6

03-MAR-02 DORAH TALBOT .4

05-MAR-02 GERHARDT KENTGEN 1.2

12-MAR-02 ROLAND BRANDT 9

20-MAR-02 FRED FULLER 1

Then we can modify it further to group the late fees by month:

select TO_CHAR(ReturnedDate,'MONTH'), Name,

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

where ReturnedDate-CheckoutDate > 14

group by TO_CHAR(ReturnedDate,'MONTH'), Name;

TO_CHAR(R NAME LATEFEE

-

-FEBRUARY PAT LAVAY 3.4

FEBRUARY GERHARDT KENTGEN 3.4

JANUARY JED HOPKINS 1.4

JANUARY EMILY TALBOT .8

MARCH FRED FULLER 3.8

MARCH DORAH TALBOT .4

MARCH ROLAND BRANDT 22.6

MARCH GERHARDT KENTGEN 1.2

Instead of simply grouping by Month and Name, you can use the ROLLUP function to generate subtotals and totals In the following example, the group by clause is modified to include a ROLLUP

function call Notice the additional rows generated at the end of the result set and after each month:

select TO_CHAR(ReturnedDate,'MONTH'), Name,

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

where ReturnedDate-CheckoutDate > 14

group by ROLLUP(TO_CHAR(ReturnedDate,'MONTH'), Name);

TO_CHAR(R NAME LATEFEE

-

-FEBRUARY PAT LAVAY 3.4

FEBRUARY GERHARDT KENTGEN 3.4

FEBRUARY 6.8

JANUARY JED HOPKINS 1.4

JANUARY EMILY TALBOT .8

JANUARY 2.2

Trang 15

MARCH FRED FULLER 3.8

MARCH DORAH TALBOT .4

MARCH ROLAND BRANDT 22.6

MARCH GERHARDT KENTGEN 1.2

MARCH 28

37

For each month, Oracle has calculated the total late fee, and shows it with a NULL name

value The output shows two separate charges of $3.40 in February, and a monthly total of $6.80

For the quarter, the total of the late charges is $37.00 You could have calculated these via SQL*Plus

commands (see Chapter 6), but this method allows you to generate these sums via a single SQL

command regardless of the tool used to query the database

Let’s refine the appearance of the report You can use the GROUPING function to determine whether the row is a total or subtotal (generated by ROLLUP) or corresponds to a NULL value in

the database In the select clause, the Name column will be selected as follows:

select DECODE(GROUPING(Name),1, 'All names',Name),

The GROUPING function will return a value of 1 if the column’s value is generated by a ROLLUP action This query uses DECODE (discussed at length in Chapter 16) to evaluate the

result of the GROUPING function If the GROUPING output is 1, the value was generated by the

ROLLUP function, and Oracle will print the phrase ‘All names’; otherwise, it will print the value

of the Name column We will apply similar logic to the Date column The full query is shown in

the following listing, along with its output:

select DECODE(GROUPING(TO_CHAR(ReturnedDate,'MONTH')),1,

'All months',TO_CHAR(ReturnedDate,'MONTH')), DECODE(GROUPING(Name),1, 'All names',Name), SUM((ReturnedDate-CheckoutDate -14)*0.20) LateFee from BOOKSHELF_CHECKOUT

where ReturnedDate-CheckoutDate > 14

group by ROLLUP(TO_CHAR(ReturnedDate, 'MONTH'), Name);

DECODE(GRO DECODE(GROUPING(NAME),1,' LATEFEE

-

-FEBRUARY PAT LAVAY 3.4

FEBRUARY GERHARDT KENTGEN 3.4

FEBRUARY All names 6.8

JANUARY JED HOPKINS 1.4

JANUARY EMILY TALBOT 8

JANUARY All names 2.2

MARCH FRED FULLER 3.8

MARCH DORAH TALBOT 4

MARCH ROLAND BRANDT 22.6

MARCH GERHARDT KENTGEN 1.2

MARCH All names 28

All months All names 37

Trang 16

You can use the CUBE function to generate subtotals for all combinations of the values in the group by clause The following query uses the CUBE function to generate this information:

select DECODE(GROUPING(TO_CHAR(ReturnedDate,'MONTH')),1,

'All months',TO_CHAR(ReturnedDate,'MONTH')), DECODE(GROUPING(Name),1, 'All names',Name), SUM((ReturnedDate-CheckoutDate -14)*0.20) LateFee from BOOKSHELF_CHECKOUT

where ReturnedDate-CheckoutDate > 14

group by CUBE(TO_CHAR(ReturnedDate,'MONTH'), Name);

DECODE(GRO DECODE(GROUPING(NAME),1,' LATEFEE

-

-All months -All names 37

All months PAT LAVAY 3.4

All months FRED FULLER 3.8

All months JED HOPKINS 1.4

All months DORAH TALBOT 4

All months EMILY TALBOT 8

All months ROLAND BRANDT 22.6

All months GERHARDT KENTGEN 4.6

FEBRUARY All names 6.8

FEBRUARY PAT LAVAY 3.4

FEBRUARY GERHARDT KENTGEN 3.4

JANUARY All names 2.2

JANUARY JED HOPKINS 1.4

JANUARY EMILY TALBOT 8

MARCH All names 28

MARCH FRED FULLER 3.8

MARCH DORAH TALBOT 4

MARCH ROLAND BRANDT 22.6

MARCH GERHARDT KENTGEN 1.2

The CUBE function provided the summaries generated by the ROLLUP option, plus it shows

the sums by Name for the ‘All months’ category Being able to perform these summaries in standard

SQL greatly enhances your ability to pick the best reporting tool for your users

Family Trees and connect by

One of Oracle’s more interesting but little used or understood facilities is its connect by clause.

Put simply, this method is used to report, in order, the branches of afamily tree Such trees are

encountered often—the genealogy of human families, livestock, horses; corporate management,

company divisions, manufacturing; literature, ideas, evolution, scientific research, theory, and

even views built upon views

The connect by clause provides a means to report on all of the family members in any of

these many trees It lets you exclude branches or individual members of a family tree, and allows

you to travel through the tree either up or down, reporting on the family members encountered

during the trip

Trang 17

The earliest ancestor in the tree is technically called theroot node In everyday English, thiswould be called thetrunk Extending from the trunk are branches, which have other branches,

which have still other branches The forks where one or more branches split away from a larger

branch are callednodes, and the very end of a branch is called a leaf, or a leaf node Figure 14-1

(above) shows a picture of such a tree

The following is a table of cows and bulls born between January 1900 and October 1908 Aseach offspring is born, it is entered as a row in the table, along with its sex, parents (the cow and

bull), and birth date If you compare the cows and offspring in this table with Figure 14-1, you’ll

find they correspond EVE has no recorded cow or bull parent because she was born on a different

farm, and ADAM and BANDIT are bulls brought in for breeding, again with no parents in the table

column Cow format a6

column Bull format a6

column Offspring format a10

column Sex format a3

select * from BREEDING

order by Birthdate;

FIGURE 14-1. Eve’s descendants

Trang 18

OFFSPRING SEX COW BULL BIRTHDATE

- - - -

-BETSY F EVE ADAM 02-JAN-00

POCO M EVE ADAM 15-JUL-00

GRETA F EVE BANDIT 12-MAR-01

MANDY F EVE POCO 22-AUG-02

CINDY F EVE POCO 09-FEB-03

NOVI F BETSY ADAM 30-MAR-03

GINNY F BETSY BANDIT 04-DEC-03

DUKE M MANDY BANDIT 24-JUL-04

TEDDI F BETSY BANDIT 12-AUG-05

SUZY F GINNY DUKE 03-APR-06

PAULA F MANDY POCO 21-DEC-06

RUTH F GINNY DUKE 25-DEC-06

DELLA F SUZY BANDIT 11-OCT-08

to 5 for DELLA, that is really thegeneration If EVE is the first generation of cattle, then DELLA is

the fifth generation Whenever the connect by clause is used, the Level column can be used in the

select statement to discover the generation of each row Level is apseudo-column like SysDate

and User It’s not really a part of the table, but it is available under specific circumstances The next

listing shows an example of using Level

The results of this query are apparent in the following table, but why did the select statement

produce this? How does it work?

column Offspring format a30

select Cow, Bull, LPAD(' ',6*(Level-1))||Offspring AS Offspring,

Sex, Birthdate from BREEDING

start with Offspring = 'EVE'

connect by Cow = PRIOR Offspring;

COW BULL OFFSPRING SEX BIRTHDATE

- - -

-EVE F EVE ADAM BETSY F 02-JAN-00

BETSY ADAM NOVI F 30-MAR-03

BETSY BANDIT GINNY F 04-DEC-03

GINNY DUKE SUZY F 03-APR-06

SUZY BANDIT DELLA F 11-OCT-08

GINNY DUKE RUTH F 25-DEC-06

BETSY BANDIT TEDDI F 12-AUG-05

EVE ADAM POCO M 15-JUL-00

EVE BANDIT GRETA F 12-MAR-01

EVE POCO MANDY F 22-AUG-02

MANDY BANDIT DUKE M 24-JUL-04

MANDY POCO PAULA F 21-DEC-06

EVE POCO CINDY F 09-FEB-03

Trang 19

Note that this is really Figure 14-1 turned clockwise onto its side EVE isn’t centered, but she

is the root node (trunk) of this tree Her children are BETSY, POCO, GRETA, MANDY, and CINDY

BETSY’s children are NOVI, GINNY, and TEDDI GINNY’s children are SUZY and RUTH And

SUZY’s child is DELLA MANDY also has two children, DUKE and PAULA

This tree started with EVE as the first “offspring.” If the SQL statement had said start with MANDY, only MANDY, DUKE, and PAULA would have been selected start with defines the beginning of

that portion of the tree that will be displayed, and it includes only branches stretching out from

the individual that start with specifies start with acts just as its name implies.

The LPAD in the select statement is probably somewhat confusing Recall from Chapter 7 the format for LPAD:

LPAD(string,length [,'set'])

That is, take the specifiedstring and left-pad it for the specified length with the specified set of

characters If no set is specified, left-pad the string with blanks

Compare this syntax to the LPAD in the select statement shown earlier:

LPAD(' ',6*(Level-1))

In this case, thestring is a single character (a space, indicated by the literal space enclosed in single

quotation marks) Also, 6*(Level–1) is thelength, and because the set is not specified, spaces will

be used In other words, this tells SQL to take this string of one space and left-pad it to the number

of spaces determined by 6*(Level–1), a calculation made by first subtracting 1 from the Level and

then multiplying this result by 6 For EVE, the Level is 1, so 6*(1–1), or 0 spaces, is used For BETSY,

the Level (her generation) is 2, so an LPAD of 6 is used Thus, for each generation after the first,

six additional spaces will be concatenated to the left of the Offspring column The effect is obvious

in the result just shown The name of each Offspring is indented by left-padding with the number

of spaces corresponding to its Level or generation

Why is this done, instead of simply applying the LPAD directly to Offspring? For two reasons.

First, a direct LPAD on Offspring would cause the names of the offspring to be right-justified The

names at each level would end up having their last letters lined up vertically Second, if Level–1

is equal to 0, as it is for EVE, the resulting LPAD of EVE will be 0 characters wide, causing EVE

to vanish:

select Cow, Bull, LPAD(Offspring,6*(Level-1),' ') AS Offspring,

Sex, Birthdate from BREEDING start with Offspring = 'EVE'

connect by Cow = PRIOR Offspring;

COW BULL OFFSPRING SEX BIRTHDATE

- - -

-F EVE ADAM BETSY F 02-JAN-00

BETSY ADAM NOVI F 30-MAR-03

BETSY BANDIT GINNY F 04-DEC-03

Trang 20

GINNY DUKE SUZY F 03-APR-06

SUZY BANDIT DELLA F 11-OCT-08

GINNY DUKE RUTH F 25-DEC-06

BETSY BANDIT TEDDI F 12-AUG-05

EVE ADAM POCO M 15-JUL-00

EVE BANDIT GRETA F 12-MAR-01

EVE POCO MANDY F 22-AUG-02

MANDY BANDIT DUKE M 24-JUL-04

MANDY POCO PAULA F 21-DEC-06

EVE POCO CINDY F 09-FEB-03

Therefore, to get the proper spacing for each level, to ensure that EVE appears, and to make

the names line up vertically on the left, the LPAD should be used with the concatenation function,

and not directly on the Offspring column

Now, how does connect by work? Look again at Figure 14-1 Starting with NOVI and traveling

downward, which cows are the offspring prior to NOVI? The first is BETSY, and the offspring just

prior to BETSY is EVE Even though it is not instantly readable, the clause

connect by Cow = PRIOR Offspring

tells SQL to find the next row in which the value in the Cow column is equal to the value in the

Offspring column in the prior row Look at the table and you’ll see that this is true

Excluding Individuals and Branches

There are two methods of excluding cows from a report One uses the normal where clause

technique, and the other uses the connect by clause itself The difference is that the exclusion

using the connect by clause will exclude not just the cow mentioned, but all of its children as

well If you use connect by to exclude BETSY, then NOVI, GINNY, TEDDI, SUZY, RUTH, and

DELLA all vanish The connect by clause really tracks the tree structure If BETSY had never been

born, none of her offspring would have been either In this example, the and clause modifies the

connect by clause:

select Cow, Bull, LPAD(' ',6*(Level-1))||Offspring AS Offspring,

Sex, Birthdate from BREEDING

start with Offspring = 'EVE'

connect by Cow = PRIOR Offspring

and Offspring != 'BETSY';

COW BULL OFFSPRING SEX BIRTHDATE

- - -

-EVE F EVE ADAM POCO M 15-JUL-00

EVE BANDIT GRETA F 12-MAR-01

EVE POCO MANDY F 22-AUG-02

MANDY BANDIT DUKE M 24-JUL-04

MANDY POCO PAULA F 21-DEC-06

EVE POCO CINDY F 09-FEB-03

Trang 21

The where clause removes only the cow or cows it mentions If BETSY dies, she is removed

from the chart, but her offspring are not In fact, notice that BETSY is still there under the Cow

column as the mother of her children, NOVI, GINNY, and TEDDI:

select Cow, Bull, LPAD(' ',6*(Level-1))||Offspring AS Offspring,

Sex, Birthdate from BREEDING

where Offspring != 'BETSY'

start with Offspring = 'EVE'

connect by Cow = PRIOR Offspring;

COW BULL OFFSPRING SEX BIRTHDATE

- - -

-EVE F BETSY ADAM NOVI F 30-MAR-03

BETSY BANDIT GINNY F 04-DEC-03

GINNY DUKE SUZY F 03-APR-06

SUZY BANDIT DELLA F 11-OCT-08

GINNY DUKE RUTH F 25-DEC-06

BETSY BANDIT TEDDI F 12-AUG-05

EVE ADAM POCO M 15-JUL-00

EVE BANDIT GRETA F 12-MAR-01

EVE POCO MANDY F 22-AUG-02

MANDY BANDIT DUKE M 24-JUL-04

MANDY POCO PAULA F 21-DEC-06

EVE POCO CINDY F 09-FEB-03

The order in which the family tree is displayed when using connect by is basically level by

level, left to right, as shown in Figure 14-1, starting with the lowest level, Level 1 For example,

you may want to alter this order to collect the cows and their offspring by birth date:

select Cow, Bull, LPAD(' ',6*(Level-1))||Offspring AS Offspring,

Sex, Birthdate from BREEDING start with Offspring = 'EVE'

connect by Cow = PRIOR Offspring

order by Cow, Birthdate;

COW BULL OFFSPRING SEX BIRTHDATE

- - -

-BETSY ADAM NOVI F 30-MAR-03

BETSY BANDIT GINNY F 04-DEC-03

BETSY BANDIT TEDDI F 12-AUG-05

EVE ADAM BETSY F 02-JAN-00

EVE ADAM POCO M 15-JUL-00

EVE BANDIT GRETA F 12-MAR-01

EVE POCO MANDY F 22-AUG-02

EVE POCO CINDY F 09-FEB-03

GINNY DUKE SUZY F 03-APR-06

GINNY DUKE RUTH F 25-DEC-06

MANDY BANDIT DUKE M 24-JUL-04

Trang 22

MANDY POCO PAULA F 21-DEC-06

SUZY BANDIT DELLA F 11-OCT-08

start with Offspring = 'EVE'

connect by Cow = PRIOR Offspring

order by Birthdate;

COW BULL OFFSPRING SEX BIRTHDATE

- - -

-EVE ADAM BETSY F 02-JAN-00

EVE ADAM POCO M 15-JUL-00

EVE BANDIT GRETA F 12-MAR-01

EVE POCO MANDY F 22-AUG-02

EVE POCO CINDY F 09-FEB-03

BETSY ADAM NOVI F 30-MAR-03

BETSY BANDIT GINNY F 04-DEC-03

MANDY BANDIT DUKE M 24-JUL-04

BETSY BANDIT TEDDI F 12-AUG-05

GINNY DUKE SUZY F 03-APR-06

MANDY POCO PAULA F 21-DEC-06

GINNY DUKE RUTH F 25-DEC-06

SUZY BANDIT DELLA F 11-OCT-08

EVE F

Now, the order of the rows no longer shows generations, as in a tree, but the indenting stillpreserves this information You can’t tell what offspring belong to which parents without looking

at the Cow and Bull columns, though Not knowing Eve’s birth date clearly disrupts the display of

the family tree

Traveling Toward the Roots

Thus far, the direction of travel in reporting on the family tree has been from parents toward

children Is it possible to start with a child, and move backward to parent, grandparent,

great-grandparent, and so on? To do so, the word prior is simply moved to the other side of the equal

sign In the following examples, the Offspring is set equal to the prior Cow value; in the earlier

examples, the Cow was set equal to the prior Offspring value The following traces DELLA’s

ancestry:

select Cow, Bull, LPAD(' ',6*(Level-1))||Offspring AS Offspring,

Sex, Birthdate from BREEDING

start with Offspring = 'DELLA'

connect by Offspring = PRIOR Cow;

Trang 23

COW BULL OFFSPRING SEX BIRTHDATE

- - -

-SUZY BANDIT DELLA F 11-OCT-08

GINNY DUKE SUZY F 03-APR-06

BETSY BANDIT GINNY F 04-DEC-03

EVE ADAM BETSY F 02-JAN-00

EVE F

This shows DELLA’s own roots, but it’s a bit confusing if compared to the previous displays

It looks as if DELLA is the ancestor, and EVE the great-great-granddaughter Adding an order by

for Birthdate helps, but EVE is still further to the right:

select Cow, Bull, LPAD(' ',6*(Level-1))||Offspring AS Offspring,

Sex, Birthdate from BREEDING

start with Offspring = 'DELLA'

connect by Offspring = PRIOR Cow

order by Birthdate;

COW BULL OFFSPRING SEX BIRTHDATE

- - -

-EVE ADAM BETSY F 02-JAN-00

BETSY BANDIT GINNY F 04-DEC-03

GINNY DUKE SUZY F 03-APR-06

SUZY BANDIT DELLA F 11-OCT-08

EVE F

The solution is simply to change the calculation in the LPAD:

select Cow, Bull, LPAD(' ',6*(5-Level))||Offspring Offspring,

Sex, Birthdate from BREEDING

start with Offspring = 'DELLA'

connect by Offspring = PRIOR Cow

order by Birthdate;

COW BULL OFFSPRING SEX BIRTHDATE

- - -

-EVE ADAM BETSY F 02-JAN-00

BETSY BANDIT GINNY F 04-DEC-03

GINNY DUKE SUZY F 03-APR-06

SUZY BANDIT DELLA F 11-OCT-08

EVE F

Finally, look how different this report is when the connect by tracks the parentage of the bull.

Here are ADAM’s offspring:

select Cow, Bull, LPAD(' ',6*(Level-1))||Offspring AS Offspring,

Sex, Birthdate from BREEDING

Trang 24

start with Offspring = 'ADAM'

connect by PRIOR Offspring = Bull;

COW BULL OFFSPRING SEX BIRTHDATE

- - -

-ADAM M EVE ADAM BETSY F 02-JAN-00

EVE ADAM POCO M 15-JUL-00

EVE POCO MANDY F 22-AUG-02

EVE POCO CINDY F 09-FEB-03

MANDY POCO PAULA F 21-DEC-06

BETSY ADAM NOVI F 30-MAR-03

ADAM and BANDIT were the original bulls at the initiation of the herd To create a singletree that reports both ADAM’s and BANDIT’s offspring, you would have to invent a “father” for

the two of them, which would be the root of the tree One of the advantages that these alternative

trees have over the type of tree shown earlier is that many inheritance groups—from families to

projects to divisions within companies—can be accurately portrayed in more than one way:

select Cow, Bull, LPAD(' ',6*(Level-1))||Offspring AS Offspring,

Sex, Birthdate from BREEDING

start with Offspring = 'BANDIT'

connect by PRIOR Offspring = Bull;

COW BULL OFFSPRING SEX BIRTHDATE

- - -

-BANDIT M EVE BANDIT GRETA F 12-MAR-01

BETSY BANDIT GINNY F 04-DEC-03

MANDY BANDIT DUKE M 24-JUL-04

GINNY DUKE SUZY F 03-APR-06

GINNY DUKE RUTH F 25-DEC-06

BETSY BANDIT TEDDI F 12-AUG-05

SUZY BANDIT DELLA F 11-OCT-08

The Basic Rules

Using connect by and start with to create tree like reports is not difficult, but certain basic rules

Trang 25

5 connect by

6 order by

prior forces reporting to be from the root out toward the leaves (if the prior column is the parent) or from a leaf toward the root (if the prior column is the child).

A where clause eliminates individuals from the tree, but not their descendants (or ancestors,

if prior is on the right side of the equal sign).

A qualification in the connect by (particularly a not equal) eliminates both an individual

and all of its descendants (or ancestors, depending on how you trace the tree)

connect by cannot be used with a table join in the where clause.

This particular set of commands is one that few people are likely to remember correctly

However, with a basic understanding of trees and inheritance, you should be able to construct

a proper select statement to report on a tree just by referring to this chapter for correct syntax.

Trang 27

15

Changing Data:

insert, update, merge, and delete

Trang 28

U ntil now, virtually everything you’ve learned about Oracle, SQL, and SQL*Plushas related to selecting data from tables in the database This chapter shows how

tochange the data in a table—how to insert new rows, update the values ofcolumns in rows, and delete rows entirely Although these topics have not beencovered explicitly, nearly everything you already know about SQL, including

datatypes, calculations, string formatting, where clauses, and the like, can be used here, so there

really isn’t much new to learn Oracle gives you a transparent, distributed database capability

that inserts, updates, and deletes data in remote databases as well (see Chapter 23) As you’ll see

in this chapter, Oracle allows you to combine these commands via multitable inserts and the merge

command (to perform inserts and updates in a single command)

insert

The SQL command insert lets you place a row of information directly into a table (or indirectly,

through a view) The COMFORT table tracks temperatures at noon and midnight as well as daily

precipitation, city by city, for four sample dates throughout the year:

describe COMFORT

Name Null? Type

- -

-CITY NOT NULL VARCHAR2(13)

SAMPLEDATE NOT NULL DATE

NOON NUMBER(3,1)

MIDNIGHT NUMBER(3,1)

PRECIPITATION NUMBER

To add a new row to this table, use this:

insert into COMFORT

values ('WALPOLE', '21-MAR-03',

56.7, 43.8, 0);

1 row created.

The word values must precede the list of data to be inserted A character string must be in

single quotation marks Numbers can stand by themselves Each field is separated by commas,

and the fields must be in the same order as the columns are when the table is described

A date must be in single quotation marks and in the default Oracle date format To insert a

date not in your default format, use the TO_DATE function, with a formatting mask, as shown

in the following example:

insert into COMFORT

values ('WALPOLE', TO_DATE('06/22/2003','MM/DD/YYYY'),

56.7, 43.8, 0);

1 row created.

Trang 30

You cannot use the insert into…select from syntax with LONG datatypes unless you are using the TO_LOB function to insert the

LONG data into a LOB column

Of course, you don’t need to simply insert the value in a selected column You can modify the

column using any of the appropriate string, date, or number functions within the select statement.

The results of those functions are what will be inserted You can attempt to insert a value in a

column that exceeds its width (for character datatypes) or its magnitude (for number datatypes)

You have to fit the value within the constraints you defined on your columns These attempts

will produce a “value too large for column” or “mismatched datatype” error message If you now

query the COMFORT table for the city of Walpole, the results will be the records you inserted:

select * from COMFORT

where City = 'WALPOLE';

CITY SAMPLEDAT NOON MIDNIGHT PRECIPITATION

Two records are shown for ‘22-JUN-03’ because one of them has a time component Use the

TO_CHAR function to see the time:

select City, SampleDate,

TO_CHAR(SampleDate,'HH24:MI:SS') AS TimeofDay, Noon from COMFORT

where City = 'WALPOLE';

CITY SAMPLEDAT TIMEOFDA NOON

Using the APPEND Hint to Improve insert Performance

As you will see in Chapter 43, Oracle uses an optimizer to determine the most efficient way to

perform each SQL command For insert statements, Oracle tries to insert each new record into

an existing block of data already allocated to the table This execution plan optimizes the use of

space required to store the data However, it may not provide adequate performance for an insert

with a select command that inserts multiple rows You can amend the execution plan by using the

Trang 31

APPEND hint to improve the performance of large inserts The APPEND hint will tell the database

to find the last block into which the table’s data has ever been inserted The new records will be

inserted starting in the next block following the last previously used block Furthermore, the inserted

data is written directly to the datafiles, bypassing the data block buffer cache As a result, there is

much less space management work for the database to do during the insert Therefore, the insert

may complete faster when the APPEND hint is used

You specify the APPEND hint within the insert command A hint looks like a comment—it

starts with /* and ends with */ The only difference is that the starting set of characters includes

a plus sign (+) before the name of the hint The following example shows an insert command

whose data is appended to the table:

insert /*+ APPEND */ into BOOKSHELF (Title)

select Title from BOOK_ORDER

where Title not in (select Title from BOOKSHELF);

The records from the BOOK_ORDER table will be inserted into the BOOKSHELF table Instead

of attempting to reuse space within the BOOKSHELF table, the new records will be placed at the

end of the table’s physical storage space

Because the new records will not attempt to reuse available space that the table has alreadyused, the space requirements for the BOOKSHELF table may increase In general, you should use

the APPEND hint only when inserting large volumes of data into tables with little reusable space

The point at which appended records will be inserted is called the table’shigh-water mark—and

the only way to reset the high-water mark is to truncate the table Because truncate will delete

all records and cannot be rolled back, you should make sure you have a backup of the table’s data

prior to performing the truncate See truncate in the Alphabetical Reference for further details.

rollback, commit, and autocommit

When you insert, update, or delete data from the database, you can reverse, orroll back, the work

you’ve done This can be very important when an error is discovered The process of committing

or rolling back work is controlled by two SQL*Plus commands: commit and rollback Additionally,

SQL*Plus has the facility to automatically commit your work without your explicitly telling it to

do so This is controlled by the autocommit feature of set Like other set features, you can show it,

like this:

show autocommit

autocommit OFF

OFF is the default, and in almost all cases it’s the preferred mode You can also specify

a number for the autocommit value; this value will determine the number of commands after

which Oracle will issue a commit Having autocommit off means insert, update, and delete

operations are not made final until you commit them:

commit;

commit complete

Trang 33

rollback to savepoint B;

If you now query COMFORT, you’ll see that the last insert has been rolled back, but the others

are still there:

select * from COMFORT

where City = 'WALPOLE';

CITY SAMPLEDAT NOON MIDNIGHT PRECIPITATION

The last two records are still not committed; you need to execute a commit command or another

command to force a commit to occur You can still roll back the second insert (to savepoint A) or roll

back all the inserts (via a rollback command).

Implicit commit

The actions that will force a commit to occur, even without your instructing it to, are quit, exit

(the equivalent of quit), and any Data Definition Language (DDL) command Using any of these

commands forces a commit.

Auto rollback

If you’ve completed a series of insert, update, or delete operations but have not yet explicitly or

implicitly committed them, and you experience serious difficulties, such as a computer failure,

Oracle will automatically roll back any uncommitted work If the machine or database goes

down, Oracle does the rollback as cleanup work the next time the database is brought back up

Multitable Inserts

You can perform multiple inserts in a single command You can perform all the inserts unconditionally

or you can specify conditions—using a when clause to tell Oracle how to manage the multiple

inserts If you specify all, then all the when clauses will be evaluated; specifying first tells Oracle

to skip subsequent when clauses after it finds one that is true for the row being evaluated You can

also use an else clause to tell Oracle what to do if none of the when clauses evaluates to true.

To illustrate this functionality, let’s create a new table with a slightly different structure thanCOMFORT:

drop table COMFORT_TEST;

create table COMFORT_TEST (

City VARCHAR2(13) NOT NULL,

SampleDate DATE NOT NULL,

Trang 34

Measure VARCHAR2(10),

Value NUMBER(3,1)

);

COMFORT_TEST will have multiple records for each record in COMFORT—its Measure column

will have values such as ‘Midnight’, ‘Noon’, and ‘Precip’, allowing us to store a greater number

of measures for each city on each sample date

Now populate COMFORT_TEST with data from COMFORT, unconditionally:

from COMFORT

where City = 'KEENE';

12 rows created.

This query tells Oracle to insert multiple rows for each row returned from the COMFORT table

The query of COMFORT returns four rows The first into clause inserts the Noon value, along with

a text string of ‘NOON’ in the Measure column The second into clause inserts the Midnight value,

and the third inserts the Precipitation value, as shown in the query of COMFORT_TEST following

the insert:

select * from COMFORT_TEST;

CITY SAMPLEDAT MEASURE VALUE

- -

-KEENE 21-MAR-03 NOON 39.9

KEENE 22-JUN-03 NOON 85.1

KEENE 23-SEP-03 NOON 99.8

KEENE 22-DEC-03 NOON -7.2

KEENE 21-MAR-03 MIDNIGHT -1.2

KEENE 22-JUN-03 MIDNIGHT 66.7

KEENE 23-SEP-03 MIDNIGHT 82.6

KEENE 22-DEC-03 MIDNIGHT -1.2

KEENE 21-MAR-03 PRECIP 4.4

KEENE 22-JUN-03 PRECIP 1.3

KEENE 23-SEP-03 PRECIP

KEENE 22-DEC-03 PRECIP 3.9

12 rows selected.

What if you had used the first keyword instead of the all keyword? Unless you use when clauses, you can’t use the first keyword The following example shows the use of the when clause to restrict

Trang 35

which inserts are performed within the multi-insert command For this example, the all keyword

when Midnight > 70 then into COMFORT_TEST (City, SampleDate, Measure, Value) values (City, SampleDate, 'MIDNIGHT', Midnight)

when Precipitation is not null then into COMFORT_TEST (City, SampleDate, Measure, Value) values (City, SampleDate, 'PRECIP', Precipitation) select City, SampleDate, Noon, Midnight, Precipitation

from COMFORT

where City = 'KEENE';

6 rows created.

What six rows were inserted? The two Noon values met this condition:

when Noon > 80 then

The one Midnight value met this condition:

when Midnight > 70 then

And the three Precipitation values met this condition:

when Precipitation is not null then

You can see the results in COMFORT_TEST:

select * from COMFORT_TEST;

CITY SAMPLEDAT MEASURE VALUE

- -

-KEENE 22-JUN-03 NOON 85.1

KEENE 23-SEP-03 NOON 99.8

KEENE 23-SEP-03 MIDNIGHT 82.6

KEENE 21-MAR-03 PRECIP 4.4

KEENE 22-JUN-03 PRECIP 1.3

KEENE 22-DEC-03 PRECIP 3.9

What if you had used first instead?

delete from COMFORT_TEST;

commit;

Trang 36

insert FIRST

when Noon > 80 then into COMFORT_TEST (City, SampleDate, Measure, Value) values (City, SampleDate, 'NOON', Noon)

when Midnight > 70 then into COMFORT_TEST (City, SampleDate, Measure, Value) values (City, SampleDate, 'MIDNIGHT', Midnight)

when Precipitation is not null then into COMFORT_TEST (City, SampleDate, Measure, Value) values (City, SampleDate, 'PRECIP', Precipitation) select City, SampleDate, Noon, Midnight, Precipitation

from COMFORT

where City = 'KEENE';

4 rows created.

In this case, four rows are inserted:

select * from COMFORT_TEST;

CITY SAMPLEDAT MEASURE VALUE

- -

-KEENE 21-MAR-03 PRECIP 4.4

KEENE 22-DEC-03 PRECIP 3.9

KEENE 22-JUN-03 NOON 85.1

KEENE 23-SEP-03 NOON 99.8

What happened to the MIDNIGHT value? Only one record passed the MIDNIGHT when clause:

when Midnight > 70 then

This record also passed the NOON when clause:

when Noon > 80 then

Therefore, its Noon value (99.8) was inserted Because the first keyword was used, and the condition

that was evaluated first (Noon) was true, Oracle did not check the rest of the conditions for that row

The same process happened to the PRECIP measures—the other non-NULL Precipitation value was

on the same record as the Noon reading of 85.1

What if none of the conditions had been met? To show that option, let’s create a third table,COMFORT2, with the same structure as COMFORT:

create table COMFORT2 (

City VARCHAR2(13) NOT NULL,

SampleDate DATE NOT NULL,

Noon NUMBER(3,1),

Midnight NUMBER(3,1),

Precipitation NUMBER

);

Trang 37

Now, we’ll execute an insert for all cities (using the first clause) along with an else clause

specifying that any rows that fail the conditions will be placed into the COMFORT2 table For this

example, the when conditions are changed to limit the number of rows that pass the conditions:

delete from COMFORT_TEST;

delete from COMFORT2;

commit;

insert FIRST

when Noon > 80 then into COMFORT_TEST (City, SampleDate, Measure, Value) values (City, SampleDate, 'NOON', Noon)

when Midnight > 100 then into COMFORT_TEST (City, SampleDate, Measure, Value) values (City, SampleDate, 'MIDNIGHT', Midnight)

when Precipitation > 100 then into COMFORT_TEST (City, SampleDate, Measure, Value) values (City, SampleDate, 'PRECIP', Precipitation) else

into COMFORT2 select City, SampleDate, Noon, Midnight, Precipitation

from COMFORT

where City = 'KEENE';

4 rows created.

The feedback tells you how many rows were created, but not which table they were created in

The total reported is for all inserts combined In this case, two records were inserted into COMFORT_

TEST and two were inserted into COMFORT2 because of the else condition:

select * from COMFORT_TEST;

CITY SAMPLEDAT MEASURE VALUE

- -

-KEENE 22-JUN-03 NOON 85.1

KEENE 23-SEP-03 NOON 99.8

select * from COMFORT2;

CITY SAMPLEDAT NOON MIDNIGHT PRECIPITATION

- - -

-KEENE 21-MAR-03 39.9 -1.2 4.4

KEENE 22-DEC-03 -7.2 -1.2 3.9

delete

Removing a row or rows from a table requires the delete command, as seen in the examples in

the last section The where clause is essential to removing only the rows you intend delete without

Trang 38

a where clause will empty the table completely The following command deletes the Walpole

entries from the COMFORT table:

delete from COMFORT where City = 'WALPOLE';

Of course, a where clause in a delete, just as in an update or a select that is part of an insert, can contain as much logic as any select statement, and may include subqueries, unions, intersects,

and so on You can always roll back a bad insert, update, or delete, but you really should experiment

with select before actually making the change to the database, to make sure you are doing the

right thing

Now that you’ve just deleted the rows where City = ‘WALPOLE’, you can test the effect of

that delete with a simple query:

select * from COMFORT

where City = 'WALPOLE';

no rows selected

Now roll back the delete and run the same query:

rollback;

Rollback complete

select * from COMFORT

where City = 'WALPOLE';

CITY SAMPLEDAT NOON MIDNIGHT PRECIPITATION

This illustrates that recovery is possible, so long as a commit hasn’t occurred If the changes have

been committed, you may be able to use flashback queries (see Chapter 27) to retrieve the data

An additional command for deleting records, truncate, does not behave the same as delete.

Whereas delete allows you to commit or roll back the deletion, truncate automatically deletes all

records from the table The action of the truncate command cannot be rolled back or committed;

the truncated records are unrecoverable You cannot perform a flashback query to see data that

has been truncated See the truncate command in the Alphabetical Reference for further details.

Trang 39

update requires setting specific values for each column you want to change, and specifying which

row or rows you want to affect by using a carefully constructed where clause:

update COMFORT set Precipitation = 5, Midnight = 73.1

where City = 'KEENE'

and SampleDate = '22-DEC-03';

1 row updated.

Here is the effect, shown in the 22-DEC-03 record:

select * from COMFORT

where City = 'KEENE';

CITY SAMPLEDAT NOON MIDNIGHT PRECIPITATION

any other legitimate function in setting a value for the update (just as you can for an insert, or in

the where clause of a delete) Here, each temperature in Keene is decreased by one degree:

update COMFORT set Midnight = Midnight - 1, Noon = Noon - 1

where City = 'KEENE';

4 rows updated.

Here is the effect of the update:

select * from COMFORT

where City = 'KEENE';

CITY SAMPLEDAT NOON MIDNIGHT PRECIPITATION

Trang 40

If your update violates the column definitions or constraints, it will

fail In this case, setting Noon or Midnight to values of 100 or greaterwill violate the numeric scale of the columns

As with delete, the where clause is critical Without one, every row in the table will be updated.

With an improperly constructed where clause, the wrong rows will be updated, often in ways

that are hard to discover or fix, especially if your work has been committed Always set feedback

on when doing updates, and look at the feedback to be sure the number of rows updated is what

you expected it to be Query the rows after you update to see if the expected change took place.

update with Embedded select

It is possible to set values in an update by embedding a select statement right in the middle of it.

Note that this select has its own where clause, picking out the temperature for the city of Manchester

from the WEATHER table, and the update has its own where clause to affect just the city of Keene

on a certain day:

update COMFORT set Midnight =

(select Temperature from WEATHER where City = 'MANCHESTER') where City = 'KEENE'

and SampleDate = '22-DEC-03';

1 row updated.

Here is the effect of the update:

select * from COMFORT

where City = 'KEENE';

CITY SAMPLEDAT NOON MIDNIGHT PRECIPITATION

Chapter 13 for details on correlated queries

You also can use an embedded select to update multiple columns at once The columns must

be in parentheses and separated by a comma, as shown here:

update COMFORT set (Noon, Midnight) =

(select Humidity, Temperature

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

TỪ KHÓA LIÊN QUAN