Tải bản đầy đủ (.pdf) (135 trang)

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

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (557.84 KB, 135 trang )

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 Oracle9
i,
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 Oracle
users 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
Chapter 13: When One Query Depends upon Another
253
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 13
Blind Folio 13:253
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:42 PM
Color profile: Generic CMYK printer profile
Composite Default screen
254
Part II: SQL and SQL*Plus
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 13
Blind Folio 13:254
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

order by B.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
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
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:42 PM
Color profile: Generic CMYK printer profile
Composite Default screen
where not exists
(select 'x' from BOOKSHELF_CHECKOUT BC
where BC.Title = B.Title)
order by B.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 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?
select Title
from BOOK_ORDER natural join BOOKSHELF;
TITLE

SHOELESS JOE
GOSPEL
Chapter 13: When One Query Depends upon Another
255
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 13
Blind Folio 13:255
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:43 PM
Color profile: Generic CMYK printer profile

Composite Default screen
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 Oracle9
i.
Inner joins are the default—they
return 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
listing:
select BO.Title
from BOOK_ORDER BO inner join BOOKSHELF B
on BO.Title = B.Title;
TITLE

GOSPEL
SHOELESS JOE
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
order (BOOK_ORDER).
To see all the books, UNION the two tables. To reduce the size of the output, only the
BOOKSHELF entries from the first half of the alphabet are selected. The following select returns
14 rows:
select Title from BOOKSHELF
where Title < 'M%';
And this select returns six rows:
256
Part II: SQL and SQL*Plus
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 13
Blind Folio 13:256
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:44 PM
Color profile: Generic CMYK printer profile
Composite Default screen
select Title from BOOK_ORDER;
If we UNION them together, how many rows are returned?
select Title from BOOKSHELF
where Title < 'M%'
union
select Title from BOOK_ORDER;
TITLE

ANNE OF GREEN GABLES
BOX SOCIALS

CHARLOTTE'S WEB
COMPLETE POEMS OF JOHN KEATS
EITHER/OR
EMMA WHO SAVED MY LIFE
GALILEO'S DAUGHTER
GOOD DOG, CARL
GOSPEL
HARRY POTTER AND THE GOBLET OF FIRE
INNUMERACY
JOHN ADAMS
JOURNALS OF LEWIS AND CLARK
KIERKEGAARD ANTHOLOGY
LETTERS AND PAPERS FROM PRISON
LONGITUDE
ONCE REMOVED
SHOELESS JOE
SOMETHING SO STRONG
19 rows selected.
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
where Title < 'M%'
union all
select Title from BOOK_ORDER
order by Title;
TITLE

ANNE OF GREEN GABLES
BOX SOCIALS
CHARLOTTE'S WEB

COMPLETE POEMS OF JOHN KEATS
EITHER/OR
EMMA WHO SAVED MY LIFE
Chapter 13: When One Query Depends upon Another
257
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 13
Blind Folio 13:257
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:44 PM
Color profile: Generic CMYK printer profile
Composite Default screen
258
Part II: SQL and SQL*Plus
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 13
Blind Folio 13:258
GALILEO'S DAUGHTER
GOOD DOG, CARL
GOSPEL
GOSPEL
HARRY POTTER AND THE GOBLET OF FIRE
INNUMERACY
JOHN ADAMS
JOURNALS OF LEWIS AND CLARK
KIERKEGAARD ANTHOLOGY
LETTERS AND PAPERS FROM PRISON
LONGITUDE
ONCE REMOVED
SHOELESS JOE
SOMETHING SO STRONG
20 rows selected.

The duplicate title is now listed twice.
In the following, the two lists of books are intersected. This list contains only those names
that are in
both
underlying tables (note that the restriction on Title < ‘M%’ has been eliminated
for this example):
select Title from BOOKSHELF
intersect
select Title from BOOK_ORDER
order by Title;
TITLE

GOSPEL
SHOELESS JOE
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
minus
select Title from BOOKSHELF
order by Title;
TITLE

GALILEO'S DAUGHTER
LONGITUDE
ONCE REMOVED
SOMETHING SO STRONG
You could have also used MINUS to show which books had not been checked out:
select Title from BOOKSHELF
minus
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp

Friday, August 13, 2004 1:46:45 PM
Color profile: Generic CMYK printer profile
Composite Default screen
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 of

columns 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
Chapter 13: When One Query Depends upon Another
259
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 13
Blind Folio 13:259
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:45 PM
Color profile: Generic CMYK printer profile
Composite Default screen
(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.
260
Part II: SQL and SQL*Plus
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 13
Blind Folio 13:260
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:45 PM
Color profile: Generic CMYK printer profile
Composite Default screen
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 14
Blind Folio 14:261
CHAPTER
14
Some Complex
Possibilities
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:46 PM

Color profile: Generic CMYK printer profile
Composite Default screen
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
262
Part II: SQL and SQL*Plus
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 14
Blind Folio 14:262
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:47 PM
Color profile: Generic CMYK printer profile
Composite Default screen
Chapter 14: Some Complex Possibilities
263
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 14
Blind Folio 14:263
The output shows the ranking of the categories; the ADULTNF category ranks first in terms of
the 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 create
views 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.
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:47 PM
Color profile: Generic CMYK printer profile
Composite Default screen
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 is
created. 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;
264
Part II: SQL and SQL*Plus
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 14
Blind Folio 14:264
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:48 PM
Color profile: Generic CMYK printer profile
Composite Default screen
Chapter 14: Some Complex Possibilities
265
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 14
Blind Folio 14:265
Days Days
NAME TITLE RETURNEDD Out Late LATEFEE


DORAH TALBOT MY LEDGER 03-MAR-02 16.00 2.00 .4
********************
sum .4
EMILY TALBOT ANNE OF GREEN GABLES 20-JAN-02 18.00 4.00 .8
********************
sum .8
FRED FULLER JOHN ADAMS 01-MAR-02 28.00 14.00 2.8
TRUMAN 20-MAR-02 19.00 5.00 1
********************
sum 3.8
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
********************
sum 4.6
JED HOPKINS INNUMERACY 22-JAN-02 21.00 7.00 1.4
********************
sum 1.4
PAT LAVAY THE MISMEASURE OF 12-FEB-02 31.00 17.00 3.4
MAN
********************
sum 3.4
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.8
********************
sum 22.6
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;
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:48 PM
Color profile: Generic CMYK printer profile
Composite Default screen
266
Part II: SQL and SQL*Plus
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 14
Blind Folio 14:266
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

P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:48 PM
Color profile: Generic CMYK printer profile
Composite Default screen
Chapter 14: Some Complex Possibilities
267
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 14
Blind Folio 14:267
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
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:49 PM
Color profile: Generic CMYK printer profile
Composite Default screen
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 a

family 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.
268
Part II: SQL and SQL*Plus
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 14
Blind Folio 14:268
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:49 PM
Color profile: Generic CMYK printer profile
Composite Default screen
Chapter 14: Some Complex Possibilities
269
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 14
Blind Folio 14:269
The earliest ancestor in the tree is technically called the
root node.
In everyday English, this
would be called the
trunk.
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 called
nodes,

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. As
each 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
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:50 PM
Color profile: Generic CMYK printer profile
Composite Default screen
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
EVE F
ADAM M
BANDIT M
Next, a query is written to illustrate the family relationships visually. This is done using LPAD
and a special column, Level, that comes along with connect by. Level is a number, from 1 for EVE
to 5 for DELLA, that is really the
generation.
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 a
pseudo-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
270
Part II: SQL and SQL*Plus
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 14
Blind Folio 14:270
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:50 PM
Color profile: Generic CMYK printer profile
Composite Default screen
Chapter 14: Some Complex Possibilities
271
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 14
Blind Folio 14:271
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 specified
string
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, the
string
is a single character (a space, indicated by the literal space enclosed in single
quotation marks). Also, 6*(Level–1) is the
length

, 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
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:51 PM
Color profile: Generic CMYK printer profile
Composite Default screen
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
272
Part II: SQL and SQL*Plus
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 14
Blind Folio 14:272
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:51 PM
Color profile: Generic CMYK printer profile
Composite Default screen
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
Chapter 14: Some Complex Possibilities
273
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 14
Blind Folio 14:273
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:52 PM
Color profile: Generic CMYK printer profile
Composite Default screen
274
Part II: SQL and SQL*Plus
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 14
Blind Folio 14:274
MANDY POCO PAULA F 21-DEC-06
SUZY BANDIT DELLA F 11-OCT-08
EVE F
The generations are still obvious in the display, but siblings are more closely grouped with
each other. Another way to look at the same family tree is by Birthdate, as follows:
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 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 still
preserves 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;
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp

Friday, August 13, 2004 1:46:52 PM
Color profile: Generic CMYK printer profile
Composite Default screen
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
Chapter 14: Some Complex Possibilities
275
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 14
Blind Folio 14:275
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:53 PM
Color profile: Generic CMYK printer profile
Composite Default screen
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 single
tree 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
must be followed:

The order of the clauses when using connect by is as follows:
1.

select
2.
from
3.
where
4.
start with
276
Part II: SQL and SQL*Plus
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 14
Blind Folio 14:276
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:53 PM
Color profile: Generic CMYK printer profile
Composite Default screen
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.
Chapter 14: Some Complex Possibilities
277
ORACLE Series TIGHT / Oracle Database 10g: TCR / Loney / 225351-7 / Chapter 14
Blind Folio 14:277
P:\010Comp\Oracle8\351-7\CD\Ventura\book.vp
Friday, August 13, 2004 1:46:53 PM
Color profile: Generic CMYK printer profile
Composite Default screen

×