Chupter ll: lntroducíng lL/SQL lrogrummíng

371
1he exumpíe trígger you'íí see ín thís sectíon líres belore un updute ol the price coíumn ín
the products tubíe, therelore, l'íí nume the trígger before_product_price_update. Aíso,
becuuse l wunt to use the price coíumn vuíues belore und ulter un UPDATE stutement modílíes
the price coíumn's vuíue, l must use u row-íeveí trígger. línuííy, l wunt to uudít u príce chunge
when the new príce ís íowered by more thun 25 percent ol the oíd príce, therelore, l'íí need to
specíly u trígger condítíon to compure the new príce wíth the oíd príce. 1he loííowíng stutement
creutes the before_product_price_update trígger:
CREATE TRIGGER before_product_price_update
BEFORE UPDATE OF price
ON products
FOR EACH ROW WHEN (new.price < old.price * 0.75)
BEGIN
dbms_output.put_line('product_id = ' || :old.product_id);
dbms_output.put_line('Old price = ' || :old.price);
dbms_output.put_line('New price = ' || :new.price);
dbms_output.put_line('The price reduction is more than 25%');
-- insert row into the product_price_audit table
INSERT INTO product_price_audit (
product_id, old_price, new_price
) VALUES (
:old.product_id, :old.price, :new.price
);
END before_product_price_update;
/
1here ure líve thíngs you shouíd notíce ubout thís stutement:
BEFORE UPDATE OF price meuns the trígger líres belore un updute ol the price
coíumn.
FOR EACH ROW meuns thís us u row-íeveí trígger, thut ís, the trígger code contuíned
wíthín the BEGIN und END keywords runs once lor euch row modílíed by the updute.
1he trígger condítíon ís (new.price < old.price * 0.75), whích meuns the
trígger líres oníy when the new príce ís íess thun 75 percent ol the oíd príce (thut ís,
when the príce ís reduced by more thun 25 percent).
1he new und oíd coíumn vuíues ure uccessed usíng the :old und :new uííuses ín the trígger.
1he trígger code díspíuys the product_id, the oíd und new prices, und u messuge
stutíng thut the príce reductíon ís more thun 25 percent. 1he code then udds u row to the
product_price_audit tubíe contuíníng the product_id und the oíd und new príces.
firing a Triggcr
1o see the output lrom the trígger, you need to run the SET SERVEROUTPUT ON commund:
SET SERVEROUTPUT ON
1o líre the before_product_price_update trígger, you must reduce u product's príce by
more thun 25 percent. Co uheud und perlorm the loííowíng UPDATE stutement to reduce the príce
372
Crucíe Dutubuse llg SQL
ol products r5 und rl0 by 30 percent (thís ís uchíeved by muítípíyíng the price coíumn by .7).
1he loííowíng UPDATE stutement cuuses the before_product_price_update trígger to líre:
UPDATE products
SET price = price * .7
WHERE product_id IN (5, 10);
product_id = 10
Old price = 15.99
New price = 11.19
The price reduction is more than 25%
product_id = 5
Old price = 49.99
New price = 34.99
The price reduction is more than 25%
2 rows updated.
As you cun see, the trígger líred lor products rl0 und r5. You cun see thut the trígger díd
índeed udd the two requíred rows contuíníng the product_ids, uíong wíth the oíd und new
príces, to the product_price_audit tubíe usíng the loííowíng query:
SELECT *
FROM product_price_audit
ORDER BY product_id;
PRODUCT_ID OLD_PRICE NEW_PRICE
---------- ---------- ----------
5 49.99 34.99
10 15.99 11.19
Gctting lnfurmatiun un Triggcrs
You cun get ínlormutíon on your tríggers lrom the user_triggers víew. 1ubíe ll-3 descríbes
some ol the coíumns ín user_triggers.
CuIumn Typc Dcscriptiun
TRIGGER_NAME VARCHAR2(30)
Nume ol the trígger.
TRIGGER_TYPE VARCHAR2(16)
1ype ol the trígger.
TRIGGERING_EVENT VARCHAR2(227)
Lvent thut cuuses the trígger to líre.
TABLE_OWNER VARCHAR2(30)
Lser who owns the tubíe thut the trígger
relerences.
BASE_OBJECT_TYPE VARCHAR2(16)
1ype ol the ob¡ect relerenced by the trígger.
TABLE_NAME VARCHAR2(30)
Nume ol the tubíe relerenced by the trígger.
COLUMN_NAME VARCHAR2(4000)
Nume ol the coíumn relerenced by the
trígger.
TABlf 11-3 Somc Coíumn· ín |hc user_triggers Vícv
Chupter ll: lntroducíng lL/SQL lrogrummíng
373
NOTf
You can gc| ín|orma|íon on aíí |hc |ríggcr· ,ou havc accc·· |o u·íng
all_triggers.
1he loííowíng exumpíe retríeves the detuíís ol the before_product_price_update
trígger lrom user_triggers (the output ís prínted pretty lor cíuríty):
SELECT trigger_name, trigger_type, triggering_event, table_owner
base_object_type, table_name, referencing_names, when_clause, status,
description, action_type, trigger_body
FROM user_triggers
WHERE trigger_name = 'BEFORE_PRODUCT_PRICE_UPDATE';
TRIGGER_NAME TRIGGER_TYPE
------------------------------ ----------------
BEFORE_PRODUCT_PRICE_UPDATE BEFORE EACH ROW
TRIGGERING_EVENT
----------------
UPDATE
TABLE_OWNER BASE_OBJECT_TYPE TABLE_NAME
------------------------------ ---------------- -----------
STORE TABLE PRODUCTS
REFERENCING_NAMES
-----------------------------------------------------------
REFERENCING NEW AS NEW OLD AS OLD
WHEN_CLAUSE
-----------------------------------------------------------
new.price < old.price * 0.75
CuIumn Typc Dcscriptiun
REFERENCING_NAMES VARCHAR2(128)
Nume ol the oíd und new uííuses.
WHEN_CLAUSE VARCHAR2(4000)
1rígger condítíon thut íímíts when the
trígger runs íts code.
STATUS VARCHAR2(8)
\hether the trígger ís enubíed or
dísubíed (ENABLED or DISABLED).
DESCRIPTION VARCHAR2(4000)
Descríptíon ol the trígger.
ACTION_TYPE VARCHAR2(11)
Actíon type ol the trígger (CALL or
PL/SQL).
TRIGGER_BODY LONG
Code contuíned ín the trígger body. (1he
LONG type uííows storuge ol íurge umounts
ol text. You'íí íeurn ubout the LONG type ín
Chupter l4.)
TABlf 11-3 Somc Coíumn· ín |hc user_triggers Vícv (contínued)
374
Crucíe Dutubuse llg SQL
STATUS
--------
ENABLED
DESCRIPTION
-----------------------------------------------------------
before_product_price_update
BEFORE UPDATE OF
price
ON
products
FOR EACH ROW
ACTION_TYPE
-----------
PL/SQL
TRIGGER_BODY
-----------------------------------------------------------
BEGIN
dbms_output.put_line('product_id = ' || :old.product_id);
dbms_output...
NOTf
You can ·cc aíí |hc codc |or |hc |ríggcr u·íng |hc SÇí*ííu· SET LONG
command, |or cxampíc, SET LONG 1000.
DisabIing and fnabIing a Triggcr
You cun stop u trígger lrom líríng by dísubííng ít by usíng the ALTER TRIGGER stutement. 1he
loííowíng exumpíe dísubíes the before_product_price_update trígger:
ALTER TRIGGER before_product_price_update DISABLE;
1he next exumpíe enubíes the before_product_price_update trígger:
ALTER TRIGGER before_product_price_update ENABLE;
Drupping a Triggcr
You drop u trígger usíng DROP TRIGGER. 1he loííowíng exumpíe drops the before_product_
price_update trígger:
DROP TRIGGER before_product_price_update;
Ncw OracIc Databasc 11 Pl/SQl fcaturcs
ln thís sectíon, you'íí see some ol the new lL/SQL leutures íntroduced ín Crucíe Dutubuse llg.
Specílícuííy, the loííowíng wííí be díscussed:
1he SIMPLE_INTEGER type
Support lor sequences ín lL/SQL
lL/SQL nutíve muchíne code generutíon
Chupter ll: lntroducíng lL/SQL lrogrummíng
37S
SlMPlf_lNTfGfR Typc
1he SIMPLE_INTEGER type ís u subtype ol BINARY_INTEGER, the SIMPLE_INTEGER cun store
the sume runge us BINARY_INTEGER, except SIMPLE_INTEGER cunnot store u NULL vuíue.
1he runge ol vuíues SIMPLE_INTEGER cun store ís 2
3l
(2,l47,483,648) to 2
3l
(2,l47,483,648).
Aríthmetíc overlíow ís truncuted when usíng SIMPLE_INTEGER vuíues, therelore, cuícuíutíons
don't ruíse un error when overlíow occurs. ßecuuse overlíow errors ure ígnored, the vuíues stored
ín u SIMPLE_INTEGER cun wrup lrom posítíve to negutíve und lrom negutíve to posítíve, us, lor
exumpíe:
2
30
+ 2
30
= 0x40000000 + 0x40000000 = 0x80000000 = 2
3l
2
3l
+ 2
3l
= 0x80000000 + 0x80000000 = 0x00000000 = 0
ln the lírst exumpíe, two posítíve vuíues ure udded, und u negutíve totuí ís produced. ln the
second exumpíe, two negutíve vuíues ure udded, und zero ís produced.
ßecuuse overlíow ís ígnored und truncuted when usíng SIMPLE_INTEGER vuíues ín cuícuíutíons,
SIMPLE_INTEGER ollers much better perlormunce thun BINARY_INTEGER when the DßA
conlígures the dutubuse to compííe lL/SQL to nutíve muchíne code. ßecuuse ol thís benelít, you
shouíd use SIMPLE_INTEGER ín your lL/SQL code when you don't need to store u NULL und
you don't cure ubout overlíow truncutíon occurríng ín your cuícuíutíons, otherwíse, you shouíd
use BINARY_INTEGER.
1he loííowíng get_area() procedure shows the use ol the SIMPLE_INTEGER type, get_
area() cuícuíutes und díspíuys the ureu ol u rectungíe:
CREATE PROCEDURE get_area
AS
v_width SIMPLE_INTEGER := 10;
v_height SIMPLE_INTEGER := 2;
v_area SIMPLE_INTEGER := v_width * v_height;
BEGIN
DBMS_OUTPUT.PUT_LINE('v_area = ' || v_area);
END get_area;
/
NOTf
You'íí |índ |hí· cxampíc, and |hc o|hcr cxampíc· ín |hí· ·cc|íon, ín a
·críp| namcd plsql_11g_examples.sql ín |hc SQL dírcc|or,. You
ma, run |hí· ·críp| í| ,ou arc u·íng Cracíc Da|aba·c 11g.
1he loííowíng exumpíe shows the executíon ol get_area():
SET SERVEROUTPUT ON
CALL get_area();
v_area = 20
As expected, the cuícuíuted ureu ís 20.
Scqucnccs in Pl/SQl
ln the prevíous chupter you suw how to creute und use sequences ol numbers ín SQL. ln Crucíe
Dutubuse llg, you cun uíso use sequences ín lL/SQL code.
As u remínder, u sequence generutes u seríes ol numbers. \hen you creute u sequence ín
SQL, you cun specíly íts ínítíuí vuíue und un íncrement lor the seríes ol subsequent numbers.

Crucíe Dutubuse ll SQL
You use the currval pseudo coíumn to get the current vuíue ín the sequence und nextval to
generute the next number. ßelore you uccess currval, you must lírst use nextval to generute
un ínítíuí number.
1he loííowíng stutement creutes u tubíe numed new_products, thís tubíe wííí be used shortíy:
CREATE TABLE new_products (
product_id INTEGER CONSTRAINT new_products_pk PRIMARY KEY,
name VARCHAR2(30) NOT NULL,
price NUMBER(5, 2)
);
1he next stutement creutes u sequence numed s_product_id:
CREATE SEQUENCE s_product_id;
1he loííowíng stutement creutes u procedure numed add_new_products, whích uses s_
product_id to set the product_id coíumn ín u row udded to the new_products tubíe,
notíce the use ol the nextval und currval pseudo coíumns ín the lL/SQL code (thís ís new
lor Crucíe Dutubuse ll):
CREATE PROCEDURE add_new_products
AS
v_product_id BINARY_INTEGER;
BEGIN
-- use nextval to generate the initial sequence number
v_product_id := s_product_id.nextval;
DBMS_OUTPUT.PUT_LINE('v_product_id = ' || v_product_id);
-- add a row to new_products
INSERT INTO new_products
VALUES (v_product_id, 'Plasma Physics book', 49.95);
DBMS_OUTPUT.PUT_LINE('s_product_id.currval = ' || s_product_id.currval);
-- use nextval to generate the next sequence number
v_product_id := s_product_id.nextval;
DBMS_OUTPUT.PUT_LINE('v_product_id = ' || v_product_id);
-- add another row to new_products
INSERT INTO new_products
VALUES (v_product_id, 'Quantum Physics book', 69.95);
DBMS_OUTPUT.PUT_LINE('s_product_id.currval = ' || s_product_id.currval);
END add_new_products;
/
1he loííowíng exumpíe runs add_new_products() und shows the contents ol the new_
products tubíe:
SET SERVEROUTPUT ON
CALL add_new_products();
v_product_id = 1
Chupter ll: lntroducíng lL/SQL lrogrummíng
377
s_product_id.currval = 1
v_product_id = 2
s_product_id.currval = 2
SELECT * FROM new_products;
PRODUCT_ID NAME PRICE
---------- ------------------------------ ----------
1 Plasma Physics book 49.95
2 Quantum Physics book 69.95
As expected, two rows were udded to the tubíe.
Pl/SQl Nativc Machinc Cudc Gcncratiun
ßy deluuít, euch lL/SQL progrum unít ís compííed ínto íntermedíute lorm, muchíne-reudubíe code.
1hís muchíne-reudubíe code ís stored ín the dutubuse und ínterpreted every tíme the code ís run.
\íth lL/SQL nutíve compííutíon, the lL/SQL ís turned ínto nutíve code und stored ín shured
ííbruríes. Nutíve code runs much luster thun íntermedíute code becuuse nutíve code doesn't huve
to be ínterpreted belore ít runs.
ln certuín versíons ol the dutubuse príor to Crucíe Dutubuse llg, you cun compííe lL/SQL
code to C code, und then compííe the C code ínto muchíne code, thís ís u very íuboríous und
probíemutíc process. ln Crucíe Dutubuse llg, the lL/SQL compííer cun generute nutíve muchíne
code dírectíy. Settíng up the dutubuse to generute nutíve muchíne code shouíd be done oníy by un
experíenced DßA (us such, íts coveruge ís beyond the scope ol thís book). You cun reud uíí ubout
lL/SQL nutíve muchíne code generutíon ín the íí/SÇí L·cr'· Cuídc and Rc|crcncc munuuí lrom
Crucíe Corporutíon.
Summary
ln thís chupter, you íeurned the loííowíng:
lL/SQL progrums ure dívíded up ínto bíocks contuíníng lL/SQL und SQL stutements.
A íoop, such us u WHILE or FOR íoop, runs stutements muítípíe tímes.
A cursor uííows lL/SQL to reud the rows returned by u query.
Lxceptíons ure used to hundíe run-tíme errors thut occur ín your lL/SQL code.
A procedure contuíns u group ol stutements. lrocedures uííow you to centruííze your
busíness íogíc ín the dutubuse und muy be run by uny progrum thut uccesses the dutubuse.
A lunctíon ís símííur to u procedure except thut u lunctíon must return u vuíue.
You cun group procedures und lunctíons together ínto puckuges, whích encupsuíute
reíuted lunctíonuííty ínto one seíl-contuíned unít.
A trígger ís u procedure thut ís run uutomutícuííy by the dutubuse when u specílíc INSERT,
UPDATE, or DELETE stutement ís run. 1ríggers ure useluí lor doíng thíngs ííke udvunced
uudítíng ol chunges mude to coíumn vuíues ín u tubíe.
ln the next chupter, you'íí íeurn ubout dutubuse ob¡ects.
This page intentionally left blank
\IAI1II
1z
Dutubuse Cb¡ects
379
380
Crucíe Dutubuse llg SQL
n thís chupter, you wííí do the loííowíng:
Leurn ubout ob¡ects ín the dutubuse
Leurn how to creute ob¡ect types contuíníng uttríbutes und methods
Lse ob¡ect types to delíne coíumn ob¡ects und ob¡ect tubíes
Creute und munípuíute ob¡ects ín SQL und lL/SQL
Leurn how u type muy ínherít lrom unother type und creute híerurchíes ol types
Delíne your own constructors to set the uttríbutes ol un ob¡ect
See how to overríde u method ín one type wíth u method lrom unother type
lntruducing Objccts
Cb¡ect-oríented progrummíng íunguuges such us }uvu, C++, und Cr uííow you to delíne cíusses,
und these cíusses uct us tempíutes lrom whích you cun creute ob¡ects. Cíusses delíne uttríbutes
und methods, uttríbutes ure used to store un ob¡ect's stute, und methods ure used to modeí un
ob¡ect's behuvíors.
\íth the reíeuse ol Crucíe Dutubuse 8, ob¡ects becume uvuííubíe wíthín the dutubuse, und
ob¡ect leutures huve been ímproved upon ín subsequent product reíeuses. 1he uvuííubíííty ol ob¡ects
ín the dutubuse wus u mu¡or breukthrough becuuse they enubíe you to delíne your own cíusses,
known us ob]cc| |,pc·, ín the dutubuse. Líke cíusses ín }uvu und Cr, dutubuse ob¡ect types cun
contuín uttríbutes und methods. Cb¡ect types ure uíso sometímes known us user-delíned types.
A símpíe exumpíe ol un ob¡ect type wouíd be u type thut represents u product. 1hís ob¡ect type
couíd contuín uttríbutes lor the product's nume, descríptíon, príce, und, ín the cuse ol u product
thut ís períshubíe, the number ol duys the product cun sít on the sheíl belore ít must be thrown
uwuy. 1hís product ob¡ect type couíd uíso contuín u method thut returns the seíí-by dute ol the
product, bused on the sheíl ííle ol the product und the current dute. Another exumpíe ol un ob¡ect
type ís one thut represents u person, thís ob¡ect type couíd store uttríbutes lor the person's lírst nume,
íust nume, dute ol bírth, und uddress, the person's uddress couíd ítseíl be represented by un ob¡ect
type, und ít couíd store thíngs ííke the street, cíty, stute, und zíp code. ln thís chupter you'íí see
exumpíes ol ob¡ect types thut represent u product, person, und uddress. You'íí uíso see how to
creute tubíes lrom those ob¡ect types, popuíute those tubíes wíth uctuuí ob¡ects, und munípuíute
those ob¡ects ín SQL und lL/SQL.
l've províded un SQL*líus scrípt numed object_schema.sql ín the SQL dírectory, whích
creutes u user numed object_user wíth u pussword ol object_password. 1hís scrípt uíso
creutes the types und tubíes, perlorms the vuríous INSERT stutements, und creutes the lL/SQL
code shown ín the lírst purt ol thís chupter. You must run thís scrípt whííe íogged ín us u user wíth
the requíred prívííeges to creute u new user wíth the CONNECT, RESOURCE, und CREATE PUBLIC
SYNONYM prívííeges, l íog ín us the system user on my dutubuse to run the scrípts. Alter the scrípt
compíetes, you wííí be íogged ín us object_user.

Chupter l2: Dutubuse Cb¡ects
381
Crcating Objcct Typcs
You creute un ob¡ect type usíng the CREATE TYPE stutement. 1he loííowíng exumpíe uses the
CREATE TYPE stutement to creute un ob¡ect type numed t_address. 1hís ob¡ect type ís used
to represent un uddress und contuíns lour uttríbutes numed street, city, state, und zip:
CREATE TYPE t_address AS OBJECT (
street VARCHAR2(15),
city VARCHAR2(15),
state CHAR(2),
zip VARCHAR2(5)
);
/
1he exumpíe shows thut euch uttríbute ís delíned usíng u dutubuse type. lor exumpíe,
street ís delíned us VARCHAR2(15). As you'íí see shortíy, the type ol un uttríbute cun ítseíl
be un ob¡ect type.
1he next exumpíe creutes un ob¡ect type numed t_person, notíce thut t_person hus un
uttríbute numed address, whích ís ol type t_address:
CREATE TYPE t_person AS OBJECT (
id INTEGER,
first_name VARCHAR2(10),
last_name VARCHAR2(10),
dob DATE,
phone VARCHAR2(12),
address t_address
);
/
1he loííowíng exumpíe creutes un ob¡ect type numed t_product thut wííí be used to
represent products, notíce thut thís type decíures u lunctíon numed get_sell_by_date()
usíng the MEMBER FUNCTION cíuuse:
CREATE TYPE t_product AS OBJECT (
id INTEGER,
name VARCHAR2(15),
description VARCHAR2(22),
price NUMBER(5, 2),
days_valid INTEGER,
-- get_sell_by_date() returns the date by which the
-- product must be sold
MEMBER FUNCTION get_sell_by_date RETURN DATE
);
/
ßecuuse t_product contuíns u method decíurutíon, u  lor t_product must uíso be
creuted. 1he body contuíns the uctuuí code lor the method, und the body ís creuted usíng the
CREATE TYPE BODY stutement. 1he loííowíng exumpíe creutes the body lor t_product,
notíce the body contuíns the code lor the get_sell_by_date() lunctíon.
382
Crucíe Dutubuse ll SQL
CREATE TYPE BODY t_product AS
-- get_sell_by_date() returns the date by which the
-- product must be sold
MEMBER FUNCTION get_sell_by_date RETURN DATE IS
v_sell_by_date DATE;
BEGIN
-- calculate the sell by date by adding the days_valid attribute
-- to the current date (SYSDATE)
SELECT days_valid + SYSDATE
INTO v_sell_by_date
FROM dual;
-- return the sell by date
RETURN v_sell_by_date;
END;
END;
/
As you cun see, get_sell_by_date() cuícuíutes und returns the dute by whích the
product must be soíd, ít does thís by uddíng the days_valid uttríbute to the current dute
returned by the buíít-ín dutubuse SYSDATE() lunctíon.
You cun uíso creute u pubííc synonym lor u type, whích enubíes uíí users to see the type und
use ít to delíne coíumns ín theír own tubíes. 1he loííowíng exumpíe creutes u pubííc synonym
numed t_pub_product lor t_product:
CREATE PUBLIC SYNONYM t_pub_product FOR t_product;
Using DfSCRlBf tu Gct lnfurmatiun
un Objcct Typcs
You cun use the DESCRIBE commund to get ínlormutíon on un ob¡ect type. 1he loííowíng
exumpíes show the t_address, t_person, und t_product types:
DESCRIBE t_address
Name Null? Type
----------------------------------------- -------- ------------
STREET VARCHAR2(15)
CITY VARCHAR2(15)
STATE CHAR(2)
ZIP VARCHAR2(5)
DESCRIBE t_person
Name Null? Type
----------------------------------------- -------- ------------
ID NUMBER(38)
FIRST_NAME VARCHAR2(10)
LAST_NAME VARCHAR2(10)
DOB DATE
PHONE VARCHAR2(12)
ADDRESS T_ADDRESS
Chupter l2: Dutubuse Cb¡ects
383
DESCRIBE t_product
Name Null? Type
----------------------------------------- -------- ------------
ID NUMBER(38)
NAME VARCHAR2(10)
DESCRIPTION VARCHAR2(22)
PRICE NUMBER(5,2)
DAYS_VALID INTEGER
METHOD
------
MEMBER FUNCTION GET_SELL_BY_DATE RETURNS DATE
You cun set the depth to whích DESCRIBE wííí show ínlormutíon lor embedded types usíng
SET DESCRIBE DEPTH. 1he loííowíng exumpíe sets the depth to 2 und then descríbes t_person
uguín, notíce thut the uttríbutes ol address ure díspíuyed, whích ís un embedded ob¡ect ol type
t_address:
SET DESCRIBE DEPTH 2
DESCRIBE t_person
Name Null? Type
----------------------------------------- -------- ------------
ID NUMBER(38)
FIRST_NAME VARCHAR2(10)
LAST_NAME VARCHAR2(10)
DOB DATE
PHONE VARCHAR2(12)
ADDRESS T_ADDRESS
STREET VARCHAR2(15)
CITY VARCHAR2(15)
STATE CHAR(2)
ZIP VARCHAR2(5)
Using Objcct Typcs in Databasc TabIcs
Now thut you've seen how to creute ob¡ect types, íet's íook ut how you use these types ín dutubuse
tubíes. You cun use un ob¡ect type to delíne un índívíduuí coíumn ín u tubíe, und the ob¡ects
subsequentíy stored ín thut coíumn ure known us coíumn ob]cc|·. You cun uíso use un ob¡ect type to
delíne un entíre row ín u tubíe, the tubíe ís then known us un ob]cc| |abíc. línuííy, you cun use un ob]cc|
rc|crcncc to uccess un índívíduuí row ín un ob¡ect tubíe, un ob¡ect relerence ís símííur to u poínter ín
C++. You'íí see exumpíes ol coíumn ob¡ects, ob¡ect tubíes, und ob¡ect relerences ín thís sectíon.
CuIumn Objccts
1he loííowíng exumpíe creutes u tubíe numed products thut contuíns u coíumn numed product
ol type t_product, the tubíe uíso contuíns u coíumn numed quantity_in_stock, whích ís
used to store the number ol those products currentíy ín stock:
CREATE TABLE products (
product t_product,
quantity_in_stock INTEGER
);

Crucíe Dutubuse ll SQL
\hen uddíng u row to thís tubíe, you must use u  to suppíy the uttríbute vuíues lor
the new t_product ob¡ect, us u remínder, the t_product type wus creuted usíng the loííowíng
stutement:
CREATE TYPE t_product AS OBJECT (
id INTEGER,
name VARCHAR2(10),
description VARCHAR2(22),
price NUMBER(5, 2),
days_valid INTEGER,
-- declare the get_sell_by_date() member function,
-- get_sell_by_date() returns the date by which the
-- product must be sold
MEMBER FUNCTION get_sell_by_date RETURN DATE
);
/
A constructor ís u buíít-ín method lor the ob¡ect type, und ít hus the sume nume us the ob¡ect
type, the constructor uccepts purumeters thut ure used to set the uttríbutes ol the new ob¡ect. 1he
constructor lor the t_product type ís numed t_product und uccepts líve purumeters, one
to set euch ol the uttríbutes, lor exumpíe, t_product(1, pasta, 20 oz bag of pasta,
3.95, 10) creutes u new t_product ob¡ect und sets íts id to l, name to pasta, description
to 20 oz bag of pasta, price to 3.95, und days_valid to l0.
1he loííowíng INSERT stutements udd two rows to the products tubíe, notíce the use
ol the t_product constructor to suppíy the uttríbute vuíues lor the product coíumn
ob¡ects:
INSERT INTO products (
product,
quantity_in_stock
) VALUES (
t_product(1, 'pasta', '20 oz bag of pasta', 3.95, 10),
50
);
INSERT INTO products (
product,
quantity_in_stock
) VALUES (
t_product(2, 'sardines', '12 oz box of sardines', 2.99, 5),
25
);
1he loííowíng query retríeves these rows lrom the products tubíe, notíce thut the product
coíumn ob¡ects' uttríbutes ure díspíuyed wíthín u constructor lor t_product:
SELECT *
FROM products;
Chupter l2: Dutubuse Cb¡ects

PRODUCT(ID, NAME, DESCRIPTION, PRICE, DAYS_VALID)
----------------------------------------------------------
QUANTITY_IN_STOCK
-----------------
T_PRODUCT(1, 'pasta', '20 oz bag of pasta', 3.95, 10)
50
T_PRODUCT(2, 'sardines', '12 oz box of sardines', 2.99, 5)
25
You cun uíso retríeve un índívíduuí coíumn ob¡ect lrom u tubíe, to do thís, you must suppíy u
tubíe uííus through whích you seíect the ob¡ect. 1he loííowíng query retríeves product rl lrom the
products tubíe, notíce the use ol the tubíe uííus p lor the products tubíe, through whích the
product ob¡ect's id uttríbute ís specílíed ín the WHERE cíuuse:
SELECT p.product
FROM products p
WHERE p.product.id = 1;
PRODUCT(ID, NAME, DESCRIPTION, PRICE, DAYS_VALID)
-----------------------------------------------------
T_PRODUCT(1, 'pasta', '20 oz bag of pasta', 3.95, 10)
1he next query expíícítíy íncíudes the product ob¡ect's id, name, price, und days_
valid uttríbutes ín the SELECT stutement, píus the quantity_in_stock:
SELECT p.product.id, p.product.name,
p.product.price, p.product.days_valid, p.quantity_in_stock
FROM products p
WHERE p.product.id = 1;
PRODUCT.ID PRODUCT.NA PRODUCT.PRICE PRODUCT.DAYS_VALID QUANTITY_IN_STOCK
---------- ---------- ------------- ------------------ -----------------
1 pasta 3.95 10 50
1he t_product ob¡ect type contuíns u lunctíon numed get_sell_by_date(), whích
cuícuíutes und returns the dute by whích the product must be soíd. 1he lunctíon does thís by
uddíng the days_valid uttríbute to the current dute, whích ís obtuíned lrom the dutubuse usíng
the SYSDATE() lunctíon. You cun cuíí the get_sell_by_date() lunctíon usíng u tubíe uííus,
us shown ín the loííowíng query thut uses the tubíe uííus p lor the products tubíe:
SELECT p.product.get_sell_by_date()
FROM products p;
P.PRODUCT
---------
19-JUN-07
13-JUN-07
Cl course, íl you run thís query your dutes wííí be díllerent, becuuse they ure cuícuíuted usíng
SYSDATE(), whích returns the current dute und tíme.
386
Crucíe Dutubuse llg SQL
1he loííowíng UPDATE stutement modílíes the descríptíon ol product rl, notíce thut the tubíe
uííus p ís used uguín:
UPDATE products p
SET p.product.description = '30 oz bag of pasta'
WHERE p.product.id = 1;
1 row updated.
1he loííowíng DELETE stutement removes product r2:
DELETE FROM products p
WHERE p.product.id = 2;
1 row deleted.
ROLLBACK;
NOTf
í| ,ou run |hc·c UPDATE and DELETE ·|a|cmcn|·, ma|c ·urc ,ou
cxccu|c |hc ROLLBACK ·o |ha| ,our cxampíc da|a ma|chc· |ha| ·hovn
ín |hc rc·| o| |hí· chap|cr.
Objcct TabIcs
You cun use un ob¡ect type to delíne un entíre tubíe, und such u tubíe ís known us un ob¡ect tubíe.
1he loííowíng exumpíe creutes un ob¡ect tubíe numed object_products, whích stores ob¡ects
ol type t_product, notíce the use ol the OF keyword to ídentíly the tubíe us un ob¡ect tubíe ol
type t_product:
CREATE TABLE object_products OF t_product;
\hen ínsertíng u row ínto un ob¡ect tubíe, you cun choose whether to use u constructor to
suppíy uttríbute vuíues or to suppíy the vuíues ín the sume wuy thut you wouíd suppíy coíumn
vuíues ín u reíutíonuí tubíe. 1he loííowíng INSERT stutement udds u row to the object_
products tubíe usíng the constructor lor t_product:
INSERT INTO object_products VALUES (
t_product(1, 'pasta', '20 oz bag of pasta', 3.95, 10)
);
1he next INSERT stutement omíts the constructor lor t_product, notíce thut the uttríbute
vuíues lor t_product ure suppííed ín the sume wuy thut coíumns wouíd be ín u reíutíonuí tubíe:
INSERT INTO object_products (
id, name, description, price, days_valid
) VALUES (
2, 'sardines', '12 oz box of sardines', 2.99, 5
);
1he loííowíng query retríeves these rows lrom the object_products tubíe:
SELECT *
FROM object_products;
Chupter l2: Dutubuse Cb¡ects

ID NAME DESCRIPTION PRICE DAYS_VALID
---------- ---------- ---------------------- ---------- ----------
1 pasta 20 oz bag of pasta 3.95 10
2 sardines 12 oz box of sardines 2.99 5
You cun uíso specíly índívíduuí ob¡ect uttríbutes ín u query, lor exumpíe, by doíng thís:
SELECT id, name, price
FROM object_products op
WHERE id = 1;
ID NAME PRICE
---------- ---------- ----------
1 pasta 3.95
or thís:
SELECT op.id, op.name, op.price
FROM object_products op
WHERE op.id = 1;
ID NAME PRICE
---------- ---------- ----------
1 pasta 3.95
You cun use the buíít-ín Crucíe dutubuse VALUE() lunctíon to seíect u row lrom un ob¡ect
tubíe. VALUE() treuts the row us un uctuuí ob¡ect und returns the uttríbutes lor the ob¡ect wíthín
u constructor lor the ob¡ect type. VALUE() uccepts u purumeter contuíníng u tubíe uííus, us shown
ín the loííowíng query:
SELECT VALUE(op)
FROM object_products op;
VALUE(OP)(ID, NAME, DESCRIPTION, PRICE, DAYS_VALID)
----------------------------------------------------------
T_PRODUCT(1, 'pasta', '20 oz bag of pasta', 3.95, 10)
T_PRODUCT(2, 'sardines', '12 oz box of sardines', 2.99, 5)
You cun uíso udd un ob¡ect uttríbute ulter VALUE():
SELECT VALUE(op).id, VALUE(op).name, VALUE(op).price
FROM object_products op;
VALUE(OP).ID VALUE(OP). VALUE(OP).PRICE
------------ ---------- ---------------
1 pasta 3.95
2 sardines 2.99
1he loííowíng UPDATE stutement modílíes the descríptíon ol product rl:
UPDATE object_products
SET description = '25 oz bag of pasta'
WHERE id = 1;
1 row updated.

Crucíe Dutubuse ll SQL
1he loííowíng DELETE stutement removes product r2:
DELETE FROM object_products
WHERE id = 2;
1 row deleted.
ROLLBACK;
Let's tuke u íook ut u more compíex ob¡ect tubíe. 1he loííowíng CREATE TABLE stutement
creutes un ob¡ect tubíe numed object_customers, whích stores ob¡ects ol type t_person:
CREATE TABLE object_customers OF t_person;
1he t_person type contuíns un embedded t_address ob¡ect, t_person wus creuted
usíng the loííowíng stutement:
CREATE TYPE t_person AS OBJECT (
id INTEGER,
first_name VARCHAR2(10),
last_name VARCHAR2(10),
dob DATE,
phone VARCHAR2(12),
address t_address
);
/
1he loííowíng INSERT stutements udd two rows ínto object_customers. 1he lírst INSERT
uses constructors lor t_person und t_address, whííe the second INSERT omíts the t_person
constructor:
INSERT INTO object_customers VALUES (
t_person(1, 'John', 'Brown', '01-FEB-1955', '800-555-1211',
t_address('2 State Street', 'Beantown', 'MA', '12345')
)
);
INSERT INTO object_customers (
id, first_name, last_name, dob, phone,
address
) VALUES (
2, 'Cynthia', 'Green', '05-FEB-1968', '800-555-1212',
t_address('3 Free Street', 'Middle Town', 'CA', '12345')
);
1he loííowíng query retríeves these rows lrom the object_customers tubíe, notíce thut
the uttríbutes lor the embedded address coíumn ob¡ect ure díspíuyed wíthín the t_address
constructor:
SELECT *
FROM object_customers;
Chupter l2: Dutubuse Cb¡ects

ID FIRST_NAME LAST_NAME DOB PHONE
---------- ---------- ---------- --------- ------------
ADDRESS(STREET, CITY, STATE, ZIP)
--------------------------------------------------------
1 John Brown 01-FEB-55 800-555-1211
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345')
2 Cynthia Green 05-FEB-68 800-555-1212
T_ADDRESS('3 Free Street', 'Middle Town', 'CA', '12345')
1he next query retríeves customer rl lrom object_customers, notíce the use ol the tubíe
uííus oc through whích the id uttríbute ís specílíed ín the WHERE cíuuse:
SELECT *
FROM object_customers oc
WHERE oc.id = 1;
ID FIRST_NAME LAST_NAME DOB PHONE
---------- ---------- ---------- --------- ------------
ADDRESS(STREET, CITY, STATE, ZIP)
------------------------------------------------------
1 John Brown 01-FEB-55 800-555-1211
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345')
ln the loííowíng query, u customer ís retríeved bused on the state uttríbute ol the address
coíumn ob¡ect:
SELECT *
FROM object_customers oc
WHERE oc.address.state = 'MA';
ID FIRST_NAME LAST_NAME DOB PHONE
---------- ---------- ---------- --------- ------------
ADDRESS(STREET, CITY, STATE, ZIP)
------------------------------------------------------
1 John Brown 01-FEB-55 800-555-1211
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345')
ln the next query, the id, first_name, und last_name uttríbutes ol customer rl ure
expíícítíy íncíuded ín the SELECT stutement, uíong wíth the uttríbutes ol the embedded address
coíumn ob¡ect:
SELECT oc.id, oc.first_name, oc.last_name,
oc.address.street, oc.address.city, oc.address.state, oc.address.zip
FROM object_customers oc
WHERE oc.id = 1;
ID FIRST_NAME LAST_NAME ADDRESS.STREET ADDRESS.CITY AD ADDRE
---------- ---------- ---------- --------------- --------------- -- -----
1 John Brown 2 State Street Beantown MA 12345
390
Crucíe Dutubuse llg SQL
Objcct ldcntificrs and Objcct Rcfcrcnccs
Luch ob¡ect ín un ob¡ect tubíe hus u uníque ob]cc| ídcn|í|ícr (ClD), und you cun retríeve the ClD
lor un ob¡ect usíng the REF() lunctíon. lor exumpíe, the loííowíng query retríeves the ClD lor
customer rl ín the object_customers tubíe:
SELECT REF(oc)
FROM object_customers oc
WHERE oc.id = 1;
REF(OC)
---------------------------------------------------------------------
0000280209D66AB93F991647649D78D08B267EE44858C7B9989D9D40689FB4DA92820
AFFE2010003280000
1he íong stríng ol numbers und íetters ure the ClD, whích ídentílíes the íocutíon ol the ob¡ect
ín the dutubuse. You cun store un ClD ín un ob¡ect relerence und íuter uccess the ob¡ect ít relers
to. An ob¡ect relerence, whích ís símííur to u poínter ín C++, poínts to un ob¡ect stored ín un
ob¡ect tubíe usíng the ClD. You muy use ob¡ect relerences to modeí reíutíonshíps between ob¡ect
tubíes, und, us you'íí see íuter, you cun use ob¡ect relerences ín lL/SQL to uccess ob¡ects.
You use the REF type to delíne un ob¡ect relerence, the loííowíng stutement creutes u tubíe
numed purchases thut contuíns two ob¡ect relerence coíumns numed customer_ref und
product_ref:
CREATE TABLE purchases (
id INTEGER PRIMARY KEY,
customer_ref REF t_person SCOPE IS object_customers,
product_ref REF t_product SCOPE IS object_products
);
1he SCOPE IS cíuuse restrícts un ob¡ect relerence to poínt to ob¡ects ín u specílíc tubíe. lor
exumpíe, the customer_ref coíumn ís restrícted to poínt to ob¡ects ín the object_customers
tubíe oníy, símííuríy, the product_ref coíumn ís restrícted to poínt to ob¡ects ín the object_
products tubíe oníy.
As l mentíoned eurííer, euch ob¡ect ín un ob¡ect tubíe hus u uníque ob¡ect ídentílíer (ClD) thut
you cun store ín un ob¡ect relerence, you cun retríeve un ClD usíng the REF() lunctíon und store
ít ín un ob¡ect relerence. lor exumpíe, the loííowíng INSERT stutement udds u row to the purchases
tubíe, notíce thut the REF() lunctíon ís used ín the queríes to get the ob¡ect ídentílíers lor
customer rl und product rl lrom the object_customers und object_products tubíes:
INSERT INTO purchases (
id,
customer_ref,
product_ref
) VALUES (
1,
(SELECT REF(oc) FROM object_customers oc WHERE oc.id = 1),
(SELECT REF(op) FROM object_products op WHERE op.id = 1)
);
1hís exumpíe records thut customer rl purchused product rl.
Chupter l2: Dutubuse Cb¡ects

1he loííowíng query seíects the row lrom the purchases tubíe, notíce thut the customer_
ref und product_ref coíumns contuín relerences to the ob¡ects ín the object_customers
und object_products tubíes:
SELECT *
FROM purchases;
ID
----------
CUSTOMER_REF
---------------------------------------------------------------------
PRODUCT_REF
---------------------------------------------------------------------
1
0000220208D66AB93F991647649D78D08B267EE44858C7B9989D9D40689FB4DA92820
AFFE2
0000220208662E2AB4256711D6A1B50010A4E7AE8A662E2AB2256711D6A1B50010A4E
7AE8A
You cun retríeve the uctuuí ob¡ects stored ín un ob¡ect relerence usíng the DEREF() lunctíon,
whích uccepts un ob¡ect relerence us u purumeter und returns the uctuuí ob¡ect. lor exumpíe, the
loííowíng query uses DEREF() to retríeve customer rl und product rl through the customer_
ref und product_ref coíumns ol the purchases tubíe:
SELECT DEREF(customer_ref), DEREF(product_ref)
FROM purchases;
DEREF(CUSTOMER_REF)(ID, FIRST_NAME, LAST_NAME, DOB, PHONE,
ADDRESS(STREET, CITY,
----------------------------------------------------------
DEREF(PRODUCT_REF)(ID, NAME, DESCRIPTION, PRICE, DAYS_VALID)
------------------------------------------------------------
T_PERSON(1, 'John', 'Brown', '01-FEB-55', '800-555-1211',
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345'))
T_PRODUCT(1, 'pasta', '20 oz bag of pasta', 3.95, 10)
1he next query retríeves the customer's first_name und address.street uttríbutes, píus
the product's name uttríbute:
SELECT DEREF(customer_ref).first_name,
DEREF(customer_ref).address.street, DEREF(product_ref).name
FROM purchases;
DEREF(CUST DEREF(CUSTOMER_ DEREF(PROD
---------- --------------- ----------
John 2 State Street pasta
1he loííowíng UPDATE stutement modílíes the product_ref coíumn to poínt to product r2:
UPDATE purchases SET product_ref = (
SELECT REF(op) FROM object_products op WHERE op.id = 2
) WHERE id = 1;
1 row updated.
392
Crucíe Dutubuse ll SQL
1he loííowíng query verílíes thís chunge:
SELECT DEREF(customer_ref), DEREF(product_ref)
FROM purchases;
DEREF(CUSTOMER_REF)(ID, FIRST_NAME, LAST_NAME, DOB, PHONE,
ADDRESS(STREET, CITY,
----------------------------------------------------------
DEREF(PRODUCT_REF)(ID, NAME, DESCRIPTION, PRICE, DAYS_VALID)
------------------------------------------------------------
T_PERSON(1, 'John', 'Brown', '01-FEB-55', '800-555-1211',
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345'))
T_PRODUCT(2, 'sardines', '12 oz box of sardines', 2.99, 5)
Cumparing Objcct VaIucs
You cun compure the vuíue ol two ob¡ects ín u WHERE cíuuse ol u query usíng the equuííty
operutor (=). lor exumpíe, the loííowíng query retríeves customer rl lrom the object_
customers tubíe:
SELECT oc.id, oc.first_name, oc.last_name, oc.dob
FROM object_customers oc
WHERE VALUE(oc) =
t_person(1, 'John', 'Brown', '01-FEB-1955', '800-555-1211',
t_address('2 State Street', 'Beantown', 'MA', '12345')
);
ID FIRST_NAME LAST_NAME DOB
---------- ---------- ---------- ---------
1 John Brown 01-FEB-55
1he next query retríeves product rl lrom the object_products tubíe:
SELECT op.id, op.name, op.price, op.days_valid
FROM object_products op
WHERE VALUE(op) = t_product(1, 'pasta', '20 oz bag of pasta', 3.95, 10);
ID NAME PRICE DAYS_VALID
---------- ---------- ---------- ----------
1 pasta 3.95 10
You cun uíso use the <> und IN operutors ín the WHERE cíuuse:
SELECT oc.id, oc.first_name, oc.last_name, oc.dob
FROM object_customers oc
WHERE VALUE(oc) <>
t_person(1, 'John', 'Brown', '01-FEB-1955', '800-555-1211',
t_address('2 State Street', 'Beantown', 'MA', '12345')
);
ID FIRST_NAME LAST_NAME DOB
---------- ---------- ---------- ---------
2 Cynthia Green 05-FEB-68
Chupter l2: Dutubuse Cb¡ects

SELECT op.id, op.name, op.price, op.days_valid
FROM object_products op
WHERE VALUE(op) IN t_product(1, 'pasta', '20 oz bag of pasta', 3.95, 10);
ID NAME PRICE DAYS_VALID
---------- ---------- ---------- ----------
1 pasta 3.95 10
ll you wunt to use un operutor ííke <, >, <=, >=, LIKE, or BETWEEN, you need to províde u
mup lunctíon lor the type. A mup lunctíon must return u síngíe vuíue ol one ol the buíít-ín types
thut the dutubuse cun then use to compure two ob¡ects. 1he vuíue returned by the mup lunctíon
wííí be díllerent lor every ob¡ect type, und you need to lígure out whut the best uttríbute, or
concutenutíon ol uttríbutes, represents un ob¡ect's vuíue. lor exumpíe, wíth the t_product type,
l'd return the price uttríbute, wíth the t_person type, l'd return u concutenutíon ol the last_
name und first_name uttríbutes.
1he loííowíng stutements creute u type numed t_person2 thut contuíns u mup lunctíon
numed get_string(), notíce thut get_string() returns u VARCHAR2 stríng contuíníng u
concutenutíon ol the last_name und first_name uttríbutes:
CREATE TYPE t_person2 AS OBJECT (
id INTEGER,
first_name VARCHAR2(10),
last_name VARCHAR2(10),
dob DATE,
phone VARCHAR2(12),
address t_address,
-- declare the get_string() map function,
-- which returns a VARCHAR2 string
MAP MEMBER FUNCTION get_string RETURN VARCHAR2
);
/
CREATE TYPE BODY t_person2 AS
-- define the get_string() map function
MAP MEMBER FUNCTION get_string RETURN VARCHAR2 IS
BEGIN
-- return a concatenated string containing the
-- last_name and first_name attributes
RETURN last_name || ' ' || first_name;
END get_string;
END;
/
As you'íí see shortíy, the dutubuse wííí uutomutícuííy cuíí get_string() when compuríng
t_person2 ob¡ects.
1he loííowíng stutements creute u tubíe numed object_customers2 und udd rows to ít:
CREATE TABLE object_customers2 OF t_person2;
INSERT INTO object_customers2 VALUES (
394
Crucíe Dutubuse ll SQL
t_person2(1, 'John', 'Brown', '01-FEB-1955', '800-555-1211',
t_address('2 State Street', 'Beantown', 'MA', '12345')
)
);
INSERT INTO object_customers2 VALUES (
t_person2(2, 'Cynthia', 'Green', '05-FEB-1968', '800-555-1212',
t_address('3 Free Street', 'Middle Town', 'CA', '12345')
)
);
1he loííowíng query uses > ín the WHERE cíuuse:
SELECT oc2.id, oc2.first_name, oc2.last_name, oc2.dob
FROM object_customers2 oc2
WHERE VALUE(oc2) >
t_person2(1, 'John', 'Brown', '01-FEB-1955', '800-555-1211',
t_address('2 State Street', 'Beantown', 'MA', '12345')
);
ID FIRST_NAME LAST_NAME DOB
---------- ---------- ---------- ---------
2 Cynthia Green 05-FEB-68
\hen the query ís executed, the dutubuse uutomutícuííy cuíís get_string() to compure
the ob¡ects ín the object_customers2 tubíe to the ob¡ect ulter the > ín the WHERE cíuuse. 1he
get_string() lunctíon returns u concutenutíon ol the last_name und first_name uttríbutes
ol the ob¡ects, und becuuse Green Cynthia ís greuter thun Brown John, she ís returned by
the query.
Using Objccts in Pl/SQl
You cun creute und munípuíute ob¡ects ín lL/SQL. ln thís sectíon, you'íí see the use ol u puckuge
numed product_package, whích ís creuted when you run the object_schema.sql scrípt,
product_package contuíns the loííowíng methods:
A lunctíon numed get_products() thut returns u REF CURSOR thut poínts to the
ob¡ects ín the object_products tubíe
A procedure numed display_product() thut díspíuys the uttríbutes ol u síngíe ob¡ect
ín the object_products tubíe
A procedure numed insert_product() thut udds un ob¡ect to the object_
products tubíe
A procedure numed update_product_price() thut updutes the price uttríbute
ol un ob¡ect ín the object_products tubíe
A lunctíon numed get_product() thut returns u síngíe ob¡ect lrom the object_
products tubíe
A procedure numed update_product() thut updutes uíí the uttríbutes ol un ob¡ect ín
the object_products tubíe
Chupter l2: Dutubuse Cb¡ects
39S
A lunctíon numed get_product_ref() thut returns u relerence to u síngíe ob¡ect lrom
the object_products tubíe
A procedure numed delete_product() thut deíetes u síngíe ob¡ect lrom the object_
products tubíe
1he object_schema.sql scrípt contuíns the loííowíng puckuge specílícutíon:
CREATE PACKAGE product_package AS
TYPE t_ref_cursor IS REF CURSOR;
FUNCTION get_products RETURN t_ref_cursor;
PROCEDURE display_product(
p_id IN object_products.id%TYPE
);
PROCEDURE insert_product(
p_id IN object_products.id%TYPE,
p_name IN object_products.name%TYPE,
p_description IN object_products.description%TYPE,
p_price IN object_products.price%TYPE,
p_days_valid IN object_products.days_valid%TYPE
);
PROCEDURE update_product_price(
p_id IN object_products.id%TYPE,
p_factor IN NUMBER
);
FUNCTION get_product(
p_id IN object_products.id%TYPE
) RETURN t_product;
PROCEDURE update_product(
p_product t_product
);
FUNCTION get_product_ref(
p_id IN object_products.id%TYPE
) RETURN REF t_product;
PROCEDURE delete_product(
p_id IN object_products.id%TYPE
);
END product_package;
/
You'íí see the methods ín the body ol product_package ín the loííowíng sectíons.
Thc gct_pruducts() functiun
1he get_products() lunctíon returns u REF CURSOR thut poínts to the ob¡ects ín the
object_products tubíe, get_products() ís delíned us loííows ín the body ol product_
package:
FUNCTION get_products
RETURN t_ref_cursor IS
-- declare a t_ref_cursor object
v_products_ref_cursor t_ref_cursor;
BEGIN
396
Crucíe Dutubuse ll SQL
-- get the REF CURSOR
OPEN v_products_ref_cursor FOR
SELECT VALUE(op)
FROM object_products op
ORDER BY op.id;
-- return the REF CURSOR
RETURN v_products_ref_cursor;
END get_products;
1he loííowíng query cuíís product_package.get_products() to retríeve the products
lrom object_products:
SELECT product_package.get_products
FROM dual;
GET_PRODUCTS
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
VALUE(OP)(ID, NAME, DESCRIPTION, PRICE, DAYS_VALID)
----------------------------------------------------------
T_PRODUCT(1, 'pasta', '20 oz bag of pasta', 3.95, 10)
T_PRODUCT(2, 'sardines', '12 oz box of sardines', 2.99, 5)
Thc dispIay_pruduct() Pruccdurc
1he display_product() procedure díspíuys the uttríbutes ol u síngíe ob¡ect ín the object_
products tubíe, display_product() ís delíned us loííows ín the body ol product_package:
PROCEDURE display_product(
p_id IN object_products.id%TYPE
) AS
-- declare a t_product object named v_product
v_product t_product;
BEGIN
-- attempt to get the product and store it in v_product
SELECT VALUE(op)
INTO v_product
FROM object_products op
WHERE id = p_id;
-- display the attributes of v_product
DBMS_OUTPUT.PUT_LINE('v_product.id=' ||
v_product.id);
DBMS_OUTPUT.PUT_LINE('v_product.name=' ||
v_product.name);
DBMS_OUTPUT.PUT_LINE('v_product.description=' ||
v_product.description);
DBMS_OUTPUT.PUT_LINE('v_product.price=' ||
Chupter l2: Dutubuse Cb¡ects
397
v_product.price);
DBMS_OUTPUT.PUT_LINE('v_product.days_valid=' ||
v_product.days_valid);
-- call v_product.get_sell_by_date() and display the date
DBMS_OUTPUT.PUT_LINE('Sell by date=' ||
v_product.get_sell_by_date());
END display_product;
1he loííowíng exumpíe cuíís product_package.display_product(1) to retríeve
product rl lrom the object_products tubíe:
SET SERVEROUTPUT ON
CALL product_package.display_product(1);
v_product.id=1
v_product.name=pasta
v_product.description=20 oz bag of pasta
v_product.price=3.95
v_product.days_valid=10
Sell by date=25-JUN-07
Thc inscrt_pruduct() Pruccdurc
1he insert_product() procedure udds un ob¡ect to the object_products tubíe, insert_
product() ís delíned us loííows ín the body ol product_package:
PROCEDURE insert_product(
p_id IN object_products.id%TYPE,
p_name IN object_products.name%TYPE,
p_description IN object_products.description%TYPE,
p_price IN object_products.price%TYPE,
p_days_valid IN object_products.days_valid%TYPE
) AS
-- create a t_product object named v_product
v_product t_product :=
t_product(
p_id, p_name, p_description, p_price, p_days_valid
);
BEGIN
-- add v_product to the object_products table
INSERT INTO object_products VALUES (v_product);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END insert_product;
1he loííowíng exumpíe cuíís product_package.insert_product() to udd u new ob¡ect
to the object_products tubíe:
CALL product_package.insert_product(3, 'salsa',
'15 oz jar of salsa', 1.50, 20);
398
Crucíe Dutubuse ll SQL
Thc updatc_pruduct_pricc() Pruccdurc
1he update_product_price() procedure updutes the príce uttríbute ol un ob¡ect ín the
object_products tubíe, update_product_price() ís delíned us loííows ín the body ol
product_package:
PROCEDURE update_product_price(
p_id IN object_products.id%TYPE,
p_factor IN NUMBER
) AS
-- declare a t_product object named v_product
v_product t_product;
BEGIN
-- attempt to select the product for update and
-- store the product in v_product
SELECT VALUE(op)
INTO v_product
FROM object_products op
WHERE id = p_id
FOR UPDATE;
-- display the current price of v_product
DBMS_OUTPUT.PUT_LINE('v_product.price=' ||
v_product.price);
-- multiply v_product.price by p_factor
v_product.price := v_product.price * p_factor;
DBMS_OUTPUT.PUT_LINE('New v_product.price=' ||
v_product.price);
-- update the product in the object_products table
UPDATE object_products op
SET op = v_product
WHERE id = p_id;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END update_product_price;
1he loííowíng exumpíe cuíís product_package.update_product_price() to updute
the príce ol product r3 ín the object_products tubíe:
CALL product_package.update_product_price(3, 2.4);
v_product.price=1.5
New v_product.price=3.6
Thc gct_pruduct() functiun
1he get_product() lunctíon returns u síngíe ob¡ect lrom the object_products tubíe, get_
product() ís delíned us loííows ín the body ol product_package:
Chupter l2: Dutubuse Cb¡ects
399
FUNCTION get_product(
p_id IN object_products.id%TYPE
)
RETURN t_product IS
-- declare a t_product object named v_product
v_product t_product;
BEGIN
-- get the product and store it in v_product
SELECT VALUE(op)
INTO v_product
FROM object_products op
WHERE op.id = p_id;
-- return v_product
RETURN v_product;
END get_product;
1he loííowíng query cuíís product_package.get_product() to get product r3 lrom the
object_products tubíe:
SELECT product_package.get_product(3)
FROM dual;
PRODUCT_PACKAGE.GET_PRODUCT(3)(ID, NAME, DESCRIPTION
----------------------------------------------------
T_PRODUCT(3, 'salsa', '15 oz jar of salsa', 3.6, 20)
Thc updatc_pruduct() Pruccdurc
1he update_product() procedure updutes uíí the uttríbutes ol un ob¡ect ín the object_
products tubíe, update_product() ís delíned us loííows ín the body ol product_package:
PROCEDURE update_product(
p_product IN t_product
) AS
BEGIN
-- update the product in the object_products table
UPDATE object_products op
SET op = p_product
WHERE id = p_product.id;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END update_product;
1he loííowíng exumpíe cuíís product_package.update_product() to updute product
r3 ín the object_products tubíe:
CALL product_package.update_product(t_product(3, 'salsa',
'25 oz jar of salsa', 2.70, 15));
400
Crucíe Dutubuse ll SQL
Thc gct_pruduct_rcf() functiun
1he get_product_ref() lunctíon returns u relerence to u síngíe ob¡ect lrom the object_
products tubíe, get_product_ref() ís delíned us loííows ín the body ol product_package:
FUNCTION get_product_ref(
p_id IN object_products.id%TYPE
)
RETURN REF t_product IS
-- declare a reference to a t_product
v_product_ref REF t_product;
BEGIN
-- get the REF for the product and
-- store it in v_product_ref
SELECT REF(op)
INTO v_product_ref
FROM object_products op
WHERE op.id = p_id;
-- return v_product_ref
RETURN v_product_ref;
END get_product_ref;
1he loííowíng query cuíís product_package.get_product_ref() to get the relerence
to product r3 lrom the object_products tubíe:
SELECT product_package.get_product_ref(3)
FROM dual;
PRODUCT_PACKAGE.GET_PRODUCT_REF(3)
------------------------------------------------------------------------------
000028020956DBE8BEFDEF4D5BA8C806A7B31B49DF916CDB2CAC1B46E9808BA181F9F2760F0100
033D0002
1he next exumpíe cuíís product_package.get_product_ref() uguín, thís tíme usíng
DEREF() to get to the uctuuí product:
SELECT DEREF(product_package.get_product_ref(3))
FROM dual;
DEREF(PRODUCT_PACKAGE.GET_PRODUCT_REF(3))(ID, NAME,
----------------------------------------------------
T_PRODUCT(3, 'salsa', '25 oz jar of salsa', 2.7, 15)
Thc dcIctc_pruduct() Pruccdurc
1he delete_product() procedure deíetes u síngíe ob¡ect lrom the object_products tubíe,
delete_product() ís delíned us loííows ín the body ol product_package:
PROCEDURE delete_product(
p_id IN object_products.id%TYPE
) AS
BEGIN
Chupter l2: Dutubuse Cb¡ects
401
-- delete the product
DELETE FROM object_products op
WHERE op.id = p_id;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END delete_product;
1he loííowíng exumpíe cuíís product_package.delete_product() to deíete product
r3 lrom the object_products tubíe:
CALL product_package.delete_product(3);
Now thut you've seen uíí the methods ín product_package, ít's tíme lor you to see two
procedures numed product_lifecycle() und product_lifecycle2() thut cuíí the
vuríous methods ín the puckuge. ßoth procedures ure creuted when you run the object_
schema.sql scrípt.
Thc pruduct_IifccycIc() Pruccdurc
1he product_lifecycle() procedure ís delíned us loííows:
CREATE PROCEDURE product_lifecycle AS
-- declare object
v_product t_product;
BEGIN
-- insert a new product
product_package.insert_product(4, 'beef',
'25 lb pack of beef', 32, 10);
-- display the product
product_package.display_product(4);
-- get the new product and store it in v_product
SELECT product_package.get_product(4)
INTO v_product
FROM dual;
-- change some attributes of v_product
v_product.description := '20 lb pack of beef';
v_product.price := 36;
v_product.days_valid := 8;
-- update the product
product_package.update_product(v_product);
-- display the product
product_package.display_product(4);
-- delete the product
product_package.delete_product(4);
END product_lifecycle;
/
402
Crucíe Dutubuse ll SQL
1he loííowíng exumpíe cuíís product_lifecycle():
CALL product_lifecycle();
v_product.id=4
v_product.name=beef
v_product.description=25 lb pack of beef
v_product.price=32
v_product.days_valid=10
Sell by date=27-JUN-07
v_product.id=4
v_product.name=beef
v_product.description=20 lb pack of beef
v_product.price=36
v_product.days_valid=8
Sell by date=25-JUN-07
Thc pruduct_IifccycIc2() Pruccdurc
1he product_lifecycle2() procedure uses un ob¡ect relerence to uccess u product,
product_lifecycle2() ís delíned us loííows:
CREATE PROCEDURE product_lifecycle2 AS
-- declare object
v_product t_product;
-- declare object reference
v_product_ref REF t_product;
BEGIN
-- insert a new product
product_package.insert_product(4, 'beef',
'25 lb pack of beef', 32, 10);
-- display the product
product_package.display_product(4);
-- get the new product reference and store it in v_product_ref
SELECT product_package.get_product_ref(4)
INTO v_product_ref
FROM dual;
-- dereference v_product_ref using the following query
SELECT DEREF(v_product_ref)
INTO v_product
FROM dual;
-- change some attributes of v_product
v_product.description := '20 lb pack of beef';
v_product.price := 36;
v_product.days_valid := 8;
-- update the product
product_package.update_product(v_product);
Chupter l2: Dutubuse Cb¡ects
403
-- display the product
product_package.display_product(4);
-- delete the product
product_package.delete_product(4);
END product_lifecycle2;
/
Cne poínt to note ín thís procedure ís thut, ín order to derelerence v_product_ref, you
huve to use the loííowíng query:
SELECT DEREF(v_product_ref)
INTO v_product
FROM dual;
1he reuson you huve to use thís query ís thut you cunnot use DEREF() dírectíy ín lL/SQL
code. lor exumpíe, the loííowíng stutement won't compííe ín lL/SQL:
v_product := DEREF(v_product_ref);
1he loííowíng exumpíe cuíís product_lifecycle2():
CALL product_lifecycle2();
v_product.id=4
v_product.name=beef
v_product.description=25 lb pack of beef
v_product.price=32
v_product.days_valid=10
Sell by date=27-JUN-07
v_product.id=4
v_product.name=beef
v_product.description=20 lb pack of beef
v_product.price=36
v_product.days_valid=8
Sell by date=25-JUN-07
Typc lnhcritancc
Crucíe Dutubuse 9 íntroduced ob¡ect type , whích uííows you to delíne híerurchíes ol
ob¡ect types. lor exumpíe, you míght wunt to delíne u busíness person ob¡ect type und huve thut
type ínherít the exístíng uttríbutes lrom t_person. 1he busíness person type couíd extend t_
person wíth uttríbutes to store the person's ¡ob títíe und the nume ol the compuny they work lor.
lor t_person to be ínheríted lrom, the t_person delínítíon must íncíude the NOT FINAL cíuuse:
CREATE TYPE t_person AS OBJECT (
id INTEGER,
first_name VARCHAR2(10),
last_name VARCHAR2(10),
dob DATE,
phone VARCHAR2(12),
address t_address,
MEMBER FUNCTION display_details RETURN VARCHAR2
) NOT FINAL;
/

Crucíe Dutubuse llg SQL
1he NOT FINAL cíuuse índícutes thut t_person cun be ínheríted lrom when delíníng
unother type. (1he deluuít when delíníng types ís FINAL, meuníng thut the ob¡ect type cunnot
be ínheríted lrom.)
1he loííowíng stutement creutes the body lor t_person, notíce thut the display_details()
lunctíon returns u VARCHAR2 contuíníng the id und name ol the person:
CREATE TYPE BODY t_person AS
MEMBER FUNCTION display_details RETURN VARCHAR2 IS
BEGIN
RETURN 'id=' || id || ', name=' || first_name || ' ' || last_name;
END;
END;
/

í'vc provídcd an SÇí*ííu· ·críp| namcd object_schema2.sql,
vhích crca|c· aíí |hc í|cm· ·hovn ín |hí· and |hc |oííovíng ·cc|íon·.
You can run |hc ·críp| í| ,ou arc u·íng Cracíc Da|aba·c 9í or abovc.
A||cr |hc ·críp| compíc|c·, ,ou vííí bc íoggcd ín a· object_user2.
1o huve u new type ínherít uttríbutes und methods lrom un exístíng type, you use the
UNDER keyword when delíníng your new type. Cur busíness person type, whích l'íí nume t_
business_person, uses the UNDER keyword to ínherít the uttríbutes lrom t_person:
CREATE TYPE t_business_person UNDER t_person (
title VARCHAR2(20),
company VARCHAR2(20)
);
/
ln thís exumpíe, t_person ís known us the ·upcr|,pc, und t_business_person ís known
us the ·ub|,pc. You cun then use t_business_person when delíníng coíumn ob¡ects or ob¡ect
tubíes. lor exumpíe, the loííowíng stutement creutes un ob¡ect tubíe numed object_business_
customers:
CREATE TABLE object_business_customers OF t_business_person;
1he loííowíng INSERT stutement udds un ob¡ect to object_business_customers,
notíce thut the two uddítíonuí title und company uttríbutes ure suppííed ut the end ol the
t_business_person constructor:
INSERT INTO object_business_customers VALUES (
t_business_person(1, 'John', 'Brown', '01-FEB-1955', '800-555-1211',
t_address('2 State Street', 'Beantown', 'MA', '12345'),
'Manager', 'XYZ Corp'
)
);
1he loííowíng query retríeves thís ob¡ect:
SELECT *
FROM object_business_customers
WHERE id = 1;
Chupter l2: Dutubuse Cb¡ects
40S
ID FIRST_NAME LAST_NAME DOB PHONE
---------- ---------- ---------- --------- ------------
ADDRESS(STREET, CITY, STATE, ZIP)
------------------------------------------------------
TITLE COMPANY
-------------------- --------------------
1 John Brown 01-FEB-55 800-555-1211
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345')
Manager XYZ Corp
1he loííowíng query cuíís the display_details() lunctíon lor thís ob¡ect:
SELECT o.display_details()
FROM object_business_customers o
WHERE id = 1;
O.DISPLAY_DETAILS()
---------------------
id=1, name=John Brown
\hen you cuíí u method, the dutubuse seurches lor thut method ín the subtype lírst, íl the
method ísn't lound, the supertype ís seurched. ll you huve u híerurchy ol types, the dutubuse wííí
seurch lor the method up the híerurchy, íl the method cunnot be lound, the dutubuse wííí report
un error.
Using a Subtypc Objcct in PIacc
uf a Supcrtypc Objcct
ln thís sectíon you'íí see how you cun use u subtype ob¡ect ín píuce ol u supertype ob¡ect, doíng
thís gíves you greut líexíbíííty when storíng und munípuíutíng reíuted types. ln the exumpíes, you'íí
see how you use u t_business_person ob¡ect (u subtype ob¡ect) ín píuce ol u t_person
ob¡ect (u supertype ob¡ect).
SQl fxampIcs
1he loííowíng stutement creutes u tubíe numed object_customers ol type t_person:
CREATE TABLE object_customers OF t_person;
1he loííowíng INSERT stutement udds u t_person ob¡ect to thís tubíe (the nume ís }uson
ßond):
INSERT INTO object_customers VALUES (
t_person(1, 'Jason', 'Bond', '03-APR-1965', '800-555-1212',
t_address('21 New Street', 'Anytown', 'CA', '12345')
)
);
1here's nothíng unusuuí ubout the prevíous stutement: 1he INSERT símpíy udds u t_person
ob¡ect to the object_customers tubíe. Now, becuuse the object_customers tubíe stores
ob¡ects ol type t_person, und t_person ís u supertype ol t_business_person, you cun
406
Crucíe Dutubuse ll SQL
store u t_business_person ob¡ect ín object_customers, the loííowíng INSERT shows
thís, uddíng u customer numed Steve Edwards:
INSERT INTO object_customers VALUES (
t_business_person(2, 'Steve', 'Edwards', '03-MAR-1955', '800-555-1212',
t_address('1 Market Street', 'Anytown', 'VA', '12345'),
'Manager', 'XYZ Corp'
)
);
1he object_customers tubíe now contuíns two ob¡ects: the t_person ob¡ect udded
eurííer (}uson ßond) und the new t_business_person ob¡ect (Steve Ldwurds). 1he loííowíng
query retríeves these two ob¡ects, notíce thut the title und company uttríbutes lor Steve
Ldwurds ure míssíng lrom the output:
SELECT *
FROM object_customers o;
ID FIRST_NAME LAST_NAME DOB PHONE
---------- ---------- ---------- --------- ------------
ADDRESS(STREET, CITY, STATE, ZIP)
------------------------------------------------------
1 Jason Bond 03-APR-65 800-555-1212
T_ADDRESS('21 New Street', 'Anytown', 'CA', '12345')
2 Steve Edwards 03-MAR-55 800-555-1212
T_ADDRESS('1 Market Street', 'Anytown', 'VA', '12345')
You cun get the luíí set ol uttríbutes lor Steve Edwards by usíng VALUE() ín the query, us
shown ín the loííowíng exumpíe, notíce the díllerent types ol the ob¡ects lor Jason Bond (u t_
person ob¡ect) und Steve Edwards (u t_business_person ob¡ect) und thut the title und
company uttríbutes lor Steve Edwards now uppeur ín the output:
SELECT VALUE(o)
FROM object_customers o;
VALUE(O)(ID, FIRST_NAME, LAST_NAME, DOB, PHONE,
ADDRESS(STREET, CITY, STATE, ZIP
---------------------------------------------------------------------
T_PERSON(1, 'Jason', 'Bond', '03-APR-65', '800-555-1212',
T_ADDRESS('21 New Street', 'Anytown', 'CA', '12345'))
T_BUSINESS_PERSON(2, 'Steve', 'Edwards', '03-MAR-55', '800-555-1212',
T_ADDRESS('1 Market Street', 'Anytown', 'VA', '12345'),
'Manager', 'XYZ Corp')
Pl/SQl fxampIcs
You cun uíso munípuíute subtype und supertype ob¡ects ín lL/SQL. lor exumpíe, the loííowíng
procedure numed subtypes_and_supertypes() munípuíutes t_business_person und
t_person ob¡ects:
CREATE PROCEDURE subtypes_and_supertypes AS
-- create objects
Chupter l2: Dutubuse Cb¡ects
407
v_business_person t_business_person :=
t_business_person(
1, 'John', 'Brown',
'01-FEB-1955', '800-555-1211',
t_address('2 State Street', 'Beantown', 'MA', '12345'),
'Manager', 'XYZ Corp'
);
v_person t_person :=
t_person(1, 'John', 'Brown', '01-FEB-1955', '800-555-1211',
t_address('2 State Street', 'Beantown', 'MA', '12345'));
v_business_person2 t_business_person;
v_person2 t_person;
BEGIN
-- assign v_business_person to v_person2
v_person2 := v_business_person;
DBMS_OUTPUT.PUT_LINE('v_person2.id = ' || v_person2.id);
DBMS_OUTPUT.PUT_LINE('v_person2.first_name = ' ||
v_person2.first_name);
DBMS_OUTPUT.PUT_LINE('v_person2.last_name = ' ||
v_person2.last_name);
-- the following lines will not compile because v_person2
-- is of type t_person, and t_person does not know about the
-- additional title and company attributes
-- DBMS_OUTPUT.PUT_LINE('v_person2.title = ' ||
-- v_person2.title);
-- DBMS_OUTPUT.PUT_LINE('v_person2.company = ' ||
-- v_person2.company);
-- the following line will not compile because you cannot
-- directly assign a t_person object to a t_business_person
-- object
-- v_business_person2 := v_person;
END subtypes_and_supertypes;
/
1he loííowíng exumpíe shows the resuít ol cuíííng subtypes_and_supertypes():
SET SERVEROUTPUT ON
CALL subtypes_and_supertypes();
v_person2.id = 1
v_person2.first_name = John
v_person2.last_name = Brown
NOT SUBSTlTUTABlf Objccts
ll you wunt to prevent the use ol u subtype ob¡ect ín píuce ol u supertype ob¡ect, you cun murk un
ob¡ect tubíe or ob¡ect coíumn us ºnot substítutubíe¨, lor exumpíe, the loííowíng stutement creutes
u tubíe numed object_customers2:
CREATE TABLE object_customers_not_subs OF t_person
NOT SUBSTITUTABLE AT ALL LEVELS;
408
Crucíe Dutubuse ll SQL
1he NOT SUBSTITUTABLE AT ALL LEVELS cíuuse índícutes thut no ob¡ects ol u type
other thun t_person cun be ínserted ínto the tubíe. ll un uttempt ís mude to udd un ob¡ect ol
type t_business_person to thís tubíe, un error ís returned:
SQL> INSERT INTO object_customers_not_subs VALUES (
2 t_business_person(1, 'Steve', 'Edwards', '03-MAR-1955', '800-555-1212',
3 t_address('1 Market Street', 'Anytown', 'VA', '12345'),
4 'Manager', 'XYZ Corp'
5 )
6 );
t_business_person(1, 'Steve', 'Edwards', '03-MAR-1955', '800-555-1212',
*
ERROR at line 2:
ORA-00932: inconsistent datatypes: expected OBJECT_USER2.T_PERSON got
OBJECT_USER2.T_BUSINESS_PERSON
You cun uíso murk un ob¡ect coíumn us not substítutubíe, lor exumpíe, the loííowíng
stutement creutes u tubíe wíth un ob¡ect coíumn numed product thut cun store oníy ob¡ects ol
type t_product:
CREATE TABLE products (
product t_product,
quantity_in_stock INTEGER
)
COLUMN product NOT SUBSTITUTABLE AT ALL LEVELS;
Any uttempts to udd un ob¡ect not ol type t_product to the product coíumn wííí resuít ín
un error.
Othcr UscfuI Objcct functiuns
ln the eurííer sectíons ol thís chupter you suw the use ol the REF(), DEREF(), und VALUE()
lunctíons. ln thís sectíon, you'íí see the loííowíng uddítíonuí lunctíons thut muy be used wíth ob¡ects:
IS OF() checks íl un ob¡ect ís ol u purtícuíur type or subtype.
TREAT() does u run-tíme check to see íl un ob¡ect's type muy be treuted us u supertype.
SYS_TYPEID() returns the lD ol un ob¡ect's type.
lS Of()
You use IS OF() to check whether un ob¡ect ís ol u purtícuíur type or subtype. lor exumpíe,
the loííowíng query uses IS OF() to check whether the ob¡ects ín the object_business_
customers tubíe ure ol type t_business_personbecuuse they ure, u row ís returned by
the query:
SELECT VALUE(o)
FROM object_business_customers o
WHERE VALUE(o) IS OF (t_business_person);
VALUE(O)(ID, FIRST_NAME, LAST_NAME, DOB, PHONE,
ADDRESS(STREET, CITY, STATE, ZIP
------------------------------------------------------------------
Chupter l2: Dutubuse Cb¡ects

T_BUSINESS_PERSON(1, 'John', 'Brown', '01-FEB-55', '800-555-1211',
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345'),
'Manager', 'XYZ Corp')
You cun uíso use IS OF() to check whether un ob¡ect ís ol u subtype ol the specílíed
type. lor exumpíe, the ob¡ects ín the object_business_customers tubíe ure ol type t_
business_person, whích ís u subtype ol t_person, therelore, the loííowíng query returns
the sume resuít us thut shown ín the prevíous exumpíe:
SELECT VALUE(o)
FROM object_business_customers o
WHERE VALUE(o) IS OF (t_person);
VALUE(O)(ID, FIRST_NAME, LAST_NAME, DOB, PHONE,
ADDRESS(STREET, CITY, STATE, ZIP
------------------------------------------------------------------
T_BUSINESS_PERSON(1, 'John', 'Brown', '01-FEB-55', '800-555-1211',
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345'),
'Manager', 'XYZ Corp')
You cun íncíude more thun one type ín IS OF(), lor exumpíe:
SELECT VALUE(o)
FROM object_business_customers o
WHERE VALUE(o) IS OF (t_business_person, t_person);
VALUE(O)(ID, FIRST_NAME, LAST_NAME, DOB, PHONE,
ADDRESS(STREET, CITY, STATE, ZIP
------------------------------------------------------------------
T_BUSINESS_PERSON(1, 'John', 'Brown', '01-FEB-55', '800-555-1211',
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345'),
'Manager', 'XYZ Corp')
ln the eurííer sectíon entítíed ºLsíng u Subtype Cb¡ect ín líuce ol u Supertype Cb¡ect,¨ you
suw the uddítíon ol u t_person ob¡ect (Jason Bond) und t_business_person ob¡ect
(Steve Edwards) to the object_customers tubíe. As u remínder, the loííowíng query shows
these ob¡ects:
SELECT VALUE(o)
FROM object_customers o;
VALUE(O)(ID, FIRST_NAME, LAST_NAME, DOB, PHONE,
ADDRESS(STREET, CITY, STATE, ZIP
---------------------------------------------------------------------
T_PERSON(1, 'Jason', 'Bond', '03-APR-65', '800-555-1212',
T_ADDRESS('21 New Street', 'Anytown', 'CA', '12345'))
T_BUSINESS_PERSON(2, 'Steve', 'Edwards', '03-MAR-55', '800-555-1212',
T_ADDRESS('1 Market Street', 'Anytown', 'VA', '12345'),
'Manager', 'XYZ Corp')
ßecuuse t_business_person type ís u subtype ol t_person, IS OF (t_person)
returns true when u t_business_person ob¡ect or u t_person ob¡ect ís checked, thís ís

Crucíe Dutubuse ll SQL
íííustruted ín the loííowíng query thut retríeves both Jason Bond und Steve Edwards usíng
IS OF (t_person):
SELECT VALUE(o)
FROM object_customers o
WHERE VALUE(o) IS OF (t_person);
VALUE(O)(ID, FIRST_NAME, LAST_NAME, DOB, PHONE,
ADDRESS(STREET, CITY, STATE, ZIP
---------------------------------------------------------------------
T_PERSON(1, 'Jason', 'Bond', '03-APR-65', '800-555-1212',
T_ADDRESS('21 New Street', 'Anytown', 'CA', '12345'))
T_BUSINESS_PERSON(2, 'Steve', 'Edwards', '03-MAR-55', '800-555-1212',
T_ADDRESS('1 Market Street', 'Anytown', 'VA', '12345'),
'Manager', 'XYZ Corp')
You cun uíso use the ONLY keyword ín con¡unctíon wíth IS OF () to check lor ob¡ects ol
u specílíc type oníy: IS OF () returns false lor ob¡ects ol unother type ín the híerurchy. lor
exumpíe, IS OF (ONLY t_person) returns true lor ob¡ects ol type t_person oníy und
returns false lor ob¡ects ol type t_business_person. ln thís wuy, you cun use IS OF
(ONLY t_person) to restríct the ob¡ect returned by u query uguínst the object_customers
tubíe to Jason Bond, us shown ín the loííowíng exumpíe:
SELECT VALUE(o)
FROM object_customers o
WHERE VALUE(o) IS OF (ONLY t_person);
VALUE(O)(ID, FIRST_NAME, LAST_NAME, DOB, PHONE,
ADDRESS(STREET, CITY, STATE, ZIP
---------------------------------------------------------
T_PERSON(1, 'Jason', 'Bond', '03-APR-65', '800-555-1212',
T_ADDRESS('21 New Street', 'Anytown', 'CA', '12345'))
Símííuríy, IS OF(ONLY t_business_person) returns true lor ob¡ects ol type t_
business_person oníy, und returns false lor ob¡ects ol type t_person. lor exumpíe,
the loííowíng query retríeves the t_business_person ob¡ect oníy und therelore Steve
Edwards ís returned:
SELECT VALUE(o)
FROM object_customers o
WHERE VALUE(o) IS OF (ONLY t_business_person);
VALUE(O)(ID, FIRST_NAME, LAST_NAME, DOB, PHONE,
ADDRESS(STREET, CITY, STATE, ZIP
---------------------------------------------------------------------
T_BUSINESS_PERSON(2, 'Steve', 'Edwards', '03-MAR-55', '800-555-1212',
T_ADDRESS('1 Market Street', 'Anytown', 'VA', '12345'),
'Manager', 'XYZ Corp')
You cun íncíude muítípíe types ulter ONLY. lor exumpíe, IS OF (ONLY t_person, t_
business_person) returns true lor t_person und t_business_person ob¡ects oníy, the
loííowíng query shows thís by returníng, us expected, both Jason Bond und Steve Edwards:
Chupter l2: Dutubuse Cb¡ects

SELECT VALUE(o)
FROM object_customers o
WHERE VALUE(o) IS OF (ONLY t_person, t_business_person);
VALUE(O)(ID, FIRST_NAME, LAST_NAME, DOB, PHONE,
ADDRESS(STREET, CITY, STATE, ZIP
---------------------------------------------------------------------
T_PERSON(1, 'Jason', 'Bond', '03-APR-65', '800-555-1212',
T_ADDRESS('21 New Street', 'Anytown', 'CA', '12345'))
T_BUSINESS_PERSON(2, 'Steve', 'Edwards', '03-MAR-55', '800-555-1212',
T_ADDRESS('1 Market Street', 'Anytown', 'VA', '12345'),
'Manager', 'XYZ Corp')
You cun uíso use IS OF() ín lL/SQL. lor exumpíe, the loííowíng procedure numed check_
types() creutes t_business_person und t_person objects, und ít uses IS OF() to
check theír types:
CREATE PROCEDURE check_types AS
-- create objects
v_business_person t_business_person :=
t_business_person(
1, 'John', 'Brown',
'01-FEB-1955', '800-555-1211',
t_address('2 State Street', 'Beantown', 'MA', '12345'),
'Manager', 'XYZ Corp'
);
v_person t_person :=
t_person(1, 'John', 'Brown', '01-FEB-1955', '800-555-1211',
t_address('2 State Street', 'Beantown', 'MA', '12345'));
BEGIN
-- check the types of the objects
IF v_business_person IS OF (t_business_person) THEN
DBMS_OUTPUT.PUT_LINE('v_business_person is of type ' ||
't_business_person');
END IF;
IF v_person IS OF (t_person) THEN
DBMS_OUTPUT.PUT_LINE('v_person is of type t_person');
END IF;
IF v_business_person IS OF (t_person) THEN
DBMS_OUTPUT.PUT_LINE('v_business_person is of type t_person');
END IF;
IF v_business_person IS OF (t_business_person, t_person) THEN
DBMS_OUTPUT.PUT_LINE('v_business_person is of ' ||
'type t_business_person or t_person');
END IF;
IF v_business_person IS OF (ONLY t_business_person) THEN
DBMS_OUTPUT.PUT_LINE('v_business_person is of only ' ||
'type t_business_person');
END IF;
IF v_business_person IS OF (ONLY t_person) THEN
DBMS_OUTPUT.PUT_LINE('v_business_person is of only ' ||
412
Crucíe Dutubuse ll SQL
'type t_person');
ELSE
DBMS_OUTPUT.PUT_LINE('v_business_person is not of only ' ||
'type t_person');
END IF;
END check_types;
/
1he loííowíng exumpíe shows the resuít ol cuíííng check_types():
SET SERVEROUTPUT ON
CALL check_types();
v_business_person is of type t_business_person
v_person is of type t_person
v_business_person is of type t_person
v_business_person is of type t_business_person or t_person
v_business_person is of only type t_business_person
v_business_person is not of only type t_person
TRfAT()
You use TREAT() to do u run-tíme check to see whether un ob¡ect ol u subtype muy be treuted us
un ob¡ect ol u supertype, íl thís ís so, TREAT() returns un ob¡ect, und íl not so, TREAT() returns
nuíí. lor exumpíe, becuuse t_business_person ís u subtype ol t_person, u t_business_
person ob¡ect cun be treuted us u t_person ob¡ect, you suw thís eurííer ín the sectíon entítíed
ºLsíng u Subtype Cb¡ect ín líuce ol u Supertype Cb¡ect,¨ where u t_business_person ob¡ect
(Steve Edwards) wus ínserted ínto the object_customers tubíe, whích normuííy hoíds t_
person ob¡ects. 1he loííowíng query uses TREAT() to check thut Steve Edwards cun be
treuted us u t_person ob¡ect:
SELECT NVL2(TREAT(VALUE(o) AS t_person), 'yes', 'no')
FROM object_customers o
WHERE first_name = 'Steve' AND last_name = 'Edwards';
NVL
---
yes
NVL2() returns yes becuuse TREAT(VALUE(o) AS t_person) returns un ob¡ect (thut ís,
not u nuíí vuíue). 1hís meuns thut Steve Edwards cun be treuted us u t_person ob¡ect.
1he next query checks whether Jason Bond (u t_person ob¡ect) cun be treuted us u t_
business_person ob¡ecthe cunnot, und, therelore, TREAT() returns nuíí, und NVL2()
returns no:
SELECT NVL2(TREAT(VALUE(o) AS t_business_person), 'yes', 'no')
FROM object_customers o
WHERE first_name = 'Jason' AND last_name = 'Bond';
NVL
---
no
Chupter l2: Dutubuse Cb¡ects

ßecuuse TREAT() returns nuíí lor the whoíe ob¡ect, uíí the índívíduuí uttríbutes lor the ob¡ect
ure uíso nuíí. lor exumpíe, the loííowíng query uttempts to uccess the first_name uttríbute
through Jason Bondnuíí ís returned (us expected):
SELECT
NVL2(TREAT(VALUE(o) AS t_business_person).first_name, 'not null', 'null')
FROM object_customers o
WHERE first_name = 'Jason' AND last_name = 'Bond';
NVL2
----
null
1he next query uses TREAT() to check whether Jason Bond cun be treuted us u t_person
ob¡ecthe  u t_person ob¡ect und therelore yes ís returned:
SELECT NVL2(TREAT(VALUE(o) AS t_person).first_name, 'yes', 'no')
FROM object_customers o
WHERE first_name = 'Jason' AND last_name = 'Bond';
NVL
---
yes
You cun uíso retríeve un ob¡ect through the use ol TREAT(), lor exumpíe, the loííowíng query
retríeves Steve Edwards:
SELECT TREAT(VALUE(o) AS t_business_person)
FROM object_customers o
WHERE first_name = 'Steve' AND last_name = 'Edwards';
TREAT(VALUE(O)AST_BUSINESS_PERSON)(ID, FIRST_NAME, LAST_NAME, DOB, PHONE,
ADDRESS
-------------------------------------------------------------------------
T_BUSINESS_PERSON(2, 'Steve', 'Edwards', '03-MAR-55', '800-555-1212',
T_ADDRESS('1 Market Street', 'Anytown', 'VA', '12345'),
'Manager', 'XYZ Corp')
ll you try thís query wíth Jason Bond, nuíí ís returned, us expected, therelore, nothíng
uppeurs ín the output ol the loííowíng query:
SELECT TREAT(VALUE(o) AS t_business_person)
FROM object_customers o
WHERE first_name = 'Jason' AND last_name = 'Bond';
TREAT(VALUE(O)AST_BUSINESS_PERSON)(ID, FIRST_NAME, LAST_NAME, DOB, PHONE,
ADDRESS
-------------------------------------------------------------------------
Let's tuke íook ut usíng TREAT() wíth the object_business_customers tubíe, whích
contuíns the t_business_person ob¡ect John Brown:
SELECT VALUE(o)
FROM object_business_customers o;

Crucíe Dutubuse ll SQL
VALUE(O)(ID, FIRST_NAME, LAST_NAME, DOB, PHONE,
ADDRESS(STREET, CITY, STATE, ZIP
------------------------------------------------------------------
T_BUSINESS_PERSON(1, 'John', 'Brown', '01-FEB-55', '800-555-1211',
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345'),
'Manager', 'XYZ Corp')
1he loííowíng query uses TREAT() to check whether John Brown cun be treuted us u t_
person ob¡ecthe cun, becuuse t_business_person ís u subtype ol t_person, therelore,
yes ís returned by the query:
SELECT NVL2(TREAT(VALUE(o) AS t_person), 'yes', 'no')
FROM object_business_customers o
WHERE first_name = 'John' AND last_name = 'Brown';
NVL
---
yes
1he loííowíng exumpíe shows the ob¡ect returned by TREAT() when queryíng the object_
business_customers tubíe, notíce thut you stííí get the title und company uttríbutes lor
John Brown:
SELECT TREAT(VALUE(o) AS t_person)
FROM object_business_customers o;
TREAT(VALUE(O)AST_PERSON)(ID, FIRST_NAME, LAST_NAME, DOB, PHONE,
ADDRESS(STREET,
------------------------------------------------------------------
T_BUSINESS_PERSON(1, 'John', 'Brown', '01-FEB-55', '800-555-1211',
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345'),
'Manager', 'XYZ Corp')
You cun uíso use TREAT() ín lL/SQL. lor exumpíe, the loííowíng procedure numed treat_
example() íííustrutes the use ol TREAT() (you shouíd study the comments ín the code to
understund how TREAT() works ín lL/SQL):
CREATE PROCEDURE treat_example AS
-- create objects
v_business_person t_business_person :=
t_business_person(
1, 'John', 'Brown',
'01-FEB-1955', '800-555-1211',
t_address('2 State Street', 'Beantown', 'MA', '12345'),
'Manager', 'XYZ Corp'
);
v_person t_person :=
t_person(1, 'John', 'Brown', '01-FEB-1955', '800-555-1211',
t_address('2 State Street', 'Beantown', 'MA', '12345'));
v_business_person2 t_business_person;
v_person2 t_person;
Chupter l2: Dutubuse Cb¡ects

BEGIN
-- assign v_business_person to v_person2
v_person2 := v_business_person;
DBMS_OUTPUT.PUT_LINE('v_person2.id = ' || v_person2.id);
DBMS_OUTPUT.PUT_LINE('v_person2.first_name = ' ||
v_person2.first_name);
DBMS_OUTPUT.PUT_LINE('v_person2.last_name = ' ||
v_person2.last_name);
-- the following lines will not compile because v_person2
-- is of type t_person, and t_person does not know about the
-- additional title and company attributes
-- DBMS_OUTPUT.PUT_LINE('v_person2.title = ' ||
-- v_person2.title);
-- DBMS_OUTPUT.PUT_LINE('v_person2.company = ' ||
-- v_person2.company);
-- use TREAT when assigning v_business_person to v_person2
DBMS_OUTPUT.PUT_LINE('Using TREAT');
v_person2 := TREAT(v_business_person AS t_person);
DBMS_OUTPUT.PUT_LINE('v_person2.id = ' || v_person2.id);
DBMS_OUTPUT.PUT_LINE('v_person2.first_name = ' ||
v_person2.first_name);
DBMS_OUTPUT.PUT_LINE('v_person2.last_name = ' ||
v_person2.last_name);
-- the following lines will still not compile because v_person2
-- is of type t_person, and t_person does not know about the
-- additional title and company attributes
-- DBMS_OUTPUT.PUT_LINE('v_person2.title = ' ||
-- v_person2.title);
-- DBMS_OUTPUT.PUT_LINE('v_person2.company = ' ||
-- v_person2.company);
-- the following lines do compile because TREAT is used
DBMS_OUTPUT.PUT_LINE('v_person2.title = ' ||
TREAT(v_person2 AS t_business_person).title);
DBMS_OUTPUT.PUT_LINE('v_person2.company = ' ||
TREAT(v_person2 AS t_business_person).company);
-- the following line will not compile because you cannot
-- directly assign a t_person object to a t_business_person
-- object
-- v_business_person2 := v_person;
-- the following line throws a runtime error because you cannot
-- assign a supertype object (v_person) to a subtype object
-- (v_business_person2)
-- v_business_person2 := TREAT(v_person AS t_business_person);
END treat_example;
/
416
Crucíe Dutubuse ll SQL
1he loííowíng exumpíe shows the resuít ol cuíííng treat_example():
SET SERVEROUTPUT ON
CALL treat_example();
v_person2.id = 1
v_person2.first_name = John
v_person2.last_name = Brown
Using TREAT
v_person2.id = 1
v_person2.first_name = John
v_person2.last_name = Brown
v_person2.title = Manager
v_person2.company = XYZ Corp
SYS_TYPflD()
You use SYS_TYPEID() to get the ID ol un ob¡ect's type. lor exumpíe, the loííowíng query uses
SYS_TYPEID() to get the ID ol the ob¡ect type ín the object_business_customers tubíe:
SELECT first_name, last_name, SYS_TYPEID(VALUE(o))
FROM object_business_customers o;
FIRST_NAME LAST_NAME SY
---------- ---------- --
John Brown 02
You cun get detuíís on the types delíned by the user through the user_types víew. 1he
loííowíng query retríeves the detuíís ol the type wíth u typeid ol '02' (the ID returned by SYS_
TYPEID() eurííer) und the type_name ol T_BUSINESS_PERSON:
SELECT typecode, attributes, methods, supertype_name
FROM user_types
WHERE typeid = '02'
AND type_name = 'T_BUSINESS_PERSON';
TYPECODE ATTRIBUTES METHODS SUPERTYPE_NAME
-------- ---------- ---------- --------------
OBJECT 8 1 T_PERSON
lrom the output ol thís query you cun see thut the supertype ol t_business_person ís
t_person. Aíso, t_business_person hus eíght uttríbutes und one method.
NOT lNSTANTlABlf Objcct Typcs
You cun murk un ob¡ect type us NOT INSTANTIABLE, whích prevents ob¡ects ol thut type lrom
beíng creuted. You míght wunt to murk un ob¡ect type us NOT INSTANTIABLE when you use the
type us un ubstruct supertype oníy und never creute uny ob¡ects ol thut type. lor exumpíe, you
couíd creute u t_vehicle ubstruct type und use ít us u supertype lor u t_car subtype und u t_
motorcycle subtype, you wouíd then creute uctuuí t_car und t_motorcycle ob¡ects, but
never t_vehicle ob¡ects.
Chupter l2: Dutubuse Cb¡ects

1he loííowíng stutement creutes u type numed t_vehicle, whích ís murked us NOT
INSTANTIABLE:
CREATE TYPE t_vehicle AS OBJECT (
id INTEGER,
make VARCHAR2(15),
model VARCHAR2(15)
) NOT FINAL NOT INSTANTIABLE;
/

Thc t_vehicle |,pc í· aí·o mar|cd a· NOT FINAL, bccau·c a
NOT INSTANTIABLE |,pc canno| bc FINAL. í| í| were FINAL, ,ou
vouídn'| bc abíc |o u·c í| a· a ·upcr|,pc, vhích í· |hc vhoíc poín| o|
crca|íng í| ín |hc |ír·| píacc.
1he next exumpíe creutes u subtype numed t_car under the t_vehicle supertype, notíce
thut t_car hus un uddítíonuí uttríbute numed convertible, whích wííí be used to record
whether the cur hus u convertíbíe rool (Y lor yes, N lor no):
CREATE TYPE t_car UNDER t_vehicle (
convertible CHAR(1)
);
/
1he loííowíng exumpíe creutes u subtype numed t_motorcycle under the t_vehicle
supertype, notíce thut t_motorcycle hus un uddítíonuí uttríbute numed sidecar, whích wííí
be used to record whether the motorcycíe hus u sídecur (Y lor yes, N lor no):
CREATE TYPE t_motorcycle UNDER t_vehicle (
sidecar CHAR(1)
);
/
1he next exumpíe creutes tubíes numed vehicles, cars, und motorcycles, whích ure
ob¡ect tubíes ol the types t_vehicle, t_car, und t_motorcycle¸ respectíveíy:
CREATE TABLE vehicles OF t_vehicle;
CREATE TABLE cars OF t_car;
CREATE TABLE motorcycles OF t_motorcycle;
ßecuuse t_vehicle ís NOT INSTANTIABLE, you cunnot udd un ob¡ect to the vehicles
tubíe. ll you uttempt to do so, the dutubuse returns un error:
SQL> INSERT INTO vehicles VALUES (
2 t_vehicle(1, 'Toyota', 'MR2', '01-FEB-1955')
3 );
t_vehicle(1, 'Toyota', 'MR2', '01-FEB-1955')
*
ERROR at line 2:
ORA-22826: cannot construct an instance of a non instantiable type
418
Crucíe Dutubuse ll SQL
1he loííowíng exumpíes udd ob¡ects to the cars und motorcycles tubíes:
INSERT INTO cars VALUES (
t_car(1, 'Toyota', 'MR2', 'Y')
);
INSERT INTO motorcycles VALUES (
t_motorcycle(1, 'Harley-Davidson', 'V-Rod', 'N')
);
1he loííowíng queríes retríeve the ob¡ects lrom the cars und motorcycles tubíes:
SELECT *
FROM cars;
ID MAKE MODEL C
---------- --------------- --------------- -
1 Toyota MR2 Y
SELECT *
FROM motorcycles;
ID MAKE MODEL S
---------- --------------- --------------- -
1 Harley-Davidson V-Rod N
Uscr-Dcfincd Cunstructurs
As ín other ob¡ect-oríented íunguuges ííke }uvu und Cr, you cun delíne your own constructors
ín lL/SQL to ínítíuííze u new ob¡ect. You cun delíne your own constructor to do such thíngs us
progrummutícuííy settíng the uttríbutes ol u new ob¡ect to deluuít vuíues.
1he loííowíng exumpíe creutes u type numed t_person2 thut decíures two constructor
methods wíth dílleríng numbers ol purumeters:
CREATE TYPE t_person2 AS OBJECT (
id INTEGER,
first_name VARCHAR2(10),
last_name VARCHAR2(10),
dob DATE,
phone VARCHAR2(12),
CONSTRUCTOR FUNCTION t_person2(
p_id INTEGER,
p_first_name VARCHAR2,
p_last_name VARCHAR2
) RETURN SELF AS RESULT,
CONSTRUCTOR FUNCTION t_person2(
p_id INTEGER,
p_first_name VARCHAR2,
p_last_name VARCHAR2,
p_dob DATE
) RETURN SELF AS RESULT
);
/
Chupter l2: Dutubuse Cb¡ects

Notíce the loííowíng ubout the constructor decíurutíons:
1he CONSTRUCTOR FUNCTION keywords ure used to ídentíly the constructors.
1he RETURN SELF AS RESULT keywords índícute the current ob¡ect beíng processed
ís returned by euch constructor, SELF represents the current ob¡ect beíng processed.
\hut thís meuns ís thut the constructor returns the new ob¡ect ít creutes.
1he lírst constructor uccepts three purumeters (p_id, p_first_name, und p_last_
name), und the second constructor uccepts lour purumeters (p_id, p_first_name,
p_last_name, und p_dob).
1he constructor decíurutíons don't contuín the uctuuí code delínítíons lor the constructors, the
delínítíons ure contuíned ín the type body, whích ís creuted by the loííowíng stutement:
CREATE TYPE BODY t_person2 AS
CONSTRUCTOR FUNCTION t_person2(
p_id INTEGER,
p_first_name VARCHAR2,
p_last_name VARCHAR2
) RETURN SELF AS RESULT IS
BEGIN
SELF.id := p_id;
SELF.first_name := p_first_name;
SELF.last_name := p_last_name;
SELF.dob := SYSDATE;
SELF.phone := '555-1212';
RETURN;
END;
CONSTRUCTOR FUNCTION t_person2(
p_id INTEGER,
p_first_name VARCHAR2,
p_last_name VARCHAR2,
p_dob DATE
) RETURN SELF AS RESULT IS
BEGIN
SELF.id := p_id;
SELF.first_name := p_first_name;
SELF.last_name := p_last_name;
SELF.dob := p_dob;
SELF.phone := '555-1213';
RETURN;
END;
END;
/
Notíce the loííowíng:
1he constructors use SELF to relerence the new ob¡ect beíng creuted. lor exumpíe,
SELF.id := p_id sets the id uttríbute ol the new ob¡ect to the vuíue ol the p_id
purumeter pussed ínto the constructor.

Crucíe Dutubuse llg SQL
1he lírst constructor sets the id, first_name, und last_name uttríbutes to the p_id,
p_first_name, und p_last_name purumeter vuíues pussed ínto the constructor, the
dob uttríbute ís set to the current dutetíme returned by SYSDATE(), und the phone
uttríbute ís set to 555-1212.
1he second constructor sets the id, first_name, last_name, und dob uttríbutes to
the p_id, p_first_name, p_last_name, und p_dob purumeter vuíues pussed ínto
the constructor, the remuíníng phone uttríbute ís set to 555-1213.
Aíthough not shown, the dutubuse uutomutícuííy provídes u deluuít constructor thut uccepts
líve purumeters und sets euch uttríbute to the uppropríute purumeter vuíue pussed ínto the
constructor. You'íí see un exumpíe ol thís shortíy.

Thc con·|ruc|or· ·hov an cxampíc o| method overíoudíng, vhcrcb,
mc|hod· o| |hc ·amc namc bu| dí||crcn| paramc|cr· arc dc|íncd ín
|hc ·amc |,pc. A mc|hod ma, bc ovcríoadcd b, provídíng dí||crcn|
numbers o| paramc|cr·, types o| paramc|cr·, or orderíng o| paramc|cr·.
1he loííowíng exumpíe descríbes t_person2, notíce the constructor delínítíons ín the output:
DESCRIBE t_person2
Name Null? Type
----------------------------------------- -------- -------------------
ID NUMBER(38)
FIRST_NAME VARCHAR2(10)
LAST_NAME VARCHAR2(10)
DOB DATE
PHONE VARCHAR2(12)
METHOD
------
FINAL CONSTRUCTOR FUNCTION T_PERSON2 RETURNS SELF AS RESULT
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
P_ID NUMBER IN
P_FIRST_NAME VARCHAR2 IN
P_LAST_NAME VARCHAR2 IN
METHOD
------
FINAL CONSTRUCTOR FUNCTION T_PERSON2 RETURNS SELF AS RESULT
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
P_ID NUMBER IN
P_FIRST_NAME VARCHAR2 IN
P_LAST_NAME VARCHAR2 IN
P_DOB DATE IN
1he loííowíng stutement creutes u tubíe ol type t_person2:
Chupter l2: Dutubuse Cb¡ects

CREATE TABLE object_customers2 OF t_person2;
1he loííowíng INSERT stutement udds un ob¡ect to the tubíe, notíce thut three purumeters ure
pussed to the t_person2 constructor:
INSERT INTO object_customers2 VALUES (
t_person2(1, 'Jeff', 'Jones')
);
ßecuuse three purumeters ure pussed to t_person2, thís INSERT stutement exercíses the lírst
constructor. 1hís constructor sets the id, first_name, und last_name uttríbutes ol the new
ob¡ect to l, Jeff, und Jones, the remuíníng dob und phone uttríbutes ure set to the resuít
returned by SYSDATE() und the ííteruí 555-1212. 1he loííowíng query retríeves the new ob¡ect:
SELECT *
FROM object_customers2
WHERE id = 1;
ID FIRST_NAME LAST_NAME DOB PHONE
---------- ---------- ---------- --------- --------
1 Jeff Jones 17-JUN-07 555-1212
1he next INSERT stutement udds unother ob¡ect to the tubíe, notíce thut lour purumeters ure
pussed to the t_person2 constructor:
INSERT INTO object_customers2 VALUES (
t_person2(2, 'Gregory', 'Smith', '03-APR-1965')
);
ßecuuse lour purumeters ure pussed to t_person2, thís INSERT stutement exercíses the
second constructor. 1hís constructor sets the id, first_name, last_name, und dob uttríbutes
ol the ob¡ect to 2, Gregory, Smith, und 03-APR-1965, respectíveíy, the remuíníng phone
uttríbute ís set to 555-1213. 1he loííowíng query retríeves the new ob¡ect:
SELECT *
FROM object_customers2
WHERE id = 2;
ID FIRST_NAME LAST_NAME DOB PHONE
---------- ---------- ---------- --------- --------
2 Gregory Smith 03-APR-65 555-1213
1he next INSERT stutement udds unother ob¡ect to the tubíe, notíce thut líve purumeters ure
pussed to the t_person2 constructor:
INSERT INTO object_customers2 VALUES (
t_person2(3, 'Jeremy', 'Hill', '05-JUN-1975', '555-1214')
);
ßecuuse líve purumeters ure pussed to t_person2, thís INSERT stutement exercíses the
deluuít constructor. 1hís constructor sets the id, first_name, last_name, dob, und phone
422
Crucíe Dutubuse ll SQL
uttríbutes to 3, Jeremy, Hill, 05-JUN-1975, und 555-1214, respectíveíy. 1he loííowíng
query retríeves the new ob¡ect:
SELECT *
FROM object_customers2
WHERE id = 3;
ID FIRST_NAME LAST_NAME DOB PHONE
---------- ---------- ---------- --------- --------
3 Jeremy Hill 05-JUN-75 555-1214
Ovcrriding Mcthuds
\hen you creute u subtype under u supertype, you cun overríde u method ín the supertype wíth u
method ín the subtype. 1hís gíves you u very líexíbíe wuy ol delíníng methods ín u híerurchy ol types.
1he loííowíng stutements creute u supertype numed t_person3, notíce thut the display_
details() lunctíon returns u VARCHAR2 contuíníng the uttríbute vuíues ol the ob¡ect:
CREATE TYPE t_person3 AS OBJECT (
id INTEGER,
first_name VARCHAR2(10),
last_name VARCHAR2(10),
MEMBER FUNCTION display_details RETURN VARCHAR2
) NOT FINAL;
/
CREATE TYPE BODY t_person3 AS
MEMBER FUNCTION display_details RETURN VARCHAR2 IS
BEGIN
RETURN 'id=' || id ||
', name=' || first_name || ' ' || last_name;
END;
END;
/
1he next set ol stutements creutes u subtype numed t_business_person3 under t_
person3, notíce thut the display_details() lunctíon ís overrídden usíng the OVERRIDING
keyword und thut the lunctíon returns u VARCHAR2 contuíníng the orígínuí und extended uttríbute
vuíues ol the ob¡ect:
CREATE TYPE t_business_person3 UNDER t_person3 (
title VARCHAR2(20),
company VARCHAR2(20),
OVERRIDING MEMBER FUNCTION display_details RETURN VARCHAR2
);
/
CREATE TYPE BODY t_business_person3 AS
OVERRIDING MEMBER FUNCTION display_details RETURN VARCHAR2 IS
BEGIN
RETURN 'id=' || id ||
', name=' || first_name || ' ' || last_name ||
', title=' || title || ', company=' || company;
Chupter l2: Dutubuse Cb¡ects
423
END;
END;
/
1he use ol the OVERRIDING keyword índícutes thut display_details() ín t_business_
person3 overrídes display_details() ín t_person3, therelore, when display_details()
ín t_business_person3 ís cuííed, ít cuíís display_details() ín t_business_person3, not
display_details() ín t_person3.
NOTf
ín |hc ncx| ·cc|íon o| |hí· chap|cr, ,ou'íí ·cc hov ,ou can dírcc|í, caíí
a mc|hod ín a ·upcr|,pc |rom a ·ub|,pc. Thí· ·avc· ,ou |rom havíng
|o rccrca|c codc ín |hc ·ub|,pc |ha| í· aírcad, ín |hc ·upcr|,pc. You do
|hí· dírcc| caíííng b, u·íng a ncv |ca|urc caíícd generuíízed ínvocutíon
ín Cracíc Da|aba·c 11g.
1he loííowíng stutements creute u tubíe numed object_business_customers3 und udd
un ob¡ect to thís tubíe:
CREATE TABLE object_business_customers3 OF t_business_person3;
INSERT INTO object_business_customers3 VALUES (
t_business_person3(1, 'John', 'Brown', 'Manager', 'XYZ Corp')
);
1he loííowíng exumpíe cuíís display_details() usíng object_business_customers3:
SELECT o.display_details()
FROM object_business_customers3 o
WHERE id = 1;
O.DISPLAY_DETAILS()
------------------------------------------------------
id=1, name=John Brown, title=Manager, company=XYZ Corp
ßecuuse the display_details() lunctíon us delíned ín t_business_person3 ís cuííed,
the VARCHAR2 returned by the lunctíon contuíns the id, first_name, und last_name uttríbutes,
uíong wíth the title und company uttríbutes.
GcncraIizcd lnvucatiun
As you suw ín the prevíous sectíon, you cun overríde u method ín the supertype wíth u method ín
the subtype. Ccncraíí2cd ínvoca|íon ís u new leuture ín Crucíe Dutubuse llg und uííows you to
cuíí u method ín u supertype lrom u subtype. As you'íí see, generuíízed ínvocutíon suves you lrom
huvíng to recreute code ín the subtype thut ís uíreudy ín the supertype.
NOTf
í'vc provídcd an SÇí*ííu· ·críp| namcd object_schema3.sql,
vhích crca|c· aíí |hc í|cm· ·hovn ín |hc rc·| o| |hí· chap|cr. You can
run |hc object_schema3.sql ·críp| oní, í| ,ou arc u·íng Cracíc
Da|aba·c 11g. A||cr |hc ·críp| compíc|c·, ,ou vííí bc íoggcd ín a·
object_user3.

Crucíe Dutubuse ll SQL
1he loííowíng stutements creute u supertype numed t_person, notíce thut the display_
details() lunctíon returns u VARCHAR2 contuíníng the uttríbute vuíues:
CREATE TYPE t_person AS OBJECT (
id INTEGER,
first_name VARCHAR2(10),
last_name VARCHAR2(10),
MEMBER FUNCTION display_details RETURN VARCHAR2
) NOT FINAL;
/
CREATE TYPE BODY t_person AS
MEMBER FUNCTION display_details RETURN VARCHAR2 IS
BEGIN
RETURN 'id=' || id ||
', name=' || first_name || ' ' || last_name;
END;
END;
/
1he next set ol stutements creutes u subtype numed t_business_person under t_person,
notíce thut the display_details() lunctíon ís overrídden usíng the OVERRIDING keyword:
CREATE TYPE t_business_person UNDER t_person (
title VARCHAR2(20),
company VARCHAR2(20),
OVERRIDING MEMBER FUNCTION display_details RETURN VARCHAR2
);
/
CREATE TYPE BODY t_business_person AS
OVERRIDING MEMBER FUNCTION display_details RETURN VARCHAR2 IS
BEGIN
-- use generalized invocation to call display_details() in t_person
RETURN (SELF AS t_person).display_details ||
', title=' || title || ', company=' || company;
END;
END;
/
As you cun see, display_details() ín t_business_person overrídes display_
details() ín t_person. 1he loííowíng ííne ín display_details() uses generuíízed
ínvocutíon to cuíí u method ín u supertype lrom u subtype:
RETURN (SELF AS t_person).display_details ||
', title=' || title || ', company=' || company;
\hut (SELF AS t_person).display_details does ís to treut un ob¡ect ol the current
type (whích ís t_business_person) us un ob¡ect ol type t_person und then to cuíí display_
details() ín t_person. So, when display_details() ín t_business_person ís cuííed,
ít lírst cuíís display_details() ín t_person (whích díspíuys the id, first_name, und
Chupter l2: Dutubuse Cb¡ects
42S
last_name uttríbute vuíues), then díspíuys the title und company uttríbute vuíues. 1hís meunt l
dídn't huve to re-creute the code uíreudy ín t_person.display_details() ín t_business_
person.display_details(), thereby suvíng some work. ll you huve more compíex methods
ín your types, thís leuture cun suve u íot ol work und muke your code eusíer to muíntuín.
1he loííowíng stutements creute u tubíe numed object_business_customers und udd un
ob¡ect to thís tubíe:
CREATE TABLE object_business_customers OF t_business_person;
INSERT INTO object_business_customers VALUES (
t_business_person(1, 'John', 'Brown', 'Manager', 'XYZ Corp')
);
1he loííowíng query cuíís display_details() usíng object_business_customers:
SELECT o.display_details()
FROM object_business_customers o;
O.DISPLAY_DETAILS()
--------------------------------------------------------------------
id=1, name=John Brown, dob=01-FEB-55, title=Manager, company=XYZ Corp
As you cun see, the id, name, und dute ol bírth (dob) ure díspíuyed (whích come lrom
display_details() ín t_person), loííowed by the title und company (whích come
lrom display_details() ín t_business_person).
Summary
ln thís chupter, you íeurned the loííowíng:
1he Crucíe dutubuse uííows you to creute ob¡ect types. An ob¡ect type ís ííke u cíuss ín
}uvu, C++, und Cr. An ob¡ect type muy contuín uttríbutes und methods, you creute un
ob¡ect type usíng the CREATE TYPE stutement.
You cun use un ob¡ect type to delíne u coíumn ob¡ect or un ob¡ect tubíe.
You cun use un ob¡ect relerence to uccess un índívíduuí row ín un ob¡ect tubíe. An ob¡ect
relerence ís símííur to u poínter ín C++.
You cun creute und munípuíute ob¡ects ín SQL und lL/SQL.
\íth the reíeuse ol Crucíe Dutubuse 9, you cun use ob¡ect type ínherítunce. 1hís uííows
you to delíne híerurchíes ol dutubuse types.
You cun use u subtype ob¡ect ín píuce ol u supertype ob¡ect, whích gíves you greut
líexíbíííty when storíng und munípuíutíng reíuted types. ll you wunt to prevent the use
ol u subtype ob¡ect ín píuce ol supertype ob¡ect, you cun murk un ob¡ect tubíe or ob¡ect
coíumn us NOT SUBSTITUTABLE.
You cun use u number ol useluí lunctíons wíth ob¡ects, such us REF(), DEREF(),
VALUE(), IS OF(), SYS_TYPEID(), und TREAT().

Crucíe Dutubuse ll SQL
You cun murk un ob¡ect type us NOT INSTANTIABLE, whích prevents ob¡ects ol thut type
lrom beíng creuted. You'íí wunt to murk un ob¡ect type us NOT INSTANTIABLE when
you use thut type us un ubstruct supertype und never uctuuííy creute ob¡ects ol thut type.
You cun delíne your own constructors to do thíngs ííke progrummutícuííy settíng u deluuít
lor uttríbutes ol un ob¡ect.
You cun overríde u method ín u supertype wíth u method ín u subtype, gívíng you u very
líexíbíe wuy ol delíníng methods ín u híerurchy ol types.
You cun use the new Crucíe Dutubuse ll generuíízed ínvocutíon leuture to cuíí methods
ín supertype lrom u subtype. Doíng thís cun suve you u íot ol work und muke your code
eusíer to muíntuín.
ln the next chupter, you'íí íeurn ubout coííectíons.
\IAI1II
1J
Coííectíons
427
428
Crucíe Dutubuse llg SQL
n thís chupter, you wííí do the loííowíng:
Leurn ubout coííectíons
Leurn how to creute coííectíon types
Lse coííectíon types to delíne coíumns ín tubíes
Creute und munípuíute coííectíon dutu ín SQL und lL/SQL
Leurn how u coííectíon muy ítseíl contuín embedded coííectíons (u ºmuítííeveí¨
coííectíon)
Lxumíne the enhuncements to coííectíons thut were íntroduced ín Crucíe Dutubuse l0g
lntruducing CuIIcctiuns
Crucíe Dutubuse 8 íntroduced two new dutubuse types, known us coíícc|íon·, thut uííow you to
store sets ol eíements. Crucíe Dutubuse 9í extended these leutures to íncíude muítííeveí coííectíons,
whích uííow you to embed u coííectíon wíthín unother coííectíon. Crucíe Dutubuse l0g lurther
extended coííectíons to íncíude ussocíutíve urruys und much more.
1here ure three types ol coííectíons:
Varrays A vurruy ís símííur to un urruy ín }uvu, C++, und Cr. A vurruy stores un ordered
set ol eíements, und euch eíement hus un índex thut records íts posítíon ín the urruy.
Líements ín u vurruy cun be modílíed oníy us u whoíe, not índívíduuííy, thís meuns thut
even íl you oníy wunt to modíly one eíement, you must suppíy uíí the eíements lor the
vurruy. A vurruy hus u muxímum síze thut you set when creutíng ít, but you cun chunge
the síze íuter.
Ncstcd tabIcs A nested tubíe ís u tubíe thut ís embedded wíthín unother tubíe. You cun
ínsert, updute, und deíete índívíduuí eíements ín u nested tubíe, thís mukes them more
líexíbíe thun u vurruy, whose eíements cun be modílíed oníy us u whoíe. A nested tubíe
doesn't huve u muxímum síze, und you cun store un urbítrury number ol eíements ín u
nested tubíe.
Assuciativc arrays (furmcrIy knuwn as indcx-by tabIcs) An ussocíutíve urruy ís símííur
to u hush tubíe ín }uvu. lntroduced ín Crucíe Dutubuse l0g, un ussocíutíve urruy ís u set
ol key und vuíue puírs. You cun get the vuíue lrom the urruy usíng the key (whích muy be
u stríng) or un ínteger thut specílíes the posítíon ol the vuíue ín the urruy. An ussocíutíve
urruy cun be used oníy ín lL/SQL und cunnot be stored ín the dutubuse.
You míght be uskíng yourseíl why you wouíd wunt to use coííectíons ín the lírst píuce. Alter
uíí, usíng two tubíes wíth u loreígn key uíreudy uííows you to modeí reíutíonshíps between dutu.
1he unswer ís thut coííectíons loííow the ob¡ect-oríented styíe ol modern progrummíng, ín uddítíon,
the dutu stored ín the coííectíon muy be uccessed more rupídíy by the dutubuse thun íl you were
to use two reíutíonuí tubíes to store the sume dutu.

Chupter l3: Coííectíons
429
l've províded un SQL*líus scrípt numed collection_schema.sql ín the SQL dírectory. 1he
scrípt creutes u user numed collection_user wíth u pussword ol collection_password,
und creutes the coííectíon types, tubíes, und lL/SQL code used ín the lírst purt ol thís chupter. You
must run thís scrípt whííe íogged ín us u user wíth the requíred prívííeges to creute u new user wíth
the CONNECT und RESOURCE prívííeges, l íog ín us the system user on my dutubuse to run the
scrípts. Alter the scrípt compíetes, you wííí be íogged ín us collection_user.
Crcating CuIIcctiun Typcs
ln thís sectíon, you'íí see how to creute u vurruy type und u nested tubíe type.
Crcating a Varray Typc
A vurruy stores un ordered set ol eíements, uíí ol the sume type, und the type cun be u buíít-ín
dutubuse type or u user-delíned ob¡ect type. Luch eíement hus un índex thut corresponds to íts
posítíon ín the urruy, und you cun modíly eíements ín the vurruy oníy us u whoíe.
You creute u vurruy type usíng the CREATE TYPE stutement, ín whích you specíly the
muxímum síze und the type ol eíements stored ín the vurruy. 1he loííowíng exumpíe creutes
u type numed t_varray_address thut cun store up to three VARCHAR2 stríngs:
CREATE TYPE t_varray_address AS VARRAY(3) OF VARCHAR2(50);
/
Luch VARCHAR2 wííí be used to represent u díllerent uddress lor u customer ol our exumpíe store.
ln Crucíe Dutubuse l0 und hígher, you cun chunge the muxímum number ol eíements ol u
vurruy usíng the ALTER TYPE stutement. lor exumpíe, the loííowíng stutement uíters the muxímum
number ol eíements to ten:
ALTER TYPE t_varray_address MODIFY LIMIT 10 CASCADE;
1he CASCADE optíon propugutes the chunge to uny dependent ob¡ects ín the dutubuse.
Crcating a Ncstcd TabIc Typc
A nested tubíe stores un unordered set ol uny number ol eíements. You cun ínsert, updute, und
deíete índívíduuí eíements ín u nested tubíe. A nested tubíe doesn't huve u muxímum síze, und you
cun store un urbítrury number ol eíements ín u nested tubíe.
ln thís sectíon, you'íí see u nested tubíe type thut stores t_address ob¡ect types. You suw
the use ol t_address ín the prevíous chupter, ít ís used to represent un uddress und ís delíned
us loííows:
CREATE TYPE t_address AS OBJECT (
street VARCHAR2(15),
city VARCHAR2(15),
state CHAR(2),
zip VARCHAR2(5)
);
/
You creute u nested tubíe type usíng the CREATE TYPE stutement, und the loííowíng exumpíe
creutes u type numed t_nested_table_address thut stores t_address ob¡ects:
CREATE TYPE t_nested_table_address AS TABLE OF t_address;
/
430
Crucíe Dutubuse ll SQL
Notíce thut you don't specíly the muxímum síze ol u nested tubíe. 1hut's becuuse u nested
tubíe cun store uny number ol eíements.
Using a CuIIcctiun Typc tu Dcfinc a CuIumn
in a TabIc
Cnce you've creuted u coííectíon type, you cun use ít to delíne u coíumn ín u tubíe. You'íí see
how to use the vurruy type und nested tubíe type creuted ín the prevíous sectíon to delíne u
coíumn ín u tubíe.
Using a Varray Typc tu Dcfinc a CuIumn in a TabIc
1he loííowíng stutement creutes u tubíe numed customers_with_varray, whích uses
t_varray_address to delíne u coíumn numed addresses:
CREATE TABLE customers_with_varray (
id INTEGER PRIMARY KEY,
first_name VARCHAR2(10),
last_name VARCHAR2(10),
addresses t_varray_address
);
1he eíements ín u vurruy ure stored dírectíy ínsíde the tubíe when the síze ol the vurruy ís 4Kß
or íess, otherwíse, the vurruy ís stored outsíde ol the tubíe. \hen u vurruy ís stored wíth the tubíe,
uccessíng íts eíements ís luster thun uccessíng eíements ín u nested tubíe.
Using a Ncstcd TabIc Typc tu Dcfinc a CuIumn in a TabIc
1he loííowíng stutement creutes u tubíe numed customers_with_nested_table, whích uses
t_nested_table_address to delíne u coíumn numed addresses:
CREATE TABLE customers_with_nested_table (
id INTEGER PRIMARY KEY,
first_name VARCHAR2(10),
last_name VARCHAR2(10),
addresses t_nested_table_address
)
NESTED TABLE
addresses
STORE AS
nested_addresses;
1he NESTED TABLE cíuuse ídentílíes the nume ol the nested tubíe coíumn (addresses
ín the exumpíe), und the STORE AS cíuuse specílíes the nume ol the nested tubíe (nested_
addresses ín the exumpíe) where the uctuuí eíements ure stored. You cunnot uccess the nested
tubíe índependentíy ol the tubíe ín whích ít ís embedded.
Chupter l3: Coííectíons
431
Gctting lnfurmatiun un CuIIcctiuns
As you'íí see ín thís sectíon, you cun use the DESCRIBE commund und u coupíe ol user víews to
get ínlormutíon on your coííectíons.
Gctting lnfurmatiun un a Varray
1he loííowíng exumpíe descríbes t_varray_address:
DESCRIBE t_varray_address
t_varray_address VARRAY(3) OF VARCHAR2(50)
1he next exumpíe descríbes the customers_with_varray tubíe, whose addresses
coíumn ís ol the t_varray_address type:
DESCRIBE customers_with_varray
Name Null? Type
------------------------------- -------- ------------------
ID NOT NULL NUMBER(38)
FIRST_NAME VARCHAR2(10)
LAST_NAME VARCHAR2(10)
ADDRESSES T_VARRAY_ADDRESS
You cun uíso get ínlormutíon on your vurruys lrom the user_varrays víew. 1ubíe l3-l
descríbes the coíumns ín user_varrays.
CuIumn Typc Dcscriptiun
parent_table_name VARCHAR2(30)
Nume ol the tubíe thut contuíns the
vurruy.
parent_table_column VARCHAR2(4000)
Nume ol the coíumn ín the purent
tubíe contuíníng the vurruy.
type_owner VARCHAR2(30)
Lser who owns the vurruy type.
type_name VARCHAR2(30)
Nume ol the vurruy type.
lob_name VARCHAR2(30)
Nume ol the íurge ob¡ect (LCß) when
the vurruy ís stored ín un LCß. You'íí
íeurn ubout LCßs ín the next chupter.
storage_spec VARCHAR2(30)
Storuge specílícutíon lor the vurruy.
return_type VARCHAR2(20)
Return type ol the coíumn.
element_
substitutable
VARCHAR2(25)
\hether or not (Y/N) the vurruy
eíement ís substítutubíe lor u subtype.
TABlf 13-1 Coíumn· ín |hc user_varrays Vícv
432
Crucíe Dutubuse llg SQL
NOTf
You can gc| ín|orma|íon on aíí |hc varra,· ,ou havc accc·· |o u·íng |hc
all_varrays vícv.
1he loííowíng exumpíe retríeves the detuíís lor t_varray_address lrom user_varrays:
SELECT parent_table_name, parent_table_column, type_name
FROM user_varrays
WHERE type_name = 'T_VARRAY_ADDRESS';
PARENT_TABLE_NAME
---------------------
PARENT_TABLE_COLUMN
---------------------
TYPE_NAME
---------------------
CUSTOMERS_WITH_VARRAY
ADDRESSES
T_VARRAY_ADDRESS
Gctting lnfurmatiun un a Ncstcd TabIc
You cun uíso use DESCRIBE wíth u nested tubíe, us shown ín the loííowíng exumpíe thut
descríbes t_nested_table_address:
DESCRIBE t_nested_table_address
t_nested_table_address TABLE OF T_ADDRESS
Name Null? Type
----------------------------------------- -------- ------------
STREET VARCHAR2(15)
CITY VARCHAR2(15)
STATE CHAR(2)
ZIP VARCHAR2(5)
1he next exumpíe descríbes the customers_with_nested_table tubíe, whose
addresses coíumn ís ol type t_nested_table_address:
DESCRIBE customers_with_nested_table
Name Null? Type
---------------------------------- -------- ----------------------
ID NOT NULL NUMBER(38)
FIRST_NAME VARCHAR2(10)
LAST_NAME VARCHAR2(10)
ADDRESSES T_NESTED_TABLE_ADDRESS
ll you set the depth to 2 und descríbe customers_with_nested_table, you cun see the
uttríbutes thut muke up t_nested_table_address:
SET DESCRIBE DEPTH 2
DESCRIBE customers_with_nested_table
Name Null? Type
----------------------------------- -------- -------------
ID NOT NULL NUMBER(38)
FIRST_NAME VARCHAR2(10)
Chupter l3: Coííectíons
433
LAST_NAME VARCHAR2(10)
ADDRESSES T_NESTED_TABLE_ADDRESS
STREET VARCHAR2(15)
CITY VARCHAR2(15)
STATE CHAR(2)
ZIP VARCHAR2(5)
You cun uíso get ínlormutíon on your nested tubíes lrom the user_nested_tables víew.
1ubíe l3-2 descríbes the coíumns ín user_nested_tables.
NOTf
You can gc| ín|orma|íon on aíí |hc nc·|cd |abíc· ,ou havc accc·· |o
u·íng |hc all_nested_tables vícv.
1he loííowíng exumpíe retríeves the detuíís lor the nested_addresses tubíe lrom user_
nested_tables:
SELECT table_name, table_type_name, parent_table_name, parent_table_column
FROM user_nested_tables
WHERE table_name = 'NESTED_ADDRESSES';
TABLE_NAME TABLE_TYPE_NAME
------------------------------ ----------------------
PARENT_TABLE_NAME
------------------------------
PARENT_TABLE_COLUMN
-----------------------------------------------------
NESTED_ADDRESSES T_NESTED_TABLE_ADDRESS
CUSTOMERS_WITH_NESTED_TABLE
ADDRESSES
CuIumn Typc Dcscriptiun
table_name VARCHAR2(30)
Nume ol the nested tubíe
table_type_owner VARCHAR2(30)
Lser who owns the nested tubíe type
table_type_name VARCHAR2(30)
Nume ol the nested tubíe type
parent_table_name VARCHAR2(30)
Nume ol the purent tubíe thut
contuíns the nested tubíe
parent_table_column VARCHAR2(4000)
Nume ol the coíumn ín the purent
tubíe contuíníng the nested tubíe
storage_spec VARCHAR2(30)
Storuge specílícutíon lor the nested
tubíe
return_type VARCHAR2(20)
Return type ol the coíumn
element_substitutable VARCHAR2(25)
\hether or not (Y/N) the nested
tubíe eíement ís substítutubíe lor u
subtype.
TABlf 13-2 Coíumn· ín |hc user_nested_tables Vícv
434
Crucíe Dutubuse ll SQL
PupuIating a CuIIcctiun with fIcmcnts
ln thís sectíon, you'íí see how to popuíute u vurruy und u nested tubíe wíth eíements usíng INSERT
stutements. You don't huve to run the INSERT stutements shown ín thís sectíon: they ure executed
when you run the collection_schema.sql scrípt.
PupuIating a Varray with fIcmcnts
1he loííowíng INSERT stutements udd rows to the customers_with_varray tubíe, notíce the
use ol the t_varray_address constructor to specíly the stríngs lor the eíements ol the vurruy:
INSERT INTO customers_with_varray VALUES (
1, 'Steve', 'Brown',
t_varray_address(
'2 State Street, Beantown, MA, 12345',
'4 Hill Street, Lost Town, CA, 54321'
)
);
INSERT INTO customers_with_varray VALUES (
2, 'John', 'Smith',
t_varray_address(
'1 High Street, Newtown, CA, 12347',
'3 New Street, Anytown, MI, 54323',
'7 Market Street, Main Town, MA, 54323'
)
);
As you cun see, the lírst row hus two uddresses und the second hus three. Any number ol
uddresses up to the muxímum íímít lor the vurruy cun be stored.
PupuIating a Ncstcd TabIc with fIcmcnts
1he loííowíng INSERT stutements udd rows to customers_with_nested_table, notíce the
use ol the t_nested_table_address und t_address constructors to specíly the eíements ol
the nested tubíe:
INSERT INTO customers_with_nested_table VALUES (
1, 'Steve', 'Brown',
t_nested_table_address(
t_address('2 State Street', 'Beantown', 'MA', '12345'),
t_address('4 Hill Street', 'Lost Town', 'CA', '54321')
)
);
INSERT INTO customers_with_nested_table VALUES (
2, 'John', 'Smith',
t_nested_table_address(
Chupter l3: Coííectíons
43S
t_address('1 High Street', 'Newtown', 'CA', '12347'),
t_address('3 New Street', 'Anytown', 'MI', '54323'),
t_address('7 Market Street', 'Main Town', 'MA', '54323')
)
);
As you cun see, the lírst row hus two uddresses und the second hus three. Any number ol
uddresses cun be stored ín u nested tubíe.
Rctricving fIcmcnts frum CuIIcctiuns
ln thís sectíon, you'íí see how to retríeve eíements lrom u vurruy und u nested tubíe usíng queríes.
1he output lrom the queríes hus been lormutted sííghtíy to muke the resuíts more reudubíe.
Rctricving fIcmcnts frum a Varray
1he loííowíng query retríeves customer rl lrom the customers_with_varray tubíe, one row
ís returned, und ít contuíns the two uddresses stored ín the vurruy:
SELECT *
FROM customers_with_varray
WHERE id = 1;
ID FIRST_NAME LAST_NAME
---------- ---------- ----------
ADDRESSES
-------------------------------------------------------
1 Steve Brown
T_VARRAY_ADDRESS('2 State Street, Beantown, MA, 12345',
'4 Hill Street, Lost Town, CA, 54321')
1he next query specílíes the uctuuí coíumn numes:
SELECT id, first_name, last_name, addresses
FROM customers_with_varray
WHERE id = 1;
ID FIRST_NAME LAST_NAME
---------- ---------- ----------
ADDRESSES
-------------------------------------------------------
1 Steve Brown
T_VARRAY_ADDRESS('2 State Street, Beantown, MA, 12345',
'4 Hill Street, Lost Town, CA, 54321')
1hese exumpíes uíí return the uddresses ín the vurruy us u síngíe row. Luter, ín the sectíon
ºLsíng 1AßLL() to 1reut u Coííectíon us u Seríes ol Rows,¨ you'íí see how you cun treut the dutu
stored ín u coííectíon us u seríes ol rows.
436
Crucíe Dutubuse ll SQL
Rctricving fIcmcnts frum a Ncstcd TabIc
1he loííowíng query retríeves customer rl lrom customers_with_nested_table, one row ís
returned, und ít contuíns the two uddresses stored ín the nested tubíe:
SELECT *
FROM customers_with_nested_table
WHERE id = 1;
ID FIRST_NAME LAST_NAME
---------- ---------- ----------
ADDRESSES(STREET, CITY, STATE, ZIP)
--------------------------------------------------------
1 Steve Brown
T_NESTED_TABLE_ADDRESS(
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345'),
T_ADDRESS('4 Hill Street', 'Lost Town', 'CA', '54321'))
1he next query specílíes the uctuuí coíumn numes:
SELECT id, first_name, last_name, addresses
FROM customers_with_nested_table
WHERE id = 1;
ID FIRST_NAME LAST_NAME
---------- ---------- ----------
ADDRESSES(STREET, CITY, STATE, ZIP)
--------------------------------------------------------
1 Steve Brown
T_NESTED_TABLE_ADDRESS(
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345'),
T_ADDRESS('4 Hill Street', 'Lost Town', 'CA', '54321'))
1he next query gets ¡ust the addresses nested tubíe, us ín the prevíous exumpíes, one row ís
returned, und ít contuíns the two uddresses stored ín the nested tubíe:
SELECT addresses
FROM customers_with_nested_table
WHERE id = 1;

ADDRESSES(STREET, CITY, STATE, ZIP)
--------------------------------------------------------
T_NESTED_TABLE_ADDRESS(
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345'),
T_ADDRESS('4 Hill Street', 'Lost Town', 'CA', '54321'))
Using TABlf() tu Trcat a CuIIcctiun
as a Scrics uf Ruws
1he prevíous queríes you've seen ín thís chupter return the contents ol u coííectíon us u síngíe
row. Sometímes, you muy wísh to treut the dutu stored ín u coííectíon us u seríes ol rows, lor
Chupter l3: Coííectíons
437
exumpíe, you míght be workíng wíth u íegucy uppíícutíon thut cun oníy use rows. 1o treut u
coííectíon us u seríes ol rows, you use the TABLE() lunctíon. ln thís sectíon, you'íí see how
to use TABLE() wíth u vurruy und u nested tubíe.
Using TABlf() with a Varray
1he loííowíng query uses TABLE() to retríeve customer rl's two uddresses lrom the
customers_with_varray tubíe, two sepurute rows ure returned:
SELECT a.*
FROM customers_with_varray c, TABLE(c.addresses) a
WHERE id = 1;
COLUMN_VALUE
-----------------------------------
2 State Street, Beantown, MA, 12345
4 Hill Street, Lost Town, CA, 54321
Notíce how the Crucíe dutubuse soltwure uutomutícuííy udds the coíumn nume ol COLUMN_
VALUE to the rows returned by the query. COLUMN_VALUE ís u pseudo coíumn uííus, und ít ís
uutomutícuííy udded when u coííectíon contuíns dutu ol one ol the buíít-ín dutu types, ííke
VARCHAR2, CHAR, NUMBER, or DATE. ßecuuse the exumpíe vurruy contuíns VARCHAR2 dutu, the
COLUMN_VALUE uííus ís udded. ll the vurruy hud contuíned dutu ol u user-delíned ob¡ect type,
then TABLE() wouíd return ob¡ects ol thut type und COLUMN_VALUE wouíd not uppeur, you'íí
see un exumpíe ol thís ín the next sectíon.
You cun uíso embed un entíre SELECT stutement ínsíde TABLE(). lor exumpíe, the loííowíng
query rewrítes the prevíous exumpíe, píucíng u SELECT ínsíde TABLE():
SELECT *
FROM TABLE(
-- get the addresses for customer #1
SELECT addresses
FROM customers_with_varray
WHERE id = 1
);
COLUMN_VALUE
-----------------------------------
2 State Street, Beantown, MA, 12345
4 Hill Street, Lost Town, CA, 54321
1he loííowíng query shows unother exumpíe thut uses TABLE() to get the uddresses:
SELECT c.id, c.first_name, c.last_name, a.*
FROM customers_with_varray c, TABLE(c.addresses) a
WHERE id = 1;
ID FIRST_NAME LAST_NAME
---------- ---------- ----------
COLUMN_VALUE
-----------------------------------
1 Steve Brown
438
Crucíe Dutubuse ll SQL
2 State Street, Beantown, MA, 12345
1 Steve Brown
4 Hill Street, Lost Town, CA, 54321
Using TABlf() with a Ncstcd TabIc
1he loííowíng query uses TABLE() to retríeve customer rl's two uddresses lrom customers_
with_nested_table, notíce thut two sepurute rows ure returned:
SELECT a.*
FROM customers_with_nested_table c, TABLE(c.addresses) a
WHERE id = 1;
STREET CITY ST ZIP
--------------- --------------- -- -----
2 State Street Beantown MA 12345
4 Hill Street Lost Town CA 54321
1he next query gets the street und state uttríbutes ol the uddresses:
SELECT a.street, a.state
FROM customers_with_nested_table c, TABLE(c.addresses) a
WHERE id = 1;
STREET ST
--------------- --
2 State Street MA
4 Hill Street CA
1he loííowíng query shows unother exumpíe thut uses TABLE() to get the uddresses:
SELECT c.id, c.first_name, c.last_name, a.*
FROM customers_with_nested_table c, TABLE(c.addresses) a
WHERE c.id = 1;
ID FIRST_NAME LAST_NAME STREET CITY ST ZIP
------ ---------- ---------- --------------- -------------- -- -----
1 Steve Brown 2 State Street Beantown MA 12345
1 Steve Brown 4 Hill Street Lost Town CA 54321
You'íí see un ímportunt use ol TABLE() íuter ín the sectíon ºModílyíng Líements ol u
Nested 1ubíe.¨
Mudifying fIcmcnts uf CuIIcctiuns
ln thís sectíon, you'íí see how to modíly the eíements ín u vurruy und u nested tubíe. You shouíd
leeí lree to run the UPDATE, INSERT, und DELETE stutements shown ín thís sectíon.
Mudifying fIcmcnts uf a Varray
1he eíements ín u vurruy cun be modílíed oníy us u whoíe, whích meuns thut even íl you oníy wunt
to modíly one eíement, you must suppíy uíí the eíements lor the vurruy. 1he loííowíng UPDATE
stutement modílíes the uddresses ol customer r2 ín the customers_with_varray tubíe:
Chupter l3: Coííectíons
439
UPDATE customers_with_varray
SET addresses = t_varray_address(
'6 Any Street, Lost Town, GA, 33347',
'3 New Street, Anytown, MI, 54323',
'7 Market Street, Main Town, MA, 54323'
)
WHERE id = 2;
1 row updated.
Mudifying fIcmcnts uf a Ncstcd TabIc
Lnííke ín u vurruy, eíements ín u nested tubíe cun be modílíed índívíduuííy. You cun ínsert, updute,
und deíete índívíduuí eíements ín u nested tubíe, you'íí see how to do uíí three ol these modílícutíons
ín thís sectíon.
1he loííowíng INSERT stutement udds un uddress to customer r2 ín customer_with_
nested_table, notíce thut TABLE() ís used to get the uddresses us u seríes ol rows:
INSERT INTO TABLE(
-- get the addresses for customer #2
SELECT addresses
FROM customers_with_nested_table
WHERE id = 2
) VALUES (
t_address('5 Main Street', 'Uptown', 'NY', '55512')
);
1 row created.
1he loííowíng UPDATE stutement chunges the '1 High Street'uddress ol customer r2 to
'9 Any Street', notíce the use ol the uííus addr ín the VALUE cíuuses when specílyíng the
uddresses:
UPDATE TABLE(
-- get the addresses for customer #2
SELECT addresses
FROM customers_with_nested_table
WHERE id = 2
) addr
SET VALUE(addr) =
t_address('9 Any Street', 'Lost Town', 'VA', '74321')
WHERE VALUE(addr) =
t_address('1 High Street', 'Newtown', 'CA', '12347');
1 row updated.
1he loííowíng DELETE stutement removes the '3 New Street...' uddress lrom
customer r2:
DELETE FROM TABLE(
-- get the addresses for customer #2
SELECT addresses
FROM customers_with_nested_table
440
Crucíe Dutubuse ll SQL
WHERE id = 2
) addr
WHERE VALUE(addr) =
t_address('3 New Street', 'Anytown', 'MI', '54323');
1 row deleted.
Using a Map Mcthud tu Cumparc thc Cuntcnts uf
Ncstcd TabIcs
You cun compure the contents ol one nested tubíe wíth the contents ol unother. 1wo nested tubíes
ure equuí oníy íl
1hey ure ol the sume type.
1hey huve the sume number ol rows.
Aíí theír eíements contuín the sume vuíues.
ll the eíements ol the nested tubíe ure ol u buíít-ín dutubuse type, ííke NUMBER, VARCHAR2,
und so on, then the dutubuse wííí uutomutícuííy compure the contents ol the nested tubíes lor you.
ll, however, the eíements ure ol u user-delíned ob¡ect type, then you wííí need to províde u mup
lunctíon thut contuíns code to compure the ob¡ects (mup lunctíons were shown ín the sectíon
ºCompuríng Cb¡ect Vuíues¨ ol the prevíous chupter).
1he loííowíng stutements creute u type numed t_address2 thut contuíns u mup lunctíon
numed get_string(), notíce thut get_string() returns u VARCHAR2 contuíníng the vuíues
lor the zip, state, city, und street uttríbutes:
CREATE TYPE t_address2 AS OBJECT (
street VARCHAR2(15),
city VARCHAR2(15),
state CHAR(2),
zip VARCHAR2(5),
-- declare the get_string() map function,
-- which returns a VARCHAR2 string
MAP MEMBER FUNCTION get_string RETURN VARCHAR2
);
/
CREATE TYPE BODY t_address2 AS
-- define the get_string() map function
MAP MEMBER FUNCTION get_string RETURN VARCHAR2 IS
BEGIN
-- return a concatenated string containing the
-- zip, state, city, and street attributes
RETURN zip || ' ' || state || ' ' || city || ' ' || street;
END get_string;
END;
/
Chupter l3: Coííectíons

As you'íí see shortíy, the dutubuse wííí uutomutícuííy cuíí get_string() when compuríng
t_address2 ob¡ects.
1he loííowíng stutements creute u nested tubíe type und u tubíe, und udd u row to the tubíe:
CREATE TYPE t_nested_table_address2 AS TABLE OF t_address2;
/
CREATE TABLE customers_with_nested_table2 (
id INTEGER PRIMARY KEY,
first_name VARCHAR2(10),
last_name VARCHAR2(10),
addresses t_nested_table_address2
)
NESTED TABLE
addresses
STORE AS
nested_addresses2;
INSERT INTO customers_with_nested_table2 VALUES (
1, 'Steve', 'Brown',
t_nested_table_address2(
t_address2('2 State Street', 'Beantown', 'MA', '12345'),
t_address2('4 Hill Street', 'Lost Town', 'CA', '54321')
)
);
1he loííowíng query íncíudes u nested tubíe ín the WHERE cíuuse, notíce thut the uddresses
ulter the = ín the WHERE cíuuse ure the sume us those ín the prevíous INSERT stutement:
SELECT cn.id, cn.first_name, cn.last_name
FROM customers_with_nested_table2 cn
WHERE cn.addresses =
t_nested_table_address2(
t_address2('2 State Street', 'Beantown', 'MA', '12345'),
t_address2('4 Hill Street', 'Lost Town', 'CA', '54321')
);
ID FIRST_NAME LAST_NAME
---------- ---------- ----------
1 Steve Brown
\hen the query ís executed, the dutubuse uutomutícuííy cuíís get_string() to compure
the t_address2 ob¡ects ín cn.addresses to the t_address2 ob¡ects ulter the = ín the
WHERE cíuuse. 1he get_string() lunctíon returns u VARCHAR2 stríng contuíníng the zip,
state, city, und street uttríbutes ol the ob¡ects, und when the stríngs ure equuí lor every
ob¡ect, the nested tubíes ure uíso equuí.
1he next query returns no rows becuuse the síngíe uddress ulter the = ín the WHERE cíuuse
mutches oníy one ol the uddresses ín cn.addresses (remember: two nested tubíes ure equuí
oníy íl they ure ol the sume type, havc |hc ·amc numbcr o| rov·, und theír eíements contuín the
sume vuíues):
SELECT cn.id, cn.first_name, cn.last_name
FROM customers_with_nested_table2 cn

Crucíe Dutubuse llg SQL
WHERE cn.addresses =
t_nested_table_address2(
t_address2('4 Hill Street', 'Lost Town', 'CA', '54321')
);
no rows selected
ln Crucíe Dutubuse l0g und hígher, you cun use the SUBMULTISET operutor to check
whether the contents ol one nested tubíe ure u subset ol unother nested tubíe. 1he loííowíng
query rewrítes the prevíous exumpíe und returns u row:
SELECT cn.id, cn.first_name, cn.last_name
FROM customers_with_nested_table2 cn
WHERE
t_nested_table_address2(
t_address2('4 Hill Street', 'Lost Town', 'CA', '54321')
)
SUBMULTISET OF cn.addresses;
ID FIRST_NAME LAST_NAME
---------- ---------- ----------
1 Steve Brown
ßecuuse the uddress ín the lírst purt ol the WHERE cíuuse ís u subset ol the uddresses ín
cn.addresses, u mutch ís lound und u row ís returned.
1he loííowíng query shows unother exumpíe, thís tíme the uddresses ín cn.addresses
ure u subset ol the uddresses ulter OF ín the WHERE cíuuse:
SELECT cn.id, cn.first_name, cn.last_name
FROM customers_with_nested_table2 cn
WHERE
cn.addresses SUBMULTISET OF
t_nested_table_address2(
t_address2('2 State Street', 'Beantown', 'MA', '12345'),
t_address2('4 Hill Street', 'Lost Town', 'CA', '54321'),
t_address2('6 State Street', 'Beantown', 'MA', '12345')
);
ID FIRST_NAME LAST_NAME
---------- ---------- ----------
1 Steve Brown
You'íí íeurn more ubout the SUBMULTISET operutor íuter ín thís chupter ín the sectíon
ºSLßMLL1lSL1 Cperutor.¨ Aíso, ín the sectíon ºLquuí und Not-Lquuí Cperutors,¨ you'íí see
how to use the ANSl operutors ímpíemented ín Crucíe Dutubuse l0g to compure nested tubíes.

Thcrc í· no dírcc| mcchaní·m |or comparíng |hc con|cn|· o| varra,·.
Chupter l3: Coííectíons
443
Using CAST() tu Cunvcrt CuIIcctiuns frum Onc
Typc tu Anuthcr
You muy use CAST() to convert u coííectíon ol one type to unother coííectíon type. ln thís
sectíon, you'íí see how to use CAST() to convert u vurruy to u nested tubíe und více versu.
Using CAST() tu Cunvcrt a Varray tu a Ncstcd TabIc
1he loííowíng stutements creute und popuíute u tubíe numed customers_with_varray2 thut
contuíns un addresses coíumn ol type t_varray_address2:
CREATE TYPE t_varray_address2 AS VARRAY(3) OF t_address;
/
CREATE TABLE customers_with_varray2 (
id INTEGER PRIMARY KEY,
first_name VARCHAR2(10),
last_name VARCHAR2(10),
addresses t_varray_address2
);
INSERT INTO customers_with_varray2 VALUES (
1, 'Jason', 'Bond',
t_varray_address2(
t_address('9 Newton Drive', 'Sometown', 'WY', '22123'),
t_address('6 Spring Street', 'New City', 'CA', '77712')
)
);
1he loííowíng query uses CAST() to return the vurruy uddresses lor customer rl us u nested
tubíe, notíce thut the uddresses uppeur ín u constructor lor the T_NESTED_TABLE_ADDRESS type,
índícutíng the conversíon ol the eíements to thís type:
SELECT CAST(cv.addresses AS t_nested_table_address)
FROM customers_with_varray2 cv
WHERE cv.id = 1;
CAST(CV.ADDRESSESAST_NESTED_TABLE_ADDRESS)(STREET, CITY, STATE, ZIP)
--------------------------------------------------------------------
T_NESTED_TABLE_ADDRESS(
T_ADDRESS('9 Newton Drive', 'Sometown', 'WY', '22123'),
T_ADDRESS('6 Spring Street', 'New City', 'CA', '77712'))
Using CAST() tu Cunvcrt a Ncstcd TabIc tu a Varray
1he loííowíng query uses CAST() to return the uddresses lor customer rl ín customers_with_
nested_table us u vurruy, notíce thut the uddresses uppeur ín u constructor lor T_VARRAY_
ADDRESS2:
SELECT CAST(cn.addresses AS t_varray_address2)
FROM customers_with_nested_table cn
444
Crucíe Dutubuse ll SQL
WHERE cn.id = 1;
CAST(CN.ADDRESSESAST_VARRAY_ADDRESS2)(STREET, CITY, STATE, ZIP)
---------------------------------------------------------------
T_VARRAY_ADDRESS2(
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345'),
T_ADDRESS('4 Hill Street', 'Lost Town', 'CA', '54321'))
Using CuIIcctiuns in Pl/SQl
You cun use coííectíons ín lL/SQL. ln thís sectíon, you'íí see how to perlorm the loííowíng tusks
ín lL/SQL:
Munípuíute u vurruy
Munípuíute u nested tubíe
Lse the lL/SQL coííectíon methods to uccess und munípuíute coííectíons
Aíí the puckuges you'íí see ín thís sectíon ure creuted when you run the collection_
schema.sql scrípt. ll you perlormed uny ol the INSERT, UPDATE, or DELETE stutements
shown ín the eurííer sectíons ol thís chupter, go uheud und rerun the collection_schema.sql
scrípt so thut your output mutches míne ín thís sectíon.
ManipuIating a Varray
ln thís sectíon, you'íí see u puckuge numed varray_package, thís puckuge contuíns the
loííowíng ítems:
A REF CURSOR type numed t_ref_cursor
A lunctíon numed get_customers(), whích returns u t_ref_cursor ob¡ect thut
poínts to the rows ín the customers_with_varray tubíe
A procedure numed insert_customer(), whích udds u row to the customers_
with_varray tubíe
1he collection_schema.sql scrípt contuíns the loííowíng puckuge specílícutíon und
body lor varray_package:
CREATE PACKAGE varray_package AS
TYPE t_ref_cursor IS REF CURSOR;
FUNCTION get_customers RETURN t_ref_cursor;
PROCEDURE insert_customer(
p_id IN customers_with_varray.id%TYPE,
p_first_name IN customers_with_varray.first_name%TYPE,
p_last_name IN customers_with_varray.last_name%TYPE,
p_addresses IN customers_with_varray.addresses%TYPE
);
END varray_package;
/
Chupter l3: Coííectíons

CREATE PACKAGE BODY varray_package AS
-- get_customers() function returns a REF CURSOR
-- that points to the rows in customers_with_varray
FUNCTION get_customers
RETURN t_ref_cursor IS
--declare the REF CURSOR object
v_customers_ref_cursor t_ref_cursor;
BEGIN
-- get the REF CURSOR
OPEN v_customers_ref_cursor FOR
SELECT *
FROM customers_with_varray;
-- return the REF CURSOR
RETURN customers_ref_cursor;
END get_customers;
-- insert_customer() procedure adds a row to
-- customers_with_varray
PROCEDURE insert_customer(
p_id IN customers_with_varray.id%TYPE,
p_first_name IN customers_with_varray.first_name%TYPE,
p_last_name IN customers_with_varray.last_name%TYPE,
p_addresses IN customers_with_varray.addresses%TYPE
) IS
BEGIN
INSERT INTO customers_with_varray
VALUES (p_id, p_first_name, p_last_name, p_addresses);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END insert_customer;
END varray_package;
/
1he loííowíng exumpíe cuíís insert_customer() to udd u new row to the customers_
with_varray tubíe:
CALL varray_package.insert_customer(
3, 'James', 'Red',
t_varray_address(
'10 Main Street, Green Town, CA, 22212',
'20 State Street, Blue Town, FL, 22213'
)
);
Call completed.
1he next exumpíe cuíís get_products() to retríeve the rows lrom customers_with_
varray:
446
Crucíe Dutubuse ll SQL
SELECT varray_package.get_customers
FROM dual;
GET_CUSTOMERS
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
ID FIRST_NAME LAST_NAME
---------- ---------- ----------
ADDRESSES
---------------------------------------------------------
1 Steve Brown
T_VARRAY_ADDRESS('2 State Street, Beantown, MA, 12345',
'4 Hill Street, Lost Town, CA, 54321')
2 John Smith
T_VARRAY_ADDRESS('1 High Street, Newtown, CA, 12347',
'3 New Street, Anytown, MI, 54323',
'7 Market Street, Main Town, MA, 54323')
3 James Red
T_VARRAY_ADDRESS('10 Main Street, Green Town, CA, 22212',
'20 State Street, Blue Town, FL, 22213')
ManipuIating a Ncstcd TabIc
ln thís sectíon, you'íí see u puckuge numed nested_table_package, thís puckuge contuíns the
loííowíng ítems:
A REF CURSOR type numed t_ref_cursor
A lunctíon numed get_customers(), whích returns u t_ref_cursor ob¡ect thut
poínts to the rows ín customers_with_nested_table
A procedure numed insert_customer(), whích udds u row to customers_with_
nested_table
1he collection_schema.sql scrípt contuíns the loííowíng puckuge specílícutíon und
body lor nested_table_package:
CREATE PACKAGE nested_table_package AS
TYPE t_ref_cursor IS REF CURSOR;
FUNCTION get_customers RETURN t_ref_cursor;
PROCEDURE insert_customer(
p_id IN customers_with_nested_table.id%TYPE,
p_first_name IN customers_with_nested_table.first_name%TYPE,
p_last_name IN customers_with_nested_table.last_name%TYPE,
p_addresses IN customers_with_nested_table.addresses%TYPE
);
Chupter l3: Coííectíons

END nested_table_package;
/
CREATE PACKAGE BODY nested_table_package AS
-- get_customers() function returns a REF CURSOR
-- that points to the rows in customers_with_nested_table
FUNCTION get_customers
RETURN t_ref_cursor IS
-- declare the REF CURSOR object
v_customers_ref_cursor t_ref_cursor;
BEGIN
-- get the REF CURSOR
OPEN v_customers_ref_cursor FOR
SELECT *
FROM customers_with_nested_table;
-- return the REF CURSOR
RETURN customers_ref_cursor;
END get_customers;
-- insert_customer() procedure adds a row to
-- customers_with_nested_table
PROCEDURE insert_customer(
p_id IN customers_with_nested_table.id%TYPE,
p_first_name IN customers_with_nested_table.first_name%TYPE,
p_last_name IN customers_with_nested_table.last_name%TYPE,
p_addresses IN customers_with_nested_table.addresses%TYPE
) IS
BEGIN
INSERT INTO customers_with_nested_table
VALUES (p_id, p_first_name, p_last_name, p_addresses);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END insert_customer;
END nested_table_package;
/
1he loííowíng exumpíe cuíís insert_customer() to udd u new row to customers_
with_nested_table:
CALL nested_table_package.insert_customer(
3, 'James', 'Red',
t_nested_table_address(
t_address('10 Main Street', 'Green Town', 'CA', '22212'),
t_address('20 State Street', 'Blue Town', 'FL', '22213')
)
);
Call completed.
448
Crucíe Dutubuse ll SQL
1he next exumpíe cuíís get_customers() to retríeve the rows lrom customers_with_
nested_table:
SELECT nested_table_package.get_customers
FROM dual;
GET_CUSTOMERS
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
ID FIRST_NAME LAST_NAME
---------- ---------- ----------
ADDRESSES(STREET, CITY, STATE, ZIP)
------------------------------------------------------------
1 Steve Brown
T_NESTED_TABLE_ADDRESS(
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345'),
T_ADDRESS('4 Hill Street', 'Lost Town', 'CA', '54321'))
2 John Smith
T_NESTED_TABLE_ADDRESS(
T_ADDRESS('1 High Street', 'Newtown', 'CA', '12347'),
T_ADDRESS('3 New Street', 'Anytown', 'MI', '54323'),
T_ADDRESS('7 Market Street', 'Main Town', 'MA', '54323'))
3 James Red
T_NESTED_TABLE_ADDRESS(
T_ADDRESS('10 Main Street', 'Green Town', 'CA', '22212'),
T_ADDRESS('20 State Street', 'Blue Town', 'FL', '22213'))
Pl/SQl CuIIcctiun Mcthuds
ln thís sectíon, you'íí see the lL/SQL methods you cun use wíth coííectíons. 1ubíe l3-3
summurízes the coííectíon methods. 1hese methods cun be used oníy ín lL/SQL.
1he loííowíng sectíons use u puckuge numed collection_method_examples, the exumpíes
íííustrute the use ol the methods shown ín the prevíous tubíe. 1he puckuge ís creuted by the
collection_schema.sql scrípt, und you'íí see the índívíduuí methods delíned ín thís puckuge
ín the loííowíng sectíons.
COUNT()
COUNT returns the number ol eíements ín u coííectíon. ßecuuse u nested tubíe cun huve índívíduuí
eíements thut ure empty, COUNT returns the number ol non-empty eíements ín u nested tubíe. lor
exumpíe, íet's suy you huve u nested tubíe numed v_nested_table thut hus íts eíements set us
shown ín the loííowíng tubíe.
fIcmcnt lndcx fmpty/Nut fmpty
l Lmpty
2 Not empty
3 Lmpty
4 Not empty
Chupter l3: Coííectíons
449
Mcthud Dcscriptiun
COUNT
Returns the number ol eíements ín u coííectíon. ßecuuse u nested tubíe
cun huve índívíduuí eíements thut ure empty, COUNT returns the number
ol non-empty eíements ín u nested tubíe.
DELETE
DELETE(n)
DELETE(n, m)
Removes eíements lrom u coííectíon. 1here ure three lorms ol DELETE:
DELETE removes uíí eíements.
DELETE(n) removes eíement n.
DELETE(n, m) removes eíements n through m.
ßecuuse vurruys uíwuys huve consecutíve subscrípts, you cunnot deíete
índívíduuí eíements lrom u vurruy (except lrom the end by usíng TRIM).
EXISTS(n)
Returns true íl eíement n ín u coííectíon exísts: EXISTS returns true lor
non-empty eíements und luíse lor empty eíements ol nested tubíes or
eíements beyond the runge ol u coííectíon.
EXTEND
EXTEND(n)
EXTEND(n, m)
Adds eíements to the end ol u coííectíon. 1here ure three lorms ol
EXTEND:
EXTEND udds one eíement, whích ís set to nuíí.
EXTEND(n) udds n eíements, whích ure set to nuíí.
EXTEND(n, m) udds n eíements, whích ure set to u copy ol the m
eíement.
FIRST
Returns the índex ol the lírst eíement ín u coííectíon. ll the coííectíon ís
compíeteíy empty, FIRST returns nuíí. ßecuuse u nested tubíe cun huve
índívíduuí eíements thut ure empty, FIRST returns the íowest índex ol u
non-empty eíement ín u nested tubíe.
LAST
Returns the índex ol the íust eíement ín u coííectíon. ll the coííectíon ís
compíeteíy empty, LAST returns nuíí. ßecuuse u nested tubíe cun huve
índívíduuí eíements thut ure empty, LAST returns the híghest índex ol u
non-empty eíement ín u nested tubíe.
LIMIT
lor nested tubíes, whích huve no decíured síze, LIMIT returns nuíí. lor
vurruys, LIMIT returns the muxímum number ol eíements thut the vurruy
cun contuín. You specíly the íímít ín the type delínítíon. 1he íímít ís
chunged when usíng TRIM und EXTEND, or when you use ALTER TYPE
to chunge the íímít.
NEXT(n)
Returns the índex ol the eíement ulter n. ßecuuse u nested tubíe cun huve
índívíduuí eíements thut ure empty, NEXT returns the índex ol u non-
empty eíement ulter n. ll there ure no eíements ulter n, NEXT returns nuíí.
PRIOR(n)
Returns the índex ol the eíement belore n. ßecuuse u nested tubíe cun huve
índívíduuí eíements thut ure empty, PRIOR returns the índex ol u non-empty
eíement belore n. ll there ure no eíements belore n, PRIOR returns nuíí.
TRIM
TRIM(n)
Removes eíements lrom the end ol u coííectíon. 1here ure two lorms ol
TRIM:
TRIM removes one eíement lrom the end.
TRIM(n) removes n eíements lrom the end.
TABlf 13-3 íí/SÇí Coíícc|íon \c|hod·

Crucíe Dutubuse ll SQL
Cíven thís conlígurutíon, v_nested_table.COUNT returns 2, the number ol non-empty
eíements.
COUNT ís used ín the get_addresses() und display_addresses() methods ol the
collection_method_examples puckuge. 1he get_addresses() lunctíon returns the
specílíed customer's uddresses lrom customers_with_nested_table, whose id ís pussed
to the lunctíon:
FUNCTION get_addresses(
p_id customers_with_nested_table.id%TYPE
) RETURN t_nested_table_address IS
-- declare object named v_addresses to store the
-- nested table of addresses
v_addresses t_nested_table_address;
BEGIN
-- retrieve the nested table of addresses into v_addresses
SELECT addresses
INTO v_addresses
FROM customers_with_nested_table
WHERE id = p_id;
-- display the number of addresses using v_addresses.COUNT
DBMS_OUTPUT.PUT_LINE(
'Number of addresses = '|| v_addresses.COUNT
);
-- return v_addresses
RETURN v_addresses;
END get_addresses;
1he loííowíng exumpíe sets the server output on und cuíís get_addresses() lor customer rl:
SET SERVEROUTPUT ON
SELECT collection_method_examples.get_addresses(1) addresses
FROM dual;
ADDRESSES(STREET, CITY, STATE, ZIP)
--------------------------------------------------------
T_NESTED_TABLE_ADDRESS(
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345'),
T_ADDRESS('4 Hill Street', 'Lost Town', 'CA', '54321'))
Number of addresses = 2
1he loííowíng display_addresses() procedure uccepts u purumeter numed p_addresses,
whích contuíns u nested tubíe ol uddresses, the procedure díspíuys the number ol uddresses ín p_
addresses usíng COUNT, und then díspíuys those uddresses usíng u íoop:
PROCEDURE display_addresses(
p_addresses t_nested_table_address
) IS
v_count INTEGER;
Chupter l3: Coííectíons
4S1
BEGIN
-- display the number of addresses in p_addresses
DBMS_OUTPUT.PUT_LINE(
'Current number of addresses = '|| p_addresses.COUNT
);
-- display the addresses in p_addresses using a loop
FOR v_count IN 1..p_addresses.COUNT LOOP
DBMS_OUTPUT.PUT_LINE('Address #' || v_count || ':');
DBMS_OUTPUT.PUT(p_addresses(v_count).street || ', ');
DBMS_OUTPUT.PUT(p_addresses(v_count).city || ', ');
DBMS_OUTPUT.PUT(p_addresses(v_count).state || ', ');
DBMS_OUTPUT.PUT_LINE(p_addresses(v_count).zip);
END LOOP;
END display_addresses;
You'íí see the use ol display_addresses() shortíy.
DflfTf()
DELETE removes eíements lrom u coííectíon. 1here ure three lorms ol DELETE:
DELETE removes uíí eíements.
DELETE(n) removes eíement n.
DELETE(n, m) removes eíements n through m.
lor exumpíe, íet's suy you huve u nested tubíe numed v_nested_table thut hus seven
eíements, then v_nested_table.DELETE(2, 5) removes eíements 2 through 5.
1he loííowíng delete_address() procedure gets the uddresses lor customer rl und then
uses DELETE to remove the uddress whose índex ís specílíed by the p_address_num purumeter:
PROCEDURE delete_address(
p_address_num INTEGER
) IS
v_addresses t_nested_table_address;
BEGIN
v_addresses := get_addresses(1);
display_addresses(v_addresses);
DBMS_OUTPUT.PUT_LINE('Deleting address #' || p_address_num);
-- delete the address specified by p_address_num
v_addresses.DELETE(p_address_num);
display_addresses(v_addresses);
END delete_address;
1he loííowíng exumpíe cuíís delete_address(2) to remove uddress r2 lrom customer rl:
CALL collection_method_examples.delete_address(2);
Number of addresses = 2
Current number of addresses = 2
4S2
Crucíe Dutubuse ll SQL
Address #1:
2 State Street, Beantown, MA, 12345
Address #2:
4 Hill Street, Lost Town, CA, 54321
Deleting address #2
Current number of addresses = 1
Address #1:
2 State Street, Beantown, MA, 12345
fXlSTS()
EXISTS(n) returns true íl eíement n ín u coííectíon exísts: EXISTS returns true lor non-empty
eíements, und ít returns luíse lor empty eíements ol nested tubíes or eíements beyond the runge ol
u coííectíon. lor exumpíe, íet's suy you huve u nested tubíe numed v_nested_table thut hus íts
eíements set us shown ín the loííowíng tubíe.
fIcmcnt lndcx fmpty/Nut fmpty
l Lmpty
2 Not empty
3 Lmpty
4 Not empty
Cíven thís conlígurutíon, v_nested_table.EXISTS(2) returns true (becuuse eíement r2
ís not empty), und v_nested_table.EXISTS(3) returns luíse (becuuse eíement r3 ís empty).
1he loííowíng exist_addresses() procedure gets the uddresses lor customer rl, uses
DELETE to remove uddress rl, und then uses EXISTS to check whether uddresses rl und r2
exíst (rl does not exíst becuuse ít hus been deíeted, r2 does exíst):
PROCEDURE exist_addresses IS
v_addresses t_nested_table_address;
BEGIN
v_addresses := get_addresses(1);
DBMS_OUTPUT.PUT_LINE('Deleting address #1');
v_addresses.DELETE(1);
-- use EXISTS to check if the addresses exist
IF v_addresses.EXISTS(1) THEN
DBMS_OUTPUT.PUT_LINE('Address #1 does exist');
ELSE
DBMS_OUTPUT.PUT_LINE('Address #1 does not exist');
END IF;
IF v_addresses.EXISTS(2) THEN
DBMS_OUTPUT.PUT_LINE('Address #2 does exist');
END IF;
END exist_addresses;
1he loííowíng exumpíe cuíís exist_addresses():
CALL collection_method_examples.exist_addresses();
Number of addresses = 2
Chupter l3: Coííectíons
4S3
Deleting address #1
Address #1 does not exist
Address #2 does exist
fXTfND()
EXTEND udds eíements to the end ol u coííectíon. 1here ure three lorms ol EXTEND:
EXTEND udds one eíement, whích ís set to nuíí.
EXTEND(n) udds n eíements, whích ure set to nuíí.
EXTEND(n, m) udds n eíements, whích ure set to u copy ol the m eíement.
lor exumpíe, íet's suy you huve u coííectíon numed v_nested_table thut hus seven
eíements, then v_nested_table.EXTEND(2, 5) udds eíement r5 twíce to the end ol the
coííectíon.
1he loííowíng extend_addresses() procedure gets the uddresses lor customer rl ínto
v_addresses, then uses EXTEND to copy uddress rl twíce to the end ol v_addresses:
PROCEDURE extend_addresses IS
v_addresses t_nested_table_address;
BEGIN
v_addresses := get_addresses(1);
display_addresses(v_addresses);
DBMS_OUTPUT.PUT_LINE('Extending addresses');
-- copy address #1 twice to the end of v_addresses
v_addresses.EXTEND(2, 1);
display_addresses(v_addresses);
END extend_addresses;
1he loííowíng exumpíe cuíís extend_addresses():
CALL collection_method_examples.extend_addresses();
Number of addresses = 2
Current number of addresses = 2
Address #1:
2 State Street, Beantown, MA, 12345
Address #2:
4 Hill Street, Lost Town, CA, 54321
Extending addresses
Current number of addresses = 4
Address #1:
2 State Street, Beantown, MA, 12345
Address #2:
4 Hill Street, Lost Town, CA, 54321
Address #3:
2 State Street, Beantown, MA, 12345
Address #4:
2 State Street, Beantown, MA, 12345
4S4
Crucíe Dutubuse ll SQL
flRST()
You use FIRST to get the índex ol the lírst eíement ín u coííectíon. ll the coííectíon ís compíeteíy
empty, FIRST returns nuíí. ßecuuse u nested tubíe cun huve índívíduuí eíements thut ure empty,
FIRST returns the íowest índex ol u non-empty eíement ín u nested tubíe. lor exumpíe, íet's suy
you huve u nested tubíe numed v_nested_table thut hus íts eíements set us shown ín the
loííowíng tubíe.
fIcmcnt lndcx fmpty/Nut fmpty
l Lmpty
2 Not empty
3 Lmpty
4 Not empty
Cíven thís conlígurutíon, v_nested_table.FIRST returns 2, the íowest índex contuíníng u
non-empty eíement.
1he loííowíng first_address() procedure gets the uddresses lor customer rl ínto v_
addresses und then uses FIRST to díspíuy the índex ol the lírst uddress ín v_addresses, the
procedure then deíetes uddress rl usíng DELETE und díspíuys the new índex returned by FIRST:
PROCEDURE first_address IS
v_addresses t_nested_table_address;
BEGIN
v_addresses := get_addresses(1);
-- display the FIRST address
DBMS_OUTPUT.PUT_LINE('First address = ' || v_addresses.FIRST);
DBMS_OUTPUT.PUT_LINE('Deleting address #1');
v_addresses.DELETE(1);
-- display the FIRST address again
DBMS_OUTPUT.PUT_LINE('First address = ' || v_addresses.FIRST);
END first_address;
1he loííowíng exumpíe cuíís first_address():
CALL collection_method_examples.first_address();
Number of addresses = 2
First address = 1
Deleting address #1
First address = 2
lAST()
LAST returns the índex ol the íust eíement ín u coííectíon. ll the coííectíon ís compíeteíy empty, LAST
returns nuíí. ßecuuse u nested tubíe cun huve índívíduuí eíements thut ure empty, LAST returns the
híghest índex ol u non-empty eíement ín u nested tubíe. lor exumpíe, íet's suy you huve u nested
tubíe numed v_nested_table thut hus íts eíements set us shown ín the loííowíng tubíe.
Chupter l3: Coííectíons
4SS
fIcmcnt lndcx fmpty/Nut fmpty
l Not empty
2 Lmpty
3 Lmpty
4 Not empty
Cíven thís conlígurutíon, v_nested_table.LAST returns 4, the híghest índex contuíníng u
non-empty eíement.
1he loííowíng last_address() procedure gets the uddresses lor customer rl ínto v_
addresses und then uses LAST to díspíuy the índex ol the íust uddress ín v_addresses, the
procedure then deíetes uddress r2 usíng DELETE und díspíuys the new índex returned by LAST:
PROCEDURE last_address IS
v_addresses t_nested_table_address;
BEGIN
v_addresses := get_addresses(1);
-- display the LAST address
DBMS_OUTPUT.PUT_LINE('Last address = ' || v_addresses.LAST);
DBMS_OUTPUT.PUT_LINE('Deleting address #2');
v_addresses.DELETE(2);
-- display the LAST address again
DBMS_OUTPUT.PUT_LINE('Last address = ' || v_addresses.LAST);
END last_address;
1he loííowíng exumpíe cuíís last_address():
CALL collection_method_examples.last_address();
Number of addresses = 2
Last address = 2
Deleting address #2
Last address = 1
NfXT()
NEXT(n) returns the índex ol the eíement ulter n. ßecuuse u nested tubíe cun huve índívíduuí
eíements thut ure empty, NEXT returns the índex ol u non-empty eíement ulter n. ll there ure no
eíements ulter n, NEXT returns nuíí. lor exumpíe, íet's suy you huve u nested tubíe numed v_
nested_table thut hus íts eíements set us shown ín the loííowíng tubíe.
fIcmcnt lndcx fmpty/Nut fmpty
l Not empty
2 Lmpty
3 Lmpty
4 Not empty
4S6
Crucíe Dutubuse ll SQL
Cíven thís conlígurutíon, v_nested_table.NEXT(1) returns 4, the índex contuíníng the
next non-empty eíement, v_nested_table.NEXT(4) returns nuíí.
1he loííowíng next_address() procedure gets the uddresses lor customer rl ínto v_
addresses und then uses NEXT(1) to get the índex ol the uddress ulter uddress rl ín v_
addresses, the procedure then uses NEXT(2) to uttempt to get the índex ol the uddress ulter
uddress r2 (there ísn't one, becuuse customer rl oníy hus two uddresses, so nuíí ís returned):
PROCEDURE next_address IS
v_addresses t_nested_table_address;
BEGIN
v_addresses := get_addresses(1);
-- use NEXT(1) to get the index of the address
-- after address #1
DBMS_OUTPUT.PUT_LINE(
'v_addresses.NEXT(1) = ' || v_addresses.NEXT(1)
);
-- use NEXT(2) to attempt to get the index of
-- the address after address #2 (there isn't one,
-- so null is returned)
DBMS_OUTPUT.PUT_LINE(
'v_addresses.NEXT(2) = ' || v_addresses.NEXT(2)
);
END next_address;
1he loííowíng exumpíe cuíís next_address(), v_addresses.NEXT(2) ís nuíí, und so no
output ís shown ulter the = lor thut eíement:
CALL collection_method_examples.next_address();
Number of addresses = 2
v_addresses.NEXT(1) = 2
v_addresses.NEXT(2) =
PRlOR()
PRIOR(n) returns the índex ol the eíement belore n. ßecuuse u nested tubíe cun huve índívíduuí
eíements thut ure empty, PRIOR returns the índex ol u non-empty eíement belore n. ll there ure
no eíements belore n, PRIOR returns nuíí. lor exumpíe, íet's suy you huve u nested tubíe numed
v_nested_table thut hus íts eíements set us shown ín the loííowíng tubíe.
fIcmcnt lndcx fmpty/Nut fmpty
l Not empty
2 Lmpty
3 Lmpty
4 Not empty
Cíven thís conlígurutíon, v_nested_table.PRIOR(4) returns l, the índex contuíníng the
príor non-empty eíement, v_nested_table.PRIOR(1) returns nuíí.
Chupter l3: Coííectíons
4S7
1he loííowíng prior_address() procedure gets the uddresses lor customer rl ínto v_
addresses und then uses PRIOR(2) to get the índex ol the uddress belore uddress r2 ín v_
addresses, the procedure then uses PRIOR(1) to uttempt to get the índex ol the uddress belore
uddress rl (there ísn't one, so nuíí ís returned):
PROCEDURE prior_address IS
v_addresses t_nested_table_address;
BEGIN
v_addresses := get_addresses(1);
-- use PRIOR(2) to get the index of the address
-- before address #2
DBMS_OUTPUT.PUT_LINE(
'v_addresses.PRIOR(2) = ' || v_addresses.PRIOR(2)
);
-- use PRIOR(1) to attempt to get the index of
-- the address before address #1 (there isn't one,
-- so null is returned)
DBMS_OUTPUT.PUT_LINE(
'v_addresses.PRIOR(1) = ' || v_addresses.PRIOR(1)
);
END prior_address;
1he loííowíng exumpíe cuíís prior_address(), v_addresses.PRIOR(1) ís nuíí, und so
no output ís shown ulter the = lor thut eíement:
CALL collection_method_examples.prior_address();
Number of addresses = 2
v_addresses.PRIOR(2) = 1
v_addresses.PRIOR(1) =
TRlM()
TRIM removes eíements lrom the end ol u coííectíon. 1here ure two lorms ol TRIM:
TRIM removes one eíement lrom the end.
TRIM(n) removes n eíements lrom the end.
lor exumpíe, íet's suy you huve u nested tubíe numed v_nested_table, then v_nested_
table.TRIM(2) removes two eíements lrom the end.
1he loííowíng trim_addresses() procedure gets the uddresses ol customer rl, copíes
uddress rl to the end ol v_addresses three tímes usíng EXTEND(3, 1), und then removes
two uddresses lrom the end ol v_addresses usíng TRIM(2):
PROCEDURE trim_addresses IS
v_addresses t_nested_table_address;
BEGIN
v_addresses := get_addresses(1);
display_addresses(v_addresses);
DBMS_OUTPUT.PUT_LINE('Extending addresses');
4S8
Crucíe Dutubuse llg SQL
v_addresses.EXTEND(3, 1);
display_addresses(v_addresses);
DBMS_OUTPUT.PUT_LINE('Trimming 2 addresses from end');
-- remove 2 addresses from the end of v_addresses
-- using TRIM(2)
v_addresses.TRIM(2);
display_addresses(v_addresses);
END trim_addresses;
1he loííowíng exumpíe cuíís trim_addresses():
CALL collection_method_examples.trim_addresses();
Number of addresses = 2
Current number of addresses = 2
Address #1:
2 State Street, Beantown, MA, 12345
Address #2:
4 Hill Street, Lost Town, CA, 54321
Extending addresses
Current number of addresses = 5
Address #1:
2 State Street, Beantown, MA, 12345
Address #2:
4 Hill Street, Lost Town, CA, 54321
Address #3:
2 State Street, Beantown, MA, 12345
Address #4:
2 State Street, Beantown, MA, 12345
Address #5:
2 State Street, Beantown, MA, 12345
Trimming 2 addresses from end
Current number of addresses = 3
Address #1:
2 State Street, Beantown, MA, 12345
Address #2:
4 Hill Street, Lost Town, CA, 54321
Address #3:
2 State Street, Beantown, MA, 12345
MuItiIcvcI CuIIcctiuns
\íth the reíeuse ol Crucíe Dutubuse 9í, you cun creute u coííectíon ín the dutubuse whose
eíements ure uíso u coííectíon. 1hese ºcoííectíons ol coííectíons¨ ure known us muí|íícvcí
coíícc|íon·. 1he loííowíng ííst shows the vuííd muítííeveí coííectíons:
A nested tubíe ol nested tubíes
A nested tubíe ol vurruys
A vurruy ol vurruys
A vurruy ol nested tubíes
Chupter l3: Coííectíons

l've províded un SQL*líus scrípt numed collection_schema2.sql ín the SQL dírectory.
1hís scrípt creutes u user numed collection_user2, wíth u pussword ol collection_
password, uíong wíth the types und the tubíe shown ín thís sectíon. You cun run thís scrípt íl
you ure usíng Crucíe Dutubuse 9 or hígher. Alter the scrípt compíetes, you wííí be íogged ín us
collection_user2.
Let's suy you wunted to store u set ol phone numbers lor euch uddress ol u customer. 1he
loííowíng exumpíe creutes u vurruy type ol three VARCHAR2 stríngs numed t_varray_phone
to represent phone numbers:
CREATE TYPE t_varray_phone AS VARRAY(3) OF VARCHAR2(14);
/
Next, the loííowíng exumpíe creutes un ob¡ect type numed t_address thut contuíns un
uttríbute numed phone_numbers, thís uttríbute ís ol type t_varray_phone:
CREATE TYPE t_address AS OBJECT (
street VARCHAR2(15),
city VARCHAR2(15),
state CHAR(2),
zip VARCHAR2(5),
phone_numbers t_varray_phone
);
/
1he next exumpíe creutes u nested tubíe type ol t_address ob¡ects:
CREATE TYPE t_nested_table_address AS TABLE OF t_address;
/
1he loííowíng exumpíe creutes u tubíe numed customers_with_nested_table, whích
contuíns u coíumn numed addresses ol type t_nested_table_address:
CREATE TABLE customers_with_nested_table (
id INTEGER PRIMARY KEY,
first_name VARCHAR2(10),
last_name VARCHAR2(10),
addresses t_nested_table_address
)
NESTED TABLE
addresses
STORE AS
nested_addresses;
So, customers_with_nested_table contuíns u nested tubíe whose eíements contuín un
uddress wíth u vurruy ol phone numbers.
1he loííowíng INSERT stutement udds u row to customers_with_nested_table, notíce
the structure und content ol the INSERT stutement, whích contuíns eíements lor the nested tubíe
ol uddresses, euch ol whích hus un embedded vurruy ol phone numbers:
INSERT INTO customers_with_nested_table VALUES (
1, 'Steve', 'Brown',
t_nested_table_address(
t_address('2 State Street', 'Beantown', 'MA', '12345',

Crucíe Dutubuse ll SQL
t_varray_phone(
'(800)-555-1211',
'(800)-555-1212',
'(800)-555-1213'
)
),
t_address('4 Hill Street', 'Lost Town', 'CA', '54321',
t_varray_phone(
'(800)-555-1211',
'(800)-555-1212'
)
)
)
);
You cun see thut the lírst uddress hus three phone numbers, whííe the second uddress hus two.
1he loííowíng query retríeves the row lrom customers_with_nested_table:
SELECT *
FROM customers_with_nested_table;
ID FIRST_NAME LAST_NAME
---------- ---------- ----------
ADDRESSES(STREET, CITY, STATE, ZIP, PHONE_NUMBERS)
------------------------------------------------------------------------
1 Steve Brown
T_NESTED_TABLE_ADDRESS(
T_ADDRESS('2 State Street', 'Beantown', 'MA', '12345',
T_VARRAY_PHONE('(800)-555-1211', '(800)-555-1212', '(800)-555-1213')),
T_ADDRESS('4 Hill Street', 'Lost Town', 'CA', '54321',
T_VARRAY_PHONE('(800)-555-1211', '(800)-555-1212')))
You cun use TABLE() to treut the dutu stored ín the coííectíons us u seríes ol rows, us shown
ín the loííowíng query:
SELECT cn.first_name, cn.last_name, a.street, a.city, a.state, p.*
FROM customers_with_nested_table cn,
TABLE(cn.addresses) a, TABLE(a.phone_numbers) p;
FIRST_NAME LAST_NAME STREET CITY ST COLUMN_VALUE
---------- ---------- --------------- ------------ -- --------------
Steve Brown 2 State Street Beantown MA (800)-555-1211
Steve Brown 2 State Street Beantown MA (800)-555-1212
Steve Brown 2 State Street Beantown MA (800)-555-1213
Steve Brown 4 Hill Street Lost Town CA (800)-555-1211
Steve Brown 4 Hill Street Lost Town CA (800)-555-1212
1he loííowíng UPDATE stutement shows how to updute the phone numbers lor the 2 State
Street uddress, notíce thut TABLE() ís used to get the uddresses us u seríes ol rows und thut u
vurruy contuíníng the new phone numbers ís suppííed ín the SET cíuuse:
Chupter l3: Coííectíons
461
UPDATE TABLE(
-- get the addresses for customer #1
SELECT cn.addresses
FROM customers_with_nested_table cn
WHERE cn.id = 1
) addrs
SET addrs.phone_numbers =
t_varray_phone(
'(800)-555-1214',
'(800)-555-1215'
)
WHERE addrs.street = '2 State Street';
1 row updated.
1he loííowíng query verílíes the chunge:
SELECT cn.first_name, cn.last_name, a.street, a.city, a.state, p.*
FROM customers_with_nested_table cn,
TABLE(cn.addresses) a, TABLE(a.phone_numbers) p;
FIRST_NAME LAST_NAME STREET CITY ST COLUMN_VALUE
---------- ---------- --------------- ------------ -- --------------
Steve Brown 2 State Street Beantown MA (800)-555-1214
Steve Brown 2 State Street Beantown MA (800)-555-1215
Steve Brown 4 Hill Street Lost Town CA (800)-555-1211
Steve Brown 4 Hill Street Lost Town CA (800)-555-1212
Support lor muítííeveí coííectíon types ís u very powerluí extensíon to the Crucíe dutubuse
soltwure, und you míght wunt to consíder usíng them ín uny dutubuse desígns you contríbute to.
OracIc Databasc 10 fnhanccmcnts tu CuIIcctiuns
ln thís sectíon, you'íí íeurn ubout the loííowíng enhuncements mude to coííectíons ín Crucíe
Dutubuse l0:
Support lor ussocíutíve urruys
Abíííty to chunge the síze or precísíon ol un eíement type
Abíííty to íncreuse the number ol eíements ín u vurruy
Abíííty to use vurruy coíumns ín temporury tubíes
Abíííty to use u díllerent tubíespuce lor u nested tubíe's storuge tubíe
ANSl support lor nested tubíes
1he vuríous stutements thut creute the ítems shown ín thís sectíon ure contuíned ín the
collection_schema3.sql scrípt. 1hís scrípt creutes u user numed collection_user3
462
Crucíe Dutubuse ll SQL
wíth u pussword ol collection_password und creutes the coííectíon types, tubíes, und lL/
SQL code. You cun run thís scrípt íl you ure usíng Crucíe Dutubuse l0 or hígher. Alter the scrípt
compíetes, you wííí be íogged ín us collection_user3.
Assuciativc Arrays
An ussocíutíve urruy ís u set ol key und vuíue puírs. You cun get the vuíue lrom the urruy usíng the
key (whích muy be u stríng) or un ínteger thut specílíes the posítíon ol the vuíue ín the urruy. 1he
loííowíng exumpíe procedure numed customers_associative_array() íííustrutes the use
ol ussocíutíve urruys:
CREATE PROCEDURE customers_associative_array AS
-- define an associative array type named t_assoc_array;
-- the value stored in each array element is a NUMBER,
-- and the index key to access each element is a VARCHAR2
TYPE t_assoc_array IS TABLE OF NUMBER INDEX BY VARCHAR2(15);
-- declare an object named v_customer_array of type t_assoc_array;
-- v_customer_array will be used to store the ages of customers
v_customer_array t_assoc_array;
BEGIN
-- assign the values to v_customer_array; the VARCHAR2 key is the
-- customer name and the NUMBER value is the age of the customer
v_customer_array('Jason') := 32;
v_customer_array('Steve') := 28;
v_customer_array('Fred') := 43;
v_customer_array('Cynthia') := 27;
-- display the values stored in v_customer_array
DBMS_OUTPUT.PUT_LINE(
'v_customer_array[''Jason''] = ' || v_customer_array('Jason')
);
DBMS_OUTPUT.PUT_LINE(
'v_customer_array[''Steve''] = ' || v_customer_array('Steve')
);
DBMS_OUTPUT.PUT_LINE(
'v_customer_array[''Fred''] = ' || v_customer_array('Fred')
);
DBMS_OUTPUT.PUT_LINE(
'v_customer_array[''Cynthia''] = ' || v_customer_array('Cynthia')
);
END customers_associative_array;
/
1he loííowíng exumpíe sets the server output on und cuíís customers_associative_
array():
SET SERVEROUTPUT ON
CALL customers_associative_array();
v_customer_array['Jason'] = 32
v_customer_array['Steve'] = 28
v_customer_array['Fred'] = 43
v_customer_array['Cynthia'] = 27
Chupter l3: Coííectíons
463
Changing thc Sizc uf an fIcmcnt Typc
You cun chunge the síze ol un eíement type ín u coííectíon when the eíement type ís one ol the
churucter, numeríc, or ruw types (ruw ís used to store bínury dutu you'íí íeurn ubout thís ín the
next chupter). Lurííer ín thís chupter, you suw the loííowíng stutement thut creutes u vurruy type
numed t_varray_address:
CREATE TYPE t_varray_address AS VARRAY(2) OF VARCHAR2(50);
/
1he loííowíng exumpíe chunges the síze ol the VARCHAR2 eíements ín t_varray_address
to 60:
ALTER TYPE t_varray_address
MODIFY ELEMENT TYPE VARCHAR2(60) CASCADE;
Type altered.
1he CASCADE optíon propugutes the chunge to uny dependent ob¡ects ín the dutubuse,
whích, ín the exumpíe, ís the customers_with_varray tubíe thut contuíns u coíumn numed
addresses ol type t_varray_address. You cun uíso use the INVALIDATE optíon to
ínvuíídute uny dependent ob¡ects und ímmedíuteíy recompííe the lL/SQL code lor the type.
lncrcasing thc Numbcr uf fIcmcnts in a Varray
You cun íncreuse the number ol eíements ín u vurruy. 1he loííowíng exumpíe íncreuses the
number ol eíements ín t_varray_address to 5:
ALTER TYPE t_varray_address
MODIFY LIMIT 5 CASCADE;
Type altered.
Using Varrays in Tcmpurary TabIcs
You cun use vurruys ín temporury tubíes, whích ure tubíes whose rows ure temporury und ure
specílíc to u user sessíon (temporury tubíes were covered ín the sectíon ºCreutíng u 1ubíe¨ ín
Chupter l0). 1he loííowíng exumpíe creutes u temporury tubíe numed cust_with_varray_
temp_table thut contuíns u vurruy numed addresses ol type t_varray_address:
CREATE GLOBAL TEMPORARY TABLE cust_with_varray_temp_table (
id INTEGER PRIMARY KEY,
first_name VARCHAR2(10),
last_name VARCHAR2(10),
addresses t_varray_address
);
Using a Diffcrcnt TabIcspacc fur a Ncstcd TabIc's
Sturagc TabIc
ßy deluuít, u nested tubíe's storuge tubíe ís creuted ín the sume tubíespuce us the purent tubíe
(u tubíespuce ís un ureu used by the dutubuse to store ob¡ects such us tubíessee the sectíon
ºCreutíng u 1ubíe¨ ín Chupter l0 lor detuíís).
464
Crucíe Dutubuse ll SQL
ln Crucíe Dutubuse l0 und hígher, you cun specíly u díllerent tubíespuce lor u nested tubíe's
storuge tubíe. 1he loííowíng exumpíe creutes u tubíe numed cust_with_nested_table thut
contuíns u nested tubíe numed addresses ol type t_nested_table_address, notíce thut the
tubíespuce lor the nested_addresses2 storuge tubíe ís the users tubíespuce:
CREATE TABLE cust_with_nested_table (
id INTEGER PRIMARY KEY,
first_name VARCHAR2(10),
last_name VARCHAR2(10),
addresses t_nested_table_address
)
NESTED TABLE
addresses
STORE AS
nested_addresses2 TABLESPACE users;
You must huve u tubíespuce numed users ín order lor thís exumpíe to work, und lor thís
reuson l've commented out the exumpíe ín the collection_schema3.sql scrípt. You cun
see uíí the tubíespuces you huve uccess to by perlormíng the loííowíng query:
SELECT tablespace_name
FROM user_tablespaces;
TABLESPACE_NAME
---------------
SYSTEM
SYSAUX
UNDOTBS1
TEMP
USERS
EXAMPLE
ll you wunt to run the prevíous CREATE TABLE stutement, you cun edít the exumpíe ín the
collection_schema3.sql scrípt to relerence one ol your tubíespuces und then copy the
stutement ínto SQL*líus und run ít.
ANSl Suppurt fur Ncstcd TabIcs
1he Amerícun Nutíonuí Stundurds lnstítute (ANSl) specílícutíon íncíudes u number ol operutors
thut muy be used wíth nested tubíes. You'íí íeurn ubout these operutors ín the loííowíng sectíons.
fquaI and Nut-fquaI Opcraturs
1he equuí (=) und not-equuí (<>) operutors compure two nested tubíes, whích ure consídered
equuí when they sutísly uíí the loííowíng condítíons:
1he tubíes ure the sume type.
1he tubíes ure the sume curdínuííty, thut ís, they contuín the sume number ol eíements.
Aíí the eíements ol the tubíe huve the sume vuíue.
1he loííowíng equal_example() procedure íííustrutes the use ol the equuí und not-equuí
operutors:
Chupter l3: Coííectíons
46S
CREATE PROCEDURE equal_example AS
-- declare a type named t_nested_table
TYPE t_nested_table IS TABLE OF VARCHAR2(10);
-- create t_nested_table objects named v_customer_nested_table1,
-- v_customer_nested_table2, and v_customer_nested_table3;
-- these objects are used to store the names of customers
v_customer_nested_table1 t_nested_table :=
t_nested_table('Fred', 'George', 'Susan');
v_customer_nested_table2 t_nested_table :=
t_nested_table('Fred', 'George', 'Susan');
v_customer_nested_table3 t_nested_table :=
t_nested_table('John', 'George', 'Susan');
v_result BOOLEAN;
BEGIN
-- use = operator to compare v_customer_nested_table1 with
-- v_customer_nested_table2 (they contain the same names, so
-- v_result is set to true)
v_result := v_customer_nested_table1 = v_customer_nested_table2;
IF v_result THEN
DBMS_OUTPUT.PUT_LINE(
'v_customer_nested_table1 equal to v_customer_nested_table2'
);
END IF;
-- use <> operator to compare v_customer_nested_table1 with
-- v_customer_nested_table3 (they are not equal because the first
-- names, 'Fred' and 'John', are different and v_result is set
-- to true)
v_result := v_customer_nested_table1 <> v_customer_nested_table3;
IF v_result THEN
DBMS_OUTPUT.PUT_LINE(
'v_customer_nested_table1 not equal to v_customer_nested_table3'
);
END IF;
END equal_example;
/
1he loííowíng exumpíe cuíís equal_example():
CALL equal_example();
v_customer_nested_table1 equal to v_customer_nested_table2
v_customer_nested_table1 not equal to v_customer_nested_table3
lN and NOT lN Opcraturs
1he IN operutor checks íl the eíements ol one nested tubíe uppeur ín unother nested tubíe.
Símííuríy, NOT IN checks íl the eíements ol one nested tubíe do not uppeur ín unother nested
tubíe. 1he loííowíng in_example() procedure íííustrutes the use ol IN und NOT IN:
CREATE PROCEDURE in_example AS
TYPE t_nested_table IS TABLE OF VARCHAR2(10);
466
Crucíe Dutubuse ll SQL
v_customer_nested_table1 t_nested_table :=
t_nested_table('Fred', 'George', 'Susan');
v_customer_nested_table2 t_nested_table :=
t_nested_table('John', 'George', 'Susan');
v_customer_nested_table3 t_nested_table :=
t_nested_table('Fred', 'George', 'Susan');
v_result BOOLEAN;
BEGIN
-- use IN operator to check if elements of v_customer_nested_table3
-- are in v_customer_nested_table1 (they are, so v_result is
-- set to true)
v_result := v_customer_nested_table3 IN
(v_customer_nested_table1);
IF v_result THEN
DBMS_OUTPUT.PUT_LINE(
'v_customer_nested_table3 in v_customer_nested_table1'
);
END IF;
-- use NOT IN operator to check if the elements of
-- v_customer_nested_table3 are not in v_customer_nested_table2
-- (they are not, so v_result is set to true)
v_result := v_customer_nested_table3 NOT IN
(v_customer_nested_table2);
IF v_result THEN
DBMS_OUTPUT.PUT_LINE(
'v_customer_nested_table3 not in v_customer_nested_table2'
);
END IF;
END in_example;
/
1he loííowíng exumpíe cuíís in_example():
CALL in_example();
v_customer_nested_table3 in v_customer_nested_table1
v_customer_nested_table3 not in v_customer_nested_table2
SUBMUlTlSfT Opcratur
1he SUBMULTISET operutor checks whether the eíements ol one nested tubíe ure u subset ol
unother nested tubíe. 1he loííowíng submultiset_example() procedure íííustrutes the use
ol SUBMULTISET:
CREATE PROCEDURE submultiset_example AS
TYPE t_nested_table IS TABLE OF VARCHAR2(10);
v_customer_nested_table1 t_nested_table :=
t_nested_table('Fred', 'George', 'Susan');
v_customer_nested_table2 t_nested_table :=
t_nested_table('George', 'Fred', 'Susan', 'John', 'Steve');
v_result BOOLEAN;
BEGIN
Chupter l3: Coííectíons
467
-- use SUBMULTISET operator to check if elements of
-- v_customer_nested_table1 are a subset of v_customer_nested_table2
-- (they are, so v_result is set to true)
v_result :=
v_customer_nested_table1 SUBMULTISET OF v_customer_nested_table2;
IF v_result THEN
DBMS_OUTPUT.PUT_LINE(
'v_customer_nested_table1 subset of v_customer_nested_table2'
);
END IF;
END submultiset_example;
/
1he loííowíng exumpíe cuíís submultiset_example():
CALL submultiset_example();
customer_nested_table1 subset of customer_nested_table2
MUlTlSfT Opcratur
1he MULTISET operutor returns u nested tubíe whose eíements ure set to certuín combínutíons ol
eíements lrom two suppííed nested tubíes. 1here ure three MULTISET operutors:
MULTISET UNION returns u nested tubíe whose eíements ure set to the sum ol the
eíements lrom two suppííed nested tubíes.
MULTISET INTERSECT returns u nested tubíe whose eíements ure set to the eíements
thut ure common to two suppííed nested tubíes.
MULTISET EXCEPT returns u nested tubíe whose eíements ure ín the lírst suppííed
nested tubíe but not ín the second.
You muy uíso use one ol the loííowíng optíons wíth MULTISET:
ALL índícutes thut uíí the uppíícubíe eíements ure ín the returned nested tubíe. ALL ís the
deluuít. lor exumpíe, MULTISET UNION ALL returns u nested tubíe whose eíements ure
set to the sum ol eíements lrom two suppííed nested tubíes, und uíí eíements, íncíudíng
dupíícutes, ure ín the returned nested tubíe.
DISTINCT índícutes thut oníy the non-dupíícute (thut ís, dístínct) eíements ure ín the
returned nested tubíe. lor exumpíe, MULTISET UNION DISTINCT returns u nested
tubíe whose eíements ure set to the sum ol eíements lrom two suppííed nested tubíes,
but dupíícutes ure removed lrom the returned nested tubíe.
1he loííowíng multiset_example() procedure íííustrutes the use ol MULTISET:
CREATE PROCEDURE multiset_example AS
TYPE t_nested_table IS TABLE OF VARCHAR2(10);
v_customer_nested_table1 t_nested_table :=
t_nested_table('Fred', 'George', 'Susan');
v_customer_nested_table2 t_nested_table :=
t_nested_table('George', 'Steve', 'Rob');
v_customer_nested_table3 t_nested_table;

Crucíe Dutubuse ll SQL
v_count INTEGER;
BEGIN
-- use MULTISET UNION (returns a nested table whose elements
-- are set to the sum of the two supplied nested tables)
v_customer_nested_table3 :=
v_customer_nested_table1 MULTISET UNION
v_customer_nested_table2;
DBMS_OUTPUT.PUT('UNION: ');
FOR v_count IN 1..v_customer_nested_table3.COUNT LOOP
DBMS_OUTPUT.PUT(v_customer_nested_table3(v_count) || ' ');
END LOOP;
DBMS_OUTPUT.PUT_LINE(' ');
-- use MULTISET UNION DISTINCT (DISTINCT indicates that only
-- the non-duplicate elements of the two supplied nested tables
-- are set in the returned nested table)
v_customer_nested_table3 :=
v_customer_nested_table1 MULTISET UNION DISTINCT
v_customer_nested_table2;
DBMS_OUTPUT.PUT('UNION DISTINCT: ');
FOR v_count IN 1..v_customer_nested_table3.COUNT LOOP
DBMS_OUTPUT.PUT(v_customer_nested_table3(v_count) || ' ');
END LOOP;
DBMS_OUTPUT.PUT_LINE(' ');
-- use MULTISET INTERSECT (returns a nested table whose elements
-- are set to the elements that are common to the two supplied
-- nested tables)
v_customer_nested_table3 :=
v_customer_nested_table1 MULTISET INTERSECT
v_customer_nested_table2;
DBMS_OUTPUT.PUT('INTERSECT: ');
FOR v_count IN 1..v_customer_nested_table3.COUNT LOOP
DBMS_OUTPUT.PUT(v_customer_nested_table3(v_count) || ' ');
END LOOP;
DBMS_OUTPUT.PUT_LINE(' ');
-- use MULTISET EXCEPT (returns a nested table whose
-- elements are in the first nested table but not in
-- the second)
v_customer_nested_table3 :=
v_customer_nested_table1 MULTISET EXCEPT
v_customer_nested_table2;
DBMS_OUTPUT.PUT_LINE('EXCEPT: ');
FOR v_count IN 1..v_customer_nested_table3.COUNT LOOP
DBMS_OUTPUT.PUT(v_customer_nested_table3(v_count) || ' ');
END LOOP;
END multiset_example;
/
Chupter l3: Coííectíons
469
1he loííowíng exumpíe cuíís multiset_example():
CALL multiset_example();
UNION: Fred George Susan George Steve Rob
UNION DISTINCT: Fred George Susan Steve Rob
INTERSECT: George
EXCEPT:
CARDlNAllTY() functiun
1he CARDINALITY() lunctíon returns the number ol eíements ín u coííectíon. 1he loííowíng
cardinality_example() procedure íííustrutes the use ol CARDINALITY():
CREATE PROCEDURE cardinality_example AS
TYPE t_nested_table IS TABLE OF VARCHAR2(10);
v_customer_nested_table1 t_nested_table :=
t_nested_table('Fred', 'George', 'Susan');
v_cardinality INTEGER;
BEGIN
-- call CARDINALITY() to get the number of elements in
-- v_customer_nested_table1
v_cardinality := CARDINALITY(v_customer_nested_table1);
DBMS_OUTPUT.PUT_LINE('v_cardinality = ' || v_cardinality);
END cardinality_example;
/
1he loííowíng exumpíe cuíís cardinality_example():
CALL cardinality_example();
v_cardinality = 3
MfMBfR Of Opcratur
1he MEMBER OF operutor checks whether un eíement ís ín u nested tubíe. 1he loííowíng
member_of_example() procedure íííustrutes the use ol MEMBER OF:
CREATE PROCEDURE member_of_example AS
TYPE t_nested_table IS TABLE OF VARCHAR2(10);
v_customer_nested_table1 t_nested_table :=
t_nested_table('Fred', 'George', 'Susan');
v_result BOOLEAN;
BEGIN
-- use MEMBER OF to check if 'George' is in
-- v_customer_nested_table1 (he is, so v_result is set
-- to true)
v_result := 'George' MEMBER OF v_customer_nested_table1;
IF v_result THEN
DBMS_OUTPUT.PUT_LINE('''George'' is a member');
END IF;
END member_of_example;
/
470
Crucíe Dutubuse ll SQL
1he loííowíng exumpíe cuíís member_of_example():
CALL member_of_example();
'George' is a member
SfT() functiun
1he SET() lunctíon lírst converts u nested tubíe ínto u set, then removes dupíícute eíements lrom
the set, und línuííy returns the set us u nested tubíe. 1he loííowíng set_example() procedure
íííustrutes the use ol SET():
CREATE PROCEDURE set_example AS
TYPE t_nested_table IS TABLE OF VARCHAR2(10);
v_customer_nested_table1 t_nested_table :=
t_nested_table('Fred', 'George', 'Susan', 'George');
v_customer_nested_table2 t_nested_table;
v_count INTEGER;
BEGIN
-- call SET() to convert a nested table into a set,
-- remove duplicate elements from the set, and get the set
-- as a nested table
v_customer_nested_table2 := SET(v_customer_nested_table1);
DBMS_OUTPUT.PUT('v_customer_nested_table2: ');
FOR v_count IN 1..v_customer_nested_table2.COUNT LOOP
DBMS_OUTPUT.PUT(v_customer_nested_table2(v_count) || ' ');
END LOOP;
DBMS_OUTPUT.PUT_LINE(' ');
END set_example;
/
1he loííowíng exumpíe cuíís set_example():
CALL set_example();
v_customer_nested_table2: Fred George Susan
lS A SfT Opcratur
1he IS A SET operutor checks íl the eíements ín u nested tubíe ure dístínct. 1he loííowíng is_
a_set_example() procedure íííustrutes the use ol IS A SET:
CREATE PROCEDURE is_a_set_example AS
TYPE t_nested_table IS TABLE OF VARCHAR2(10);
v_customer_nested_table1 t_nested_table :=
t_nested_table('Fred', 'George', 'Susan', 'George');
v_result BOOLEAN;
BEGIN
-- use IS A SET operator to check if the elements in
-- v_customer_nested_table1 are distinct (they are not, so
-- v_result is set to false)
v_result := v_customer_nested_table1 IS A SET;
IF v_result THEN
DBMS_OUTPUT.PUT_LINE('Elements are all unique');
ELSE
DBMS_OUTPUT.PUT_LINE('Elements contain duplicates');
END IF;
Chupter l3: Coííectíons
471
END is_a_set_example;
/
1he loííowíng exumpíe cuíís is_a_set_example():
CALL is_a_set_example();
Elements contain duplicates
lS fMPTY Opcratur
1he IS EMPTY operutor checks íl u nested tubíe doesn't contuín eíements. 1he loííowíng is_
empty_example() procedure íííustrutes the use ol IS EMPTY:
CREATE PROCEDURE is_empty_example AS
TYPE t_nested_table IS TABLE OF VARCHAR2(10);
v_customer_nested_table1 t_nested_table :=
t_nested_table('Fred', 'George', 'Susan');
v_result BOOLEAN;
BEGIN
-- use IS EMPTY operator to check if
-- v_customer_nested_table1 is empty (it is not, so
-- v_result is set to false)
v_result := v_customer_nested_table1 IS EMPTY;
IF v_result THEN
DBMS_OUTPUT.PUT_LINE('Nested table is empty');
ELSE
DBMS_OUTPUT.PUT_LINE('Nested table contains elements');
END IF;
END is_empty_example;
/
1he loííowíng exumpíe cuíís is_empty_example():
CALL is_empty_example();
Nested table contains elements
COllfCT() functiun
1he COLLECT() lunctíon returns u nested tubíe lrom u set ol eíements. 1he loííowíng query
íííustrutes the use ol COLLECT():
SELECT COLLECT(first_name)
FROM customers_with_varray;
COLLECT(FIRST_NAME)
----------------------------------------------
SYSTPfrFhAg+WRJGwW7ma9zy1KA==('Steve', 'John')
You cun use CAST() to convert the eíements returned by COLLECT() to u specílíc type, us
shown ín the loííowíng query:
SELECT CAST(COLLECT(first_name) AS t_table)
FROM customers_with_varray;
CAST(COLLECT(FIRST_NAME)AST_TABLE)
----------------------------------
T_TABLE('Steve', 'John')
472
Crucíe Dutubuse ll SQL
lor your relerence, the t_table type used ín the prevíous exumpíe ís creuted by the
loííowíng stutement ín the collection_schema3.sql scrípt:
CREATE TYPE t_table AS TABLE OF VARCHAR2(10);
/
POWfRMUlTlSfT() functiun
1he POWERMULTISET() lunctíon returns uíí combínutíons ol eíements ín u gíven nested tubíe, us
shown ín the loííowíng query:
SELECT *
FROM TABLE(
POWERMULTISET(t_table('This', 'is', 'a', 'test'))
);
COLUMN_VALUE
----------------------------------
T_TABLE('This')
T_TABLE('is')
T_TABLE('This', 'is')
T_TABLE('a')
T_TABLE('This', 'a')
T_TABLE('is', 'a')
T_TABLE('This', 'is', 'a')
T_TABLE('test')
T_TABLE('This', 'test')
T_TABLE('is', 'test')
T_TABLE('This', 'is', 'test')
T_TABLE('a', 'test')
T_TABLE('This', 'a', 'test')
T_TABLE('is', 'a', 'test')
T_TABLE('This', 'is', 'a', 'test')
POWfRMUlTlSfT_BY_CARDlNAllTY() functiun
1he POWERMULTISET_BY_CARDINALITY() lunctíon returns the combínutíons ol eíements ín u
gíven nested tubíe thut huve u specílíed number ol eíements (or ºcurdínuííty¨). 1he loííowíng query
íííustrutes the use ol POWERMULTISET_BY_CARDINALITY(), specílyíng u curdínuííty ol 3:
SELECT *
FROM TABLE(
POWERMULTISET_BY_CARDINALITY(
t_table('This', 'is', 'a', 'test'), 3
)
);
COLUMN_VALUE
-----------------------------
T_TABLE('This', 'is', 'a')
T_TABLE('This', 'is', 'test')
T_TABLE('This', 'a', 'test')
T_TABLE('is', 'a', 'test')
Chupter l3: Coííectíons
473
Summary
ln thís chupter, you huve íeurned the loííowíng:
Coííectíons uííow you to store sets ol eíements.
1here ure three types ol coííectíons: vurruys, nested tubíes, und ussocíutíve urruys.
A vurruy ís símííur to un urruy ín }uvu, you cun use u vurruy to store un ordered set ol
eíements wíth euch eíement huvíng un índex ussocíuted wíth ít. 1he eíements ín u vurruy
ure ol the sume type, und u vurruy hus one dímensíon. A vurruy hus u muxímum síze thut
you set when creutíng ít, but you cun chunge the síze íuter.
A nested tubíe ís u tubíe thut ís embedded wíthín unother tubíe, und you cun ínsert,
updute, und deíete índívíduuí eíements ín u nested tubíe. ßecuuse you cun modíly
índívíduuí eíements ín u nested tubíe, they ure more líexíbíe thun u vurruyu vurruy
cun be modílíed oníy us u whoíe. A nested tubíe doesn't huve u muxímum síze, und
you cun store un urbítrury number ol eíements ín u nested tubíe.
An ussocíutíve urruy ís u set ol key und vuíue puírs. You cun get the vuíue lrom the urruy
usíng the key (whích muy be u stríng) or un ínteger thut specílíes the posítíon ol the vuíue
ín the urruy. An ussocíutíve urruy ís símííur to u hush tubíe ín progrummíng íunguuges
such us }uvu.
A coííectíon muy ítseíl contuín embedded coííectíons. Such u coííectíon ís known us u
muítííeveí coííectíon.
ln the next chupter, you'íí íeurn ubout íurge ob¡ects.
This page intentionally left blank
\IAI1II
14
Lurge Cb¡ects
475
476
Crucíe Dutubuse llg SQL
n thís chupter, you wííí do the loííowíng:
Leurn ubout íurge ob¡ects (LCßs)
See lííes whose content wííí be used to popuíute exumpíe LCßs
Lxumíne the díllerences between the díllerent types ol LCßs
Creute tubíes contuíníng LCßs
Lse LCßs ín SQL und lL/SQL
Lxumíne the LONG und LONG RAW types
See the Crucíe Dutubuse l0g und llg enhuncements to LCßs
lntruducing largc Objccts (lOBs)
1oduy's websítes demund more thun ¡ust the storuge und retríevuí ol text und numbers: they uíso
requíre muítímedíu. Consequentíy, dutubuses ure now beíng cuííed upon to store ítems ííke musíc
und vídeo. lríor to the reíeuse ol Crucíe Dutubuse 8, you hud to store íurge bíocks ol churucter
dutu usíng the LONG dutubuse type, und íurge bíocks ol bínury dutu hud to be stored usíng eíther
the LONG RAW type or the shorter RAW type.
\íth the reíeuse Crucíe Dutubuse 8, u new cíuss ol dutubuse types known us íargc ob]cc|s,
or LCßs lor short, wus íntroduced. LCßs muy be used to store bínury dutu, churucter dutu, und
relerences to lííes. 1he bínury dutu cun contuín ímuges, musíc, vídeo, documents, executubíes,
und so on. LCßs cun store up to l28 terubytes ol dutu, dependíng on the dutubuse conlígurutíon.
Thc fxampIc fiIcs
You'íí see the use ol the loííowíng two lííes ín thís chupter:
textContent.txt A text lííe
binaryContent.doc A Mícrosolt \ord lííe
NOTf
Thc·c |ííc· arc con|aíncd ín |hc sample_files dírcc|or,, vhích
í· crca|cd vhcn ,ou cx|rac| |hc Zíp |ííc |or |hí· boo|. í| ,ou van| |o
|oííov aíong ví|h |hc cxampíc·, ,ou ·houíd cop, |hc sample_files
dírcc|or, |o |hc C par|í|íon on ,our da|aba·c ·crvcr. í| ,ou'rc u·íng
íínux or Lníx, ,ou can cop, |hc dírcc|or, |o onc o| ,our par|í|íon·.

Chupter l4: Lurge Cb¡ects
477
1he lííe textContent.txt contuíns un extruct lrom Shukespeure's píuy \acbc|h. 1he
loííowíng text ís the speech mude by Mucbeth shortíy belore he ís kíííed:
1o-morrow, und to-morrow, und to-morrow,
Creeps ín thís petty puce lrom duy to duy,
1o the íust syííubíe ol recorded tíme,
And uíí our yesterduys huve ííghted looís
1he wuy to u dusty deuth. Cut, out, bríel cundíe!
Líle's but u wuíkíng shudow, u poor píuyer,
1hut struts und lrets hís hour upon the stuge,
And then ís heurd no more: ít ís u tuíe
1oíd by un ídíot, luíí ol sound und lury,
Sígnílyíng nothíng.
1he binaryContent.doc lííe ís u \ord document thut contuíns the sume text us
textContent.txt. (A \ord document ís u bínury lííe.) Aíthough u \ord document ís used
ín the exumpíes, you cun use uny bínury lííe, lor exumpíe, Ml3, DívX, }lLC, MlLC, lDl, or
LXL. l huve tested the exumpíes wíth uíí these types ol lííes.
largc Objcct Typcs
1here ure lour LCß types:
CLOB 1he churucter LCß type, whích ís used to store churucter dutu.
NCLOB 1he Nutíonuí Churucter Set LCß type, whích ís used to store muítípíe byte
churucter dutu (typícuííy used lor non-Lngíísh churucters). You cun íeurn uíí ubout non-
Lngíísh churucter sets ín the Cracíc Da|aba·c Cíobaíí2a|íon Suppor| Cuídc pubííshed
by Crucíe Corporutíon.
BLOB 1he bínury LCß type, whích ís used to store bínury dutu.
BFILE 1he bínury llLL type, whích ís used to store u poínter to u lííe. 1he lííe cun be
on u hurd dísk, CD, DVD, ßíu-Ruy dísk, HD-DVD, or uny other devíce thut ís uccessíbíe
through the dutubuse server's lííe system. 1he lííe ítseíl ís never stored ín the dutubuse,
oníy u poínter to the lííe.
lríor to Crucíe Dutubuse 8 your oníy choíce lor storíng íurge umounts ol dutu wus to use the
LONG und LONG RAW types (you couíd uíso use the RAW type lor storíng bínury dutu ol íess thun
4 kííobytes ín síze). 1he LCß types huve three udvuntuges over these oíder types:
A LCß cun store up to l28 terubytes ol dutu. 1hís ís lur more dutu thun you cun store ín
u LONG und LONG RAW coíumn, whích muy oníy store up to 2 gígubytes ol dutu.
A tubíe cun huve muítípíe LCß coíumns, but u tubíe cun oníy huve one LONG or LONG
RAW coíumn.
LCß dutu cun be uccessed ín rundom order, LONG und LONG RAW dutu cun be uccessed
oníy ín sequentíuí order.
478
Crucíe Dutubuse ll SQL
A LCß consísts ol two purts:
Thc lOB Iucatur A poínter thut specílíes the íocutíon ol the LCß dutu
Thc lOB data 1he uctuuí churucter or byte dutu stored ín the LCß
Dependíng on the umount ol dutu stored ín u CLOB, NCLOB or BLOB coíumn, the dutu wííí be
stored eíther ínsíde or outsíde ol the tubíe. ll the dutu ís íess thun 4 kííobytes, the dutu ís stored ín
the sume tubíe, otherwíse, the dutu ís stored outsíde the tubíe. \íth u BFILE coíumn, oníy the
íocutor ís stored ín the tubíeund the íocutor poínts to un externuí lííe stored ín the lííe system.
Crcating TabIcs Cuntaining largc Objccts
You'íí see the use ol the loííowíng three tubíes ín thís sectíon:
1he clob_content tubíe, whích contuíns u CLOB coíumn numed clob_column
1he blob_content tubíe, whích contuíns u BLOB coíumn numed blob_column
1he bfile_content tubíe, whích contuíns u BFILE coíumn numed bfile_column
l've províded un SQL*líus scrípt numed lob_schema.sql ín the SQL dírectory. 1hís scrípt
muy be run usíng Crucíe Dutubuse 8 und hígher. 1he scrípt creutes u user numed lob_user wíth
u pussword ol lob_password, und ít creutes the tubíes und lL/SQL code used ín the lírst purt ol
thís chupter. Alter the scrípt compíetes, you wííí be íogged ín us lob_user.
1he three tubíes ure creuted usíng the loííowíng stutements ín the scrípt:
CREATE TABLE clob_content (
id INTEGER PRIMARY KEY,
clob_column CLOB NOT NULL
);
CREATE TABLE blob_content (
id INTEGER PRIMARY KEY,
blob_column BLOB NOT NULL
);
CREATE TABLE bfile_content (
id INTEGER PRIMARY KEY,
bfile_column BFILE NOT NULL
);
Using largc Objccts in SQl
ln thís sectíon, you'íí íeurn how to use SQL to munípuíute íurge ob¡ects. You'íí sturt by exumíníng
CLOB und BLOB ob¡ects und then move on to BFILE ob¡ects.
Using ClOBs and BlOBs
1he loííowíng sectíons show how to popuíute CLOB und BLOB ob¡ects wíth dutu, retríeve the
dutu, und then modíly the dutu.
Chupter l4: Lurge Cb¡ects
479
PupuIating ClOBs and BlOBs with Data
1he loííowíng INSERT stutements udd two rows to the clob_content tubíe, notíce the use ol
the TO_CLOB() lunctíon to convert the text to u CLOB:
INSERT INTO clob_content (
id, clob_column
) VALUES (
1, TO_CLOB('Creeps in this petty pace')
);
INSERT INTO clob_content (
id, clob_column
) VALUES (
2, TO_CLOB(' from day to day')
);
1he loííowíng INSERT stutements udd two rows to the blob_content tubíe, notíce the
use ol the TO_BLOB() lunctíon to convert the numbers to u BLOB (the lírst stutement contuíns
u bínury number, und the second contuíns u hexudecímuí number):
INSERT INTO blob_content (
id, blob_column
) VALUES (
1, TO_BLOB('100111010101011111')
);
INSERT INTO blob_content (
id, blob_column
) VALUES (
2, TO_BLOB('A0FFB71CF90DE')
);
Rctricving Data frum ClOBs
1he loííowíng query retríeves the rows lrom the clob_content tubíe:
SELECT *
FROM clob_content;
ID
----------
CLOB_COLUMN
-------------------------
1
Creeps in this petty pace
2
from day to day
1he next query uttempts to retríeve the row lrom the blob_content tubíe und luíís:
SELECT *
FROM blob_content;
SP2-0678: Column or attribute type can not be displayed by SQL*Plus
480
Crucíe Dutubuse ll SQL
1hís exumpíe luíís becuuse SQL*líus cunnot díspíuy the bínury dutu ín u BLOB. You'íí íeurn how
to retríeve the dutu lrom u BLOB íuter ín the sectíon ºLsíng Lurge Cb¡ects ín lL/SQL.¨
You cun, however, get the non-BLOB coíumns lrom the tubíe:
SELECT id
FROM blob_content;
ID
----------
1
2
Mudifying thc Data in ClOBs and BlOBs
You shouíd leeí lree to run the UPDATE und INSERT stutements shown ín thís sectíon. 1he
loííowíng UPDATE stutements show how you modíly the contents ol u CLOB und u BLOB:
UPDATE clob_content
SET clob_column = TO_CLOB('What light through yonder window breaks')
WHERE id = 1;
UPDATE blob_content
SET blob_column = TO_BLOB('1110011010101011111')
WHERE id = 1;
You cun uíso ínítíuííze the LCß íocutor, but not store uctuuí dutu ín the LCß. You do thís usíng the
EMPTY_CLOB() lunctíon to store un empty CLOB, und EMPTY_BLOB() to store un empty BLOB:
INSERT INTO clob_content(
id, clob_column
) VALUES (
3, EMPTY_CLOB()
);
INSERT INTO blob_content(
id, blob_column
) VALUES (
3, EMPTY_BLOB()
);
1hese stutements ínítíuííze the LCß íocutor, but set the LCß dutu to empty.
You cun uíso use EMPTY_CLOB() und EMPTY_BLOB() ín UPDATE stutements when you
wunt to empty out the LCß dutu. lor exumpíe:
UPDATE clob_content
SET clob_column = EMPTY_CLOB()
WHERE id = 1;
UPDATE blob_content
SET blob_column = EMPTY_BLOB()
WHERE id = 1;
Chupter l4: Lurge Cb¡ects
481
ll you run uny ol the INSERT und UPDATE stutements shown ín thís sectíon, go uheud und roíí
buck the chunges so thut your output mutches míne ín the rest ol thís chupter:
ROLLBACK;
Using Bfllfs
A BFILE stores u poínter to u lííe thut ís uccessíbíe through the dutubuse server's lííe system. 1he
ímportunt poínt to remember ís thut these lííes ure stored outsíde ol the dutubuse. A BFILE cun
poínt to lííes íocuted on uny medíu: u hurd dísk, CD, DVD, ßíu-Ruy, HD-DVD, und so on.
NOTf
A BFILE con|aín· a poín|cr |o an cx|crnaí |ííc. Thc ac|uaí |ííc í|·cí| í·
never ·|orcd ín |hc da|aba·c, oní, a poín|cr |o |ha| |ííc í· ·|orcd. Thc
|ííc mu·| bc accc··íbíc |hrough |hc da|aba·c ·crvcr'· |ííc ·,·|cm.
Crcating a Dircctury Objcct
ßelore you cun store u poínter to u lííe ín u BFILE, you must lírst creute u dírectory ob¡ect ín the
dutubuse. 1he dírectory ob¡ect stores the dírectory ín the lííe system where the lííes ure íocuted.
You creute u dírectory ob¡ect usíng the CREATE DIRECTORY stutement, und to run thís stutement
you must huve the CREATE ANY DIRECTORY dutubuse prívííege.
1he loííowíng exumpíe (contuíned ín lob_schema.sql) creutes u dírectory ob¡ect numed
SAMPLE_FILES_DIR lor the lííe system dírectory C:\sample_files:
CREATE DIRECTORY SAMPLE_FILES_DIR AS 'C:\sample_files';
NOTf
Víndov· u·c· |hc bac|·ía·h charac|cr (\) ín dírcc|oríc·, vhííc íínux
and Lníx u·c |hc |orvard ·ía·h charac|cr (/). Aí·o, í| ,our sample_
files dírcc|or, í· no| ·|orcd ín |hc C par|í|íon, |hcn ,ou nccd |o
·pccí|, |hc appropría|c pa|h ín |hc prcvíou· cxampíc.
\hen you creute u dírectory ob¡ect you must ensure thut
1he uctuuí dírectory exísts ín the lííe system.
1he user uccount ín the operutíng system thut wus used to ínstuíí the Crucíe soltwure hus
reud permíssíon on the dírectory und on uny lííes thut ure to be poínted to by u BFILE ín
the dutubuse.
ll you're usíng \índows, you shouídn't need to worry ubout the second poínt. 1he Crucíe
dutubuse soltwure shouíd huve been ínstuííed usíng u user uccount thut hus udmínístrutor
prívííeges, und such u user uccount hus reud permíssíon on everythíng ín the lííe system. ll you're
usíng Línux or Lníx, you'íí need to grunt reud uccess to the uppropríute Crucíe user uccount thut
owns the dutubuse (you do thís usíng the chmod commund).
482
Crucíe Dutubuse llg SQL
PupuIating a Bfllf CuIumn with a Puintcr tu a fiIc
ßecuuse u BFILE ís ¡ust u poínter to un externuí lííe, popuíutíng u BFILE coíumn ís very símpíe.
Aíí you huve to do ís to use the Crucíe dutubuse's BFILENAME() lunctíon to popuíute u BFILE
wíth u poínter to your externuí lííe. 1he BFILENAME() lunctíon uccepts two purumeters: the
dírectory ob¡ect's nume und the nume ol the lííe.
lor exumpíe, the loííowíng INSERT udds u row to the bfile_content tubíe, notíce
thut the BFILENAME() lunctíon ís used to popuíute bfile_column wíth u poínter to the
textContent.txt lííe:
INSERT INTO bfile_content (
id, bfile_column
) VALUES (
1, BFILENAME('SAMPLE_FILES_DIR', 'textContent.txt')
);
1he next INSERT udds u row to the bfile_content tubíe, notíce thut the BFILENAME()
lunctíon ís used to popuíute bfile_column wíth u poínter to the binaryContent.doc lííe:
INSERT INTO bfile_content (
id, bfile_column
) VALUES (
2, BFILENAME('SAMPLE_FILES_DIR', 'binaryContent.doc')
);
1he loííowíng query uttempts to retríeve the rows lrom bfile_content und luíís becuuse
SQL*líus cunnot díspíuy the content ín u BFILE:
SELECT *
FROM bfile_content;
SP2-0678: Column or attribute type can not be displayed by SQL*Plus
You muy use lL/SQL to uccess the content ín u BFILE or u BLOB, und you'íí íeurn how to do
thut next.
Using largc Objccts in Pl/SQl
ln thís sectíon, you'íí íeurn how to use LCßs ín lL/SQL. You'íí sturt oll by exumíníng the methods
ín the DBMS_LOB puckuge, whích comes wíth the dutubuse. Luter, you'íí see píenty ol lL/SQL
progrums thut show how to use the DBMS_LOB methods to reud dutu ín u LCß, copy dutu lrom
one LCß to unother, seurch dutu ín u LCß, copy dutu lrom u lííe to u LCß, copy dutu lrom u LCß
to u lííe, und much more.
1ubíe l4-l summurízes the most commoníy used methods ín the DBMS_LOB puckuge.
ln the loííowíng sectíons, you'íí see the detuíís ol some ol the methods shown ín the prevíous
tubíe. You cun see uíí the DBMS_LOB methods ín the Cracíc Da|aba·c íí/SÇí íac|agc· and
T,pc· Rc|crcncc munuuí pubííshed by Crucíe Corporutíon.
Chupter l4: Lurge Cb¡ects
483
Mcthud Dcscriptiun
APPEND(dest_lob, src_lob) Adds the dutu reud lrom src_lob to the end ol dest_lob.
CLOSE(lob) Cíoses u prevíousíy opened LCß.
COMPARE(lob1, lob2, amount,
offset1, offset2)
Compures the dutu stored ín lob1 und lob2, sturtíng ut offset1 ín
lob1 und offset2 ín lob2. Cllsets uíwuys sturt ut l, whích ís the
posítíon ol the lírst churucter or byte ín the dutu.
1he dutu ín the LCßs ure compured over u muxímum number ol
churucters or bytes (the muxímum ís specílíed ín amount).
CONVERTTOBLOB(dest_blob, src_clob,
amount, dest_offset, src_offset,
blob_csid, lang_context, warning)
Converts the churucter dutu reud lrom src_clob ínto bínury dutu
wrítten to dest_blob.
1he reud begíns ut src_offset ín src_clob, und the wríte begíns
ut dest_offset ín dest_blob.
blob_csid ís the desíred churucter set lor the converted dutu wrítten
to dest_blob. You shouíd typícuííy use DBMS_LOB.DEFAULT_
CSID, whích ís the deluuít churucter set lor the dutubuse.
lang_context ís the íunguuge context to use when convertíng the
churucters reud lrom src_clob. You shouíd typícuííy use DBMS_
LOB.DEFAULT_LANG_CTX, whích ís the deluuít íunguuge context lor
the dutubuse.
warning ís set to DBMS_LOB.WARN_INCONVERTIBLE_CHAR íl
there wus u churucter thut couíd not be converted.
CONVERTTOCLOB(dest_clob, src_blob,
amount, dest_offset, src_offset,
blob_csid, lang_context, warning)
Converts the bínury dutu reud lrom src_blob ínto churucter dutu
wrítten to dest_clob.
blob_csid ís the churucter set lor the dutu reud lrom dest_blob.
You shouíd typícuííy use DBMS_LOB.DEFAULT_CSID.
lang_context ís the íunguuge context to use when wrítíng the
converted churucters to dest_clob. You shouíd typícuííy use DBMS_
LOB.DEFAULT_LANG_CTX.
warning ís set to DBMS_LOB.WARN_INCONVERTIBLE_CHAR íl
there wus u churucter thut couíd not be converted.
COPY(dest_lob, src_lob, amount,
dest_offset, src_offset)
Copíes dutu lrom src_lob to dest_lob, sturtíng ut the ollsets lor u
totuí umount ol churucters or bytes.
CREATETEMPORARY(lob, cache,
duration)
Creutes u temporury LCß ín the user's deluuít temporury tubíespuce.
ERASE(lob, amount, offset) Lruses dutu lrom u LCß, sturtíng ut the ollset lor u totuí umount ol
churucters or bytes.
FILECLOSE(bfile) Cíoses bfile. You shouíd use the newer CLOSE() method ínsteud ol
FILECLOSE().
FILECLOSEALL() Cíoses uíí prevíousíy opened BFILEs.
FILEEXISTS(bfile)
Checks íl the externuí lííe poínted to by bfile uctuuííy exísts.
FILEGETNAME(bfile, directory,
filename)
Returns the dírectory und lííenume ol the externuí lííe poínted to by
bfile.
FILEISOPEN(bfile)
Checks íl bfile ís currentíy open. You shouíd use the newer
ISOPEN() method ínsteud ol FILEISOPEN().
FILEOPEN(bfile, open_mode) Cpens bfile ín the índícuted mode, whích cun be set oníy to
DBMS_LOB.FILE_READONLY, whích índícutes the lííe muy oníy be
reud lrom (und never wrítten to). You shouíd use the newer OPEN()
method ínsteud ol FILEOPEN().
TABlf 14-1 DBMS_LOB
484
Crucíe Dutubuse llg SQL
Mcthud Dcscriptiun
FREETEMPORARY(lob)
lrees u temporury LCß.
GETCHUNKSIZE(lob) Returns the chunk síze used when reudíng und wrítíng the dutu stored
ín the LCß. A chunk ís u unít ol dutu.
GET_STORAGE_LIMIT() Returns the muxímum uííowubíe síze lor u LCß.
GETLENGTH(lob)
Cets the íength ol the dutu stored ín the LCß.
INSTR(lob, pattern, offset, n) Returns the sturtíng posítíon ol churucters or bytes thut mutch the n|h
occurrence ol u puttern ín the LCß dutu. 1he dutu ís reud lrom the
LCß sturtíng ut the ollset.
ISOPEN(lob) Checks íl the LCß wus uíreudy opened.
ISTEMPORARY(lob)
Checks íl the LCß ís u temporury LCß.
LOADFROMFILE(dest_lob, src_bfile,
amount, dest_offset, src_offset)
Louds the dutu retríeved víu src_bfile to dest_lob, sturtíng ut
the ollsets lor u totuí umount ol churucters or bytes, src_bfile ís u
BFILE thut poínts to un externuí lííe.
LOADFROMFILE() ís oíd, und you shouíd use the hígher-
perlormunce LOADBLOBFROMFILE() or LOADCLOBFROMFILE()
methods.
LOADBLOBFROMFILE(dest_blob,
src_bfile, amount, dest_offset,
src_offset)
Louds the dutu retríeved víu src_bfile to dest_blob, sturtíng ut
the ollsets lor u totuí umount ol bytes, src_bfile ís u BFILE thut
poínts to un externuí lííe.
LOADBLOBFROMFILE() ollers ímproved perlormunce over
LOADFROMFILE() when usíng u BLOB.
LOADCLOBFROMFILE(dest_clob, src_
bfile, amount, dest_offset, src_
offset, src_csid, lang_context,
warning)
Louds the dutu retríeved víu src_bfile to dest_clob, sturtíng ut
the ollsets lor u totuí umount ol churucters, src_bfile ís u BFILE
thut poínts to un externuí lííe.
LOADCLOBFROMFILE() ollers ímproved perlormunce over
LOADFROMFILE() when usíng u CLOB/NCLOB.
LOBMAXSIZE
Returns the muxímum síze lor u LCß ín bytes (currentíy 2
64
).
OPEN(lob, open_mode) Cpens the LCß ín the índícuted mode, whích muy be set to
DBMS_LOB.FILE_READONLY, whích índícutes the LCß muy oníy
be reud lrom
DBMS_LOB.FILE_READWRITE, whích índícutes the LCß muy
reud lrom und wrítten to
READ(lob, amount, offset, buffer) Reuds the dutu lrom the LCß und stores them ín the buffer vuríubíe,
sturtíng ut the ollset ín the LCß lor u totuí umount ol churucters or bytes.
SUBSTR(lob, amount, offset) Returns purt ol the LCß dutu, sturtíng ut the ollset ín the LCß lor u
totuí umount ol churucters or bytes.
TRIM(lob, newlen) 1ríms the LCß dutu to the specílíed shorter íength.
WRITE(lob, amount, offset, buffer) \rítes the dutu lrom the buffer vuríubíe to the LCß, sturtíng ut the
ollset ín the LCß lor u totuí umount ol churucters or bytes.
WRITEAPPEND(lob, amount, buffer) \rítes the dutu lrom the buffer vuríubíe to the end ol the LCß,
sturtíng ut the ollset ín the LCß lor u totuí umount ol churucters or bytes.
TABlf 14-1 DBMS_LOB \c|hod· (contínued)
Chupter l4: Lurge Cb¡ects
48S
APPfND()
APPEND() udds the dutu ín u source LCß to the end ol u destínutíon LCß. 1here ure two versíons
ol APPEND():
DBMS_LOB.APPEND(
dest_lob IN OUT NOCOPY BLOB,
src_lob IN BLOB
);
DBMS_LOB.APPEND(
dest_lob IN OUT NOCOPY CLOB/NCLOB CHARACTER SET ANY_CS,
src_lob IN CLOB/NCLOB CHARACTER SET dest_lob%CHARSET
);
where
dest_lob ís the destínutíon LCß to whích the dutu ís uppended.
src_lob ís the source LCß lrom whích the dutu ís reud.
CHARACTER SET ANY_CS meuns the dutu ín dest_lob cun be uny churucter set.
CHARACTER SET dest_lob%CHARSET ís the churucter set ol dest_lob.
1he loííowíng tubíe shows the exceptíon thrown by APPEND().
fxccptiun Thruwn Whcn
VALUE_ERROR
Líther dest_lob or src_lob ís nuíí.
ClOSf()
CLOSE() cíoses u prevíousíy opened LCß. 1here ure three versíons ol CLOSE():
DBMS_LOB.CLOSE(
lob IN OUT NOCOPY BLOB
);
DBMS_LOB.CLOSE(
lob IN OUT NOCOPY CLOB/NCLOB CHARACTER SET ANY_CS
);
DBMS_LOB.CLOSE(
lob IN OUT NOCOPY BFILE
);
wherelob ís the LCß to be cíosed.
486
Crucíe Dutubuse ll SQL
COMPARf()
COMPARE() compures the dutu stored ín two LCßs, sturtíng ut the ollsets over u totuí umount ol
churucters or bytes. 1here ure three versíons ol COMPARE():
DBMS_LOB.COMPARE(
lob1 IN BLOB,
lob2 IN BLOB,
amount IN INTEGER := 4294967295,
offset1 IN INTEGER := 1,
offset2 IN INTEGER := 1
) RETURN INTEGER;
DBMS_LOB.COMPARE(
lob1 IN CLOB/NCLOB CHARACTER SET ANY_CS,
lob2 IN CLOB/NCLOB CHARACTER SET lob_1%CHARSET,
amount IN INTEGER := 4294967295,
offset1 IN INTEGER := 1,
offset2 IN INTEGER := 1
) RETURN INTEGER;
DBMS_LOB.COMPARE(
lob1 IN BFILE,
lob2 IN BFILE,
amount IN INTEGER,
offset1 IN INTEGER := 1,
offset2 IN INTEGER := 1
) RETURN INTEGER;
where
lob1 und lob2 ure the LCßs to compure.
amount ís the muxímum number ol churucters to reud lrom u CLOB/NCLOB, or the
muxímum number ol bytes to reud lrom u BLOB/BFILE.
offset1 und offset2 ure the ollsets ín churucters or bytes ín lob1 und lob2 to sturt
the compuríson (the ollsets sturt ut l).
COMPARE() returns
0 íl the LCßs ure ídentícuí.
l íl the LCßs uren't ídentícuí.
Nuíí íl
amount < 1
amount > LOBMAXSIZE (Note: LOBMAXSIZE ís the muxímum síze ol the LCß)
offset1 or offset2 < 1
offset1 or offset2 > LOBMAXSIZE
Chupter l4: Lurge Cb¡ects
487
1he loííowíng tubíe shows the exceptíons thrown by COMPARE().
fxccptiun Thruwn Whcn
UNOPENED_FILE
1he lííe husn't been opened yet.
NOEXIST_DIRECTORY
1he dírectory doesn't exíst.
NOPRIV_DIRECTORY
You don't huve prívííeges to uccess the dírectory.
INVALID_DIRECTORY
1he dírectory ís ínvuííd.
INVALID_OPERATION
1he lííe exísts, but you don't huve prívííeges to uccess the lííe.
COPY()
COPY() copíes dutu lrom u source LCß to u destínutíon LCß, sturtíng ut the ollsets lor u totuí
umount ol churucters or bytes. 1here ure two versíons ol COPY():
DBMS_LOB.COPY(
dest_lob IN OUT NOCOPY BLOB,
src_lob IN BLOB,
amount IN INTEGER,
dest_offset IN INTEGER := 1,
src_offset IN INTEGER := 1
);
DBMS_LOB.COPY(
dest_lob IN OUT NOCOPY CLOB/NCLOB CHARACTER SET ANY_CS,
src_lob IN CLOB/NCLOB CHARACTER SET dest_lob%CHARSET,
amount IN INTEGER,
dest_offset IN INTEGER := 1,
src_offset IN INTEGER := 1
);
where
dest_lob und src_lob ure the LCßs to wríte to und reud lrom, respectíveíy.
amount ís the muxímum number ol churucters to reud lrom u CLOB/NCLOB, or the
muxímum number ol bytes to reud lrom u BLOB/BFILE.
dest_offset und src_offset ure the ollsets ín churucters or bytes ín dest_lob und
src_lob to sturt the copy (the ollsets sturt ut l).
1he loííowíng tubíe shows the exceptíons thrown by COPY().
fxccptiun Thruwn Whcn
VALUE_ERROR
Any ol the purumeters ure nuíí.
INVALID_ARGVAL
Líther:
src_offset < 1
dest_offset < 1
src_offset > LOBMAXSIZE
dest_offset > LOBMAXSIZE
amount < 1
amount > LOBMAXSIZE
488
Crucíe Dutubuse ll SQL
CRfATfTfMPORARY()
CREATETEMPORARY() creutes u temporury LCß ín the user's deluuít temporury tubíespuce.
1here ure two versíons ol CREATETEMPORARY():
DBMS_LOB.CREATETEMPORARY(
lob IN OUT NOCOPY BLOB,
cache IN BOOLEAN,
duration IN PLS_INTEGER := 10
);
DBMS_LOB.CREATETEMPORARY (
lob IN OUT NOCOPY CLOB/NCLOB CHARACTER SET ANY_CS,
cache IN BOOLEAN,
duration IN PLS_INTEGER := 10
);
where
lob ís the temporury LCß to creute.
cache índícutes whether the LCß shouíd be reud ínto the buller cuche (true lor yes, luíse
lor no).
duration ís u hínt (cun be set to SESSION, TRANSACTION, or CALL) us to whether the
temporury LCß ís removed ut the end ol the sessíon, trunsuctíon, or cuíí (the deluuít ís
SESSION).
1he loííowíng tubíe shows the exceptíon thrown by CREATETEMPORARY().
fxccptiun Thruwn Whcn
VALUE_ERROR
1he lob purumeter ís nuíí.
fRASf()
ERASE() removes dutu lrom u LCß, sturtíng ut the ollset lor u totuí umount ol churucters or bytes.
1here ure two versíons ol ERASE():
DBMS_LOB.ERASE(
lob IN OUT NOCOPY BLOB,
amount IN OUT NOCOPY INTEGER,
offset IN INTEGER := 1
);
DBMS_LOB.ERASE(
lob IN OUT NOCOPY CLOB/NCLOB CHARACTER SET ANY_CS,
amount IN OUT NOCOPY INTEGER,
offset IN INTEGER := 1
);
where
lob ís the LCß to eruse.
Chupter l4: Lurge Cb¡ects
489
amount ís the muxímum number ol churucters to reud lrom u CLOB/NCLOB, or the
number ol bytes to reud lrom u BLOB.
offset ís the ollset ín churucters or bytes ín lob to sturt the erusure (the ollset sturts ut l).
1he loííowíng tubíe shows the exceptíons thrown by ERASE().
fxccptiun Thruwn Whcn
VALUE_ERROR
Any ol the purumeters ure nuíí.
INVALID_ARGVAL
Líther:
amount < 1
amount > LOBMAXSIZE
offset < 1
offset > LOBMAXSIZE
fllfClOSf()
FILECLOSE() cíoses u BFILE. You shouíd use the newer CLOSE() procedure, us Crucíe
Corporutíon does not píun to extend the oíder FILECLOSE() procedure. l'm oníy íncíudíng
coveruge ol FILECLOSE() here so you cun understund oíder progrums.
DBMS_LOB.FILECLOSE(
bfile IN OUT NOCOPY BFILE
);
wherebfile ís the BFILE to cíose.
1he loííowíng tubíe shows the exceptíons thrown by FILECLOSE().
fxccptiun Thruwn Whcn
VALUE_ERROR
1he bfile purumeter ís nuíí.
UNOPENED_FILE
1he lííe husn't been opened yet.
NOEXIST_DIRECTORY
1he dírectory doesn't exíst.
NOPRIV_DIRECTORY
You don't huve prívííeges to uccess the dírectory.
INVALID_DIRECTORY
1he dírectory ís ínvuííd.
INVALID_OPERATION
1he lííe exísts, but you don't huve prívííeges to uccess the lííe.
fllfClOSfAll()
FILECLOSEALL() cíoses uíí BFILE ob¡ects.
DBMS_LOB.FILECLOSEALL;
1he loííowíng tubíe shows the exceptíon thrown by FILECLOSEALL().
fxccptiun Thruwn Whcn
UNOPENED_FILE
No lííes huve been opened ín the sessíon.
490
Crucíe Dutubuse ll SQL
fllffXlSTS()
FILEEXISTS() checks íl u lííe exísts.
DBMS_LOB.FILEEXISTS(
bfile IN BFILE
) RETURN INTEGER;
wherebfile ís u BFILE thut poínts to un externuí lííe.
FILEEXISTS() returns
0 íl the lííe doesn't exíst.
l íl the lííe exísts.
1he loííowíng tubíe shows the exceptíons thrown by FILEEXISTS().
fxccptiun Thruwn Whcn
VALUE_ERROR
1he bfile purumeter ís nuíí.
NOEXIST_DIRECTORY
1he dírectory doesn't exíst.
NOPRIV_DIRECTORY
You don't huve prívííeges to uccess the dírectory.
INVALID_DIRECTORY
1he dírectory ís ínvuííd.
fllfGfTNAMf()
FILEGETNAME() returns the dírectory und lííenume lrom u BFILE.
DBMS_LOB.FILEGETNAME(
bfile IN BFILE,
directory OUT VARCHAR2,
filename OUT VARCHAR2
);
where
bfile ís the poínter to the lííe.
directory ís the dírectory where the lííe ís stored.
filename ís the nume ol the lííe.
1he loííowíng tubíe shows the exceptíons thrown by FILEGETNAME().
fxccptiun Thruwn Whcn
VALUE_ERROR
Any ol the ínput purumeters ure nuíí or ínvuííd.
INVALID_ARGVAL
1he directory or filename purumeters ure nuíí.
fllflSOPfN()
FILEISOPEN() checks íl u lííe ís open. You shouíd use the newer ISOPEN() procedure to
check íl u lííe ís open ín your own progrums, us Crucíe Corporutíon does not píun to extend the
oíder FILEISOPEN() method. l'm íncíudíng coveruge ol FILEISOPEN() here oníy so you cun
understund oíder progrums.
Chupter l4: Lurge Cb¡ects
491
DBMS_LOB.FILEISOPEN(
bfile IN BFILE
) RETURN INTEGER;
where bfile ís the poínter to the lííe.
FILEISOPEN() returns
0 íl the lííe ísn't open.
l íl the lííe ís open.
1he loííowíng tubíe shows the exceptíons thrown by FILEISOPEN().
fxccptiun Thruwn Whcn
NOEXIST_DIRECTORY
1he dírectory doesn't exíst.
NOPRIV_DIRECTORY
You don't huve prívííeges to uccess the dírectory.
INVALID_DIRECTORY
1he dírectory ís ínvuííd.
INVALID_OPERATION
1he lííe doesn't exíst or you don't huve prívííeges to uccess the lííe.
fllfOPfN()
FILEOPEN() opens u lííe. You shouíd use the newer OPEN() procedure to open u lííe ín your
own progrums, us Crucíe Corporutíon does not píun to extend the oíder FILEOPEN() procedure.
l'm íncíudíng coveruge ol FILEOPEN() here oníy so you cun understund oíder progrums.
DBMS_LOB.FILEOPEN(
bfile IN OUT NOCOPY BFILE,
open_mode IN BINARY_INTEGER := DBMS_LOB.FILE_READONLY
);
where
bfile ís the poínter to the lííe.
open_mode índícutes the open mode, the oníy open mode ís DBMS_LOB.FILE_
READONLY, whích índícutes the lííe muy be reud lrom.
1he loííowíng tubíe shows the exceptíons thrown by FILEOPEN().
fxccptiun Thruwn Whcn
VALUE_ERROR
Any ol the ínput purumeters ure nuíí or ínvuííd.
INVALID_ARGVAL
1he open_mode ís not set to DBMS_LOB.FILE_READONLY
OPEN_TOOMANY
An uttempt wus mude to open more thun SESSION_MAX_OPEN_
FILES lííes, where SESSION_MAX_OPEN_FILES ís u dutubuse
ínítíuíízutíon purumeter set by u dutubuse udmínístrutor.
NOEXIST_DIRECTORY
1he dírectory doesn't exíst.
INVALID_DIRECTORY
1he dírectory ís ínvuííd.
INVALID_OPERATION
1he lííe exísts, but you don't huve prívííeges to uccess the lííe.
492
Crucíe Dutubuse ll SQL
fRffTfMPORARY()
FREETEMPORARY() lrees u temporury LCß lrom the deluuít temporury tubíespuce ol the user.
1here ure two versíons ol FREETEMPORARY():
DBMS_LOB.FREETEMPORARY (
lob IN OUT NOCOPY BLOB
);
DBMS_LOB.FREETEMPORARY (
lob IN OUT NOCOPY CLOB/NCLOB CHARACTER SET ANY_CS
);
where lob ís the íob to be lreed.
1he loííowíng tubíe shows the exceptíon thrown by FREETEMPORARY().
fxccptiun Thruwn Whcn
VALUE_ERROR
Any ol the ínput purumeters ure nuíí or ínvuííd.
GfTCHUNkSlZf()
GETCHUNKSIZE() returns the chunk síze when reudíng und wrítíng LCß dutu (u chunk ís u unít
ol dutu). 1here ure two versíons ol GETCHUNKSIZE():
DBMS_LOB.GETCHUNKSIZE(
lob IN BLOB
) RETURN INTEGER;
DBMS_LOB.GETCHUNKSIZE(
lob IN CLOB/NCLOB CHARACTER SET ANY_CS
) RETURN INTEGER;
wherelob ís the LCß to get the chunk síze lor.
GETCHUNKSIZE() returns
1he chunk síze ín bytes lor u BLOB
1he chunk síze ín churucters lor u CLOB/NCLOB
1he loííowíng tubíe shows the exceptíon thrown by GETCHUNKSIZE().
fxccptiun Thruwn Whcn
VALUE_ERROR
1he lob purumeter ís nuíí.
GfT_STORAGf_llMlT()
GET_STORAGE_LIMIT() returns the muxímum uííowubíe síze lor u LCß.
DBMS_LOB.GET_STORAGE_LIMIT()
RETURN INTEGER;
Chupter l4: Lurge Cb¡ects
493
GfTlfNGTH()
GETLENGTH() returns the íength ol the LCß dutu. 1here ure three versíons ol GETLENGTH():
DBMS_LOB.GETLENGTH(
lob IN BLOB
) RETURN INTEGER;
DBMS_LOB.GETLENGTH(
lob IN CLOB/NCLOB CHARACTER SET ANY_CS
) RETURN INTEGER;
DBMS_LOB.GETLENGTH(
bfile IN BFILE
) RETURN INTEGER;
where
lob ís the BLOB, CLOB, or NCLOB dutu to get the íength ol.
bfile ís the BFILE dutu to get the íength ol.
GETLENGTH() returns
1he íength ín bytes lor u BLOB or BFILE
1he íength ín churucters lor u CLOB or NCLOB
1he loííowíng tubíe shows the exceptíon thrown by GETLENGTH().
fxccptiun Thruwn Whcn
VALUE_ERROR
1he lob or bfile purumeter ís nuíí.
lNSTR()
INSTR() returns the sturtíng posítíon ol churucters thut mutch the  occurrence ol u puttern ín
the LCß dutu, sturtíng ut un ollset. 1here ure three versíons ol INSTR():
DBMS_LOB.INSTR(
lob IN BLOB,
pattern IN RAW,
offset IN INTEGER := 1,
n IN INTEGER := 1
) RETURN INTEGER;
DBMS_LOB.INSTR(
lob IN CLOB/NCLOB CHARACTER SET ANY_CS,
pattern IN VARCHAR2 CHARACTER SET lob%CHARSET,
offset IN INTEGER := 1,
n IN INTEGER := 1
) RETURN INTEGER;
494
Crucíe Dutubuse ll SQL
DBMS_LOB.INSTR(
bfile IN BFILE,
pattern IN RAW,
offset IN INTEGER := 1,
n IN INTEGER := 1
) RETURN INTEGER;
where
lob ís the BLOB, CLOB, or NCLOB to reud lrom.
bfile ís the BFILE to reud lrom.
pattern ís the puttern to seurch lor ín the LCß dutu, the puttern ís u group ol RAW bytes
lor u BLOB or BFILE, und u VARCHAR2 churucter stríng lor u CLOB, the muxímum síze ol
the puttern ís l6,383 bytes.
offset ís the ollset to sturt reudíng dutu lrom the LCß (the ollset sturts ut l).
n ís the occurrence ol the puttern to seurch the dutu lor.
INSTR() returns
1he ollset ol the sturt ol the puttern (íl lound)
Zero íl the puttern ísn't lound
Nuíí íl
Any ol the IN purumeters ure nuíí or ínvuííd
offset < 1 or offset > LOBMAXSIZE
n < l or n > LOBMAXSIZE
1he loííowíng tubíe shows the exceptíons thrown by INSTR().
fxccptiun Thruwn Whcn
VALUE_ERROR
Any ol the ínput purumeters ure nuíí or ínvuííd.
UNOPENED_FILE
1he BFILE ísn't open.
NOEXIST_DIRECTORY
1he dírectory doesn't exíst.
NOPRIV_DIRECTORY
1he dírectory exísts, but you don't huve prívííeges to uccess the
dírectory.
INVALID_DIRECTORY
1he dírectory ís ínvuííd.
INVALID_OPERATION
1he lííe exísts, but you don't huve prívííeges to uccess the lííe.
lSOPfN()
ISOPEN() checks íl the LCß wus uíreudy opened. 1here ure three versíons ol ISOPEN():
Chupter l4: Lurge Cb¡ects
49S
DBMS_LOB.ISOPEN(
lob IN BLOB
) RETURN INTEGER;
DBMS_LOB.ISOPEN(
lob IN CLOB/NCLOB CHARACTER SET ANY_CS
) RETURN INTEGER;
DBMS_LOB.ISOPEN(
bfile IN BFILE
) RETURN INTEGER;
where
lob ís the BLOB, CLOB, or NCLOB to check.
bfile ís the BFILE to check.
ISOPEN() returns
0 íl the LCß ísn't open.
l íl the LCß ís open.
1he loííowíng tubíe shows the exceptíon thrown by ISOPEN().
fxccptiun Thruwn Whcn
VALUE_ERROR
1he lob or bfile purumeter ís nuíí or ínvuííd.
lSTfMPORARY()
ISTEMPORARY() checks íl the LCß ís u temporury LCß. 1here ure two versíons ol
ISTEMPORARY():
DBMS_LOB.ISTEMPORARY(
lob IN BLOB
) RETURN INTEGER;
DBMS_LOB.ISTEMPORARY (
lob IN CLOB/NCLOB CHARACTER SET ANY_CS
) RETURN INTEGER;
where
lob ís the LCß to check.
ISTEMPORARY() returns
0 íl the LCß ísn't temporury.
l íl the LCß ís temporury.
496
Crucíe Dutubuse ll SQL
1he loííowíng tubíe shows the exceptíon thrown by ISTEMPORARY().
fxccptiun Thruwn Whcn
VALUE_ERROR
1he lob purumeter ís nuíí or ínvuííd.
lOADfROMfllf()
LOADFROMFILE() íouds dutu retríeved víu u BFILE ínto u CLOB, NCLOB, or BLOB, sturtíng ut the
ollsets lor u totuí umount ol churucters or bytes. You shouíd use the hígher-perlormunce
LOADCLOBFROMFILE() or LOADBLOBFROMFILE() procedures ín your own progrums, und l'm
íncíudíng coveruge ol LOADFROMFILE() here oníy so you cun understund oíder progrums.
1here ure two versíons ol LOADFROMFILE():
DBMS_LOB.LOADFROMFILE(
dest_lob IN OUT NOCOPY BLOB,
src_bfile IN BFILE,
amount IN INTEGER,
dest_offset IN INTEGER := 1,
src_offset IN INTEGER := 1
);
DBMS_LOB.LOADFROMFILE(
dest_lob IN OUT NOCOPY CLOB/NCLOB CHARACTER SET ANY_CS,
src_bfile IN BFILE,
amount IN INTEGER,
dest_offset IN INTEGER := 1,
src_offset IN INTEGER := 1
);
where
dest_lob ís the LCß ínto whích the dutu ís to be wrítten.
src_bfile ís the poínter to the lííe lrom whích the dutu ís to be reud.
amount ís the muxímum number ol bytes or churucters to reud lrom src_bfile.
dest_offset ís the ollset ín bytes or churucters ín dest_lob to sturt wrítíng dutu (the
ollset sturts ut l).
src_offset ís the ollset ín bytes ín src_bfile to sturt reudíng dutu (the ollset sturts ut l).
1he loííowíng tubíe shows the exceptíons thrown by LOADFROMFILE().
fxccptiun Thruwn Whcn
VALUE_ERROR
Any ol the ínput purumeters ure nuíí or ínvuííd.
INVALID_ARGVAL
Líther:
src_offset < 1
dest_offset < 1
src_offset > LOBMAXSIZE
dest_offset > LOBMAXSIZE
amount < 1
amount > LOBMAXSIZE
Chupter l4: Lurge Cb¡ects
497
lOADBlOBfROMfllf()
LOADBLOBFROMFILE() íouds dutu retríeved víu u BFILE ínto u BLOB. LOADBLOBFROMFILE()
ollers ímproved perlormunce over the LOADFROMFILE() method when usíng u BLOB.
DBMS_LOB.LOADBLOBFROMFILE(
dest_blob IN OUT NOCOPY BLOB,
src_bfile IN BFILE,
amount IN INTEGER,
dest_offset IN OUT INTEGER := 1,
src_offset IN OUT INTEGER := 1
);
where
dest_blob ís the BLOB ínto whích the dutu ís to be wrítten.
src_bfile ís the poínter to the lííe lrom whích the dutu ís to be reud.
amount ís the muxímum number ol bytes to reud lrom src_bfile.
dest_offset ís the ollset ín bytes ín dest_lob to sturt wrítíng dutu (the ollset sturts
ut l).
src_offset ís the ollset ín bytes ín src_bfile to sturt reudíng dutu (the ollset sturts
ut l).
1he loííowíng tubíe shows the exceptíons thrown by LOADBLOBFROMFILE().
fxccptiun Thruwn Whcn
VALUE_ERROR
Any ol the ínput purumeters ure nuíí or ínvuííd.
INVALID_ARGVAL
Líther:
src_offset < 1
dest_offset < 1
src_offset > LOBMAXSIZE
dest_offset > LOBMAXSIZE
amount < 1
amount > LOBMAXSIZE
lOADClOBfROMfllf()
LOADCLOBFROMFILE() íouds dutu retríeved víu u BFILE ínto u CLOB/NCLOB.
LOADCLOBFROMFILE() ollers ímproved perlormunce over the LOADFROMFILE()
method when usíng u CLOB/NCLOB. LOADCLOBFROMFILE() uíso uutomutícuííy converts
bínury dutu to churucter dutu.
DBMS_LOB.LOADCLOBFROMFILE(
dest_clob IN OUT NOCOPY CLOB/NCLOB,
src_bfile IN BFILE,
amount IN INTEGER,
dest_offset IN OUT INTEGER,
src_offset IN OUT INTEGER,
src_csid IN NUMBER,
498
Crucíe Dutubuse llg SQL
lang_context IN OUT INTEGER,
warning OUT INTEGER
);
where
dest_blob ís the CLOB/NCLOB ínto whích the dutu ís to be wrítten.
src_bfile ís the poínter to the lííe lrom whích the dutu ís to be reud.
amount ís the muxímum number ol churucters to reud lrom src_bfile.
dest_offset ís the ollset ín churucters ín dest_lob to sturt wrítíng dutu (the ollset
sturts ut l).
src_offset ís the ollset ín churucters ín src_bfile to sturt reudíng dutu (the ollset
sturts ut l).
src_csid ís the churucter set ol src_bfile (you shouíd typícuííy use DBMS_LOB
.DEFAULT_CSID, whích ís the deluuít churucter set lor the dutubuse).
lang_context ís the íunguuge context to use lor the íoud (you shouíd typícuííy
use DBMS_LOB.DEFAULT_LANG_CTX, whích ís the deluuít íunguuge context lor the
dutubuse).
warning ís u wurníng messuge thut contuíns ínlormutíon íl there wus u probíem wíth
the íoud, u common probíem ís thut u churucter ín src_bfile cunnot be converted
to u churucter ín dest_lob (ín whích cuse, warning ís set to DBMS_LOB.WARN_
INCONVERTIBLE_CHAR).
NOTf
You can ícarn aíí abou| charac|cr ·c|·, con|cx|·, and hov |o convcr|
charac|cr· |rom onc íanguagc |o ano|hcr ín |hc Crucíe Dutubuse
Cíobuíízutíon Support Cuíde pubíí·hcd b, Cracíc Corpora|íon.
1he loííowíng tubíe shows the exceptíons thrown by LOADCLOBFROMFILE().
fxccptiun Thruwn Whcn
VALUE_ERROR
Any ol the ínput purumeters ure nuíí or ínvuííd.
INVALID_ARGVAL
Líther:
src_offset < 1
dest_offset < 1
src_offset > LOBMAXSIZE
dest_offset > LOBMAXSIZE
amount < 1
amount > LOBMAXSIZE
OPfN()
OPEN() opens u LCß. 1here ure three versíons ol OPEN():
Chupter l4: Lurge Cb¡ects
499
DBMS_LOB.OPEN(
lob IN OUT NOCOPY BLOB,
open_mode IN BINARY_INTEGER
);
DBMS_LOB.OPEN(
lob IN OUT NOCOPY CLOB/NCLOB CHARACTER SET ANY_CS,
open_mode IN BINARY_INTEGER
);
DBMS_LOB.OPEN(
bfile IN OUT NOCOPY BFILE,
open_mode IN BINARY_INTEGER := DBMS_LOB.FILE_READONLY
);
where
lob ís the LCß to open.
bfile ís the poínter to the lííe to open.
open_mode índícutes the open mode, the deluuít ís DBMS_LOB.FILE_READONLY,
whích índícutes the LCß muy oníy be reud lrom, DBMS_LOB.FILE_READWRITE
índícutes the LCß muy be reud lrom und wrítten to.
1he loííowíng tubíe shows the exceptíon thrown by OPEN().
fxccptiun Thruwn Whcn
VALUE_ERROR
Any ol the ínput purumeters ure nuíí or ínvuííd.
RfAD()
READ() reuds dutu ínto u buller lrom u LCß. 1here ure three versíons ol READ():
DBMS_LOB.READ(
lob IN BLOB,
amount IN OUT NOCOPY BINARY_INTEGER,
offset IN INTEGER,
buffer OUT RAW
);
DBMS_LOB.READ(
lob IN CLOB/NCLOB CHARACTER SET ANY_CS,
amount IN OUT NOCOPY BINARY_INTEGER,
offset IN INTEGER,
buffer OUT VARCHAR2 CHARACTER SET lob%CHARSET
);
DBMS_LOB.READ(
bfile IN BFILE,
amount IN OUT NOCOPY BINARY_INTEGER,
S00
Crucíe Dutubuse ll SQL
offset IN INTEGER,
buffer OUT RAW
);
where
lob ís the CLOB, NCLOB, or BLOB to reud lrom.
bfile ís the BFILE to reud lrom.
amount ís the muxímum number ol churucters to reud lrom u CLOB/NCLOB, or the
muxímum number ol bytes to reud lrom u BLOB/BFILE.
offset ís the ollset to sturt reudíng (the ollset sturts ut l).
buffer ís the vuríubíe where the dutu reud lrom the LCß ís to be stored.
1he loííowíng tubíe shows the exceptíons thrown by READ().
fxccptiun Thruwn Whcn
VALUE_ERROR
Any ol the ínput purumeters ure nuíí.
INVALID_ARGVAL
Líther:
amount < 1
amount > MAXBUFSIZE
amount > cupucíty ol buller ín bytes or churucters
offset < 1
offset > LOBMAXSIZE
NO_DATA_FOUND
1he end ol the LCß wus reuched und there ure no more bytes or
churucters to reud lrom the LCß.
SUBSTR()
SUBSTR() returns purt ol the LCß dutu, sturtíng ut the ollset lor u totuí umount ol churucters or
bytes. 1here ure three versíons ol SUBSTR():
DBMS_LOB.SUBSTR(
lob IN BLOB,
amount IN INTEGER := 32767,
offset IN INTEGER := 1
) RETURN RAW;
DBMS_LOB.SUBSTR (
lob IN CLOB/NCLOB CHARACTER SET ANY_CS,
amount IN INTEGER := 32767,
offset IN INTEGER := 1
) RETURN VARCHAR2 CHARACTER SET lob%CHARSET;
DBMS_LOB.SUBSTR (
bfile IN BFILE,
amount IN INTEGER := 32767,
offset IN INTEGER := 1
) RETURN RAW;
Chupter l4: Lurge Cb¡ects
S01
where
lob ís the BLOB, CLOB, or NCLOB to reud lrom.
bfile ís the poínter to the lííe to reud lrom.
amount ís the muxímum number ol churucters reud lrom u CLOB/NCLOB, or the
muxímum number ol bytes to reud lrom u BLOB/BFILE.
offset ís the ollset to sturt reudíng dutu lrom the LCß (the ollset sturts ut l).
SUBSTR() returns
RAW dutu when reudíng lrom u BLOB/BFILE.
VARCHAR2 dutu when reudíng lrom u CLOB/NCLOB.
Nuíí íl
amount < 1
amount > 32767
offset < 1
offset > LOBMAXSIZE
1he loííowíng tubíe shows the exceptíons thrown by SUBSTR().
fxccptiun Thruwn Whcn
VALUE_ERROR
Any ol the ínput purumeters ure nuíí or ínvuííd.
UNOPENED_FILE
1he BFILE ísn't open.
NOEXIST_DIRECTORY
1he dírectory doesn't exíst.
NOPRIV_DIRECTORY
You don't huve prívííeges on the dírectory.
INVALID_DIRECTORY
1he dírectory ís ínvuííd.
INVALID_OPERATION
1he lííe exísts, but you don't huve prívííeges to uccess the lííe.
TRlM()
TRIM() tríms the LCß dutu to the specílíed shorter íength. 1here ure two versíons ol TRIM():
DBMS_LOB.TRIM(
lob IN OUT NOCOPY BLOB,
newlen IN INTEGER
);
DBMS_LOB.TRIM(
lob IN OUT NOCOPY CLOB/NCLOB CHARACTER SET ANY_CS,
newlen IN INTEGER
);
where
S02
Crucíe Dutubuse ll SQL
lob ís the BLOB, CLOB, or NCLOB to trím.
newlen ís the new íength (ín bytes lor u BLOB, or churucters lor u CLOB/NCLOB).
1he loííowíng tubíe shows the exceptíons thrown by TRIM().
fxccptiun Thruwn Whcn
VALUE_ERROR
1he íob purumeter ís nuíí.
INVALID_ARGVAL
Líther:
newlen < 0
newlen > LOBMAXSIZE
WRlTf()
WRITE() wrítes dutu lrom u buller to u LCß. 1here ure two versíons ol WRITE():
DBMS_LOB.WRITE(
lob IN OUT NOCOPY BLOB,
amount IN BINARY_INTEGER,
offset IN INTEGER,
buffer IN RAW
);
DBMS_LOB.WRITE(
lob IN OUT NOCOPY CLOB/NCLOB CHARACTER SET ANY_CS,
amount IN BINARY_INTEGER,
offset IN INTEGER,
buffer IN VARCHAR2 CHARACTER SET lob%CHARSET
);
where
lob ís the LCß to wríte to.
amount ís the muxímum number ol churucters to wríte to u CLOB/NCLOB, or the
muxímum number ol bytes to wríte to u BLOB.
offset ís the ollset to sturt wrítíng dutu to the LCß (the ollset sturts ut l).
buffer ís the vuríubíe thut contuíns the dutu to be wrítten to the LCß.
1he loííowíng tubíe shows the exceptíons thrown by WRITE().
fxccptiun Thruwn Whcn
VALUE_ERROR
Any ol the ínput purumeters ure nuíí or ínvuííd.
INVALID_ARGVAL
Líther:
amount < 1
amount > MAXBUFSIZE
offset < 1
offset > LOBMAXSIZE
Chupter l4: Lurge Cb¡ects
S03
WRlTfAPPfND()
WRITEAPPEND() wrítes dutu lrom the buller to the end ol u LCß, sturtíng ut the ollset lor u totuí
umount ol churucters or bytes. 1here ure two versíons ol WRITEAPPEND():
DBMS_LOB.WRITEAPPEND(
lob IN OUT NOCOPY BLOB,
amount IN BINARY_INTEGER,
buffer IN RAW
);
DBMS_LOB.WRITEAPPEND(
lob IN OUT NOCOPY CLOB/NCLOB CHARACTER SET ANY_CS,
amount IN BINARY_INTEGER,
buffer IN VARCHAR2 CHARACTER SET lob%CHARSET
);
where
lob ís the BLOB, CLOB, or NCLOB to wríte to.
amount ís the muxímum number ol churucters to wríte to u CLOB/NCLOB, or the
muxímum number ol bytes to wríte to u BLOB.
buffer ís the vuríubíe thut contuíns the dutu to be wrítten to the LCß.
1he loííowíng tubíe shows the exceptíons thrown by WRITEAPPEND().
fxccptiun Thruwn Whcn
VALUE_ERROR
Any ol the ínput purumeters ure nuíí or ínvuííd.
INVALID_ARGVAL
Líther:
amount < 1
amount > MAXBUFSIZE
fxampIc Pl/SQl Pruccdurcs
ln thís sectíon, you'íí see exumpíe lL/SQL procedures thut use the vuríous methods descríbed ín
the prevíous sectíons. 1he exumpíe procedures ure creuted when you run the lob_schema.sql
scrípt.
Rctricving a lOB lucatur
1he loííowíng get_clob_locator() procedure gets u LCß íocutor lrom the clob_content
tubíe, get_clob_locator() perlorms the loííowíng tusks:
Accepts un IN OUT purumeter numed p_clob ol type CLOB, p_clob ís set to u LCß
íocutor ínsíde the procedure. ßecuuse p_clob ís IN OUT, the vuíue ís pussed out ol the
procedure.
Accepts un IN purumeter numed p_id ol type INTEGER, whích specílíes the id ol u row
to retríeve lrom the clob_content tubíe.
Seíects clob_column lrom the clob_content tubíe ínto p_clob, thís stores the LCß
íocutor ol clob_column ín p_clob.
S04
Crucíe Dutubuse ll SQL
CREATE PROCEDURE get_clob_locator(
p_clob IN OUT CLOB,
p_id IN INTEGER
) AS
BEGIN
-- get the LOB locator and store it in p_clob
SELECT clob_column
INTO p_clob
FROM clob_content
WHERE id = p_id;
END get_clob_locator;
/
1he loííowíng get_blob_locator() procedure does the sume thíng us the prevíous
procedure, except ít gets the íocutor lor u BLOB lrom the blob_content tubíe:
CREATE PROCEDURE get_blob_locator(
p_blob IN OUT BLOB,
p_id IN INTEGER
) AS
BEGIN
-- get the LOB locator and store it in p_blob
SELECT blob_column
INTO p_blob
FROM blob_content
WHERE id = p_id;
END get_blob_locator;
/
1hese two procedures ure used ín the code shown ín the loííowíng sectíons.
Rcading Data frum ClOBs and BlOBs
1he loííowíng read_clob_example() procedure reuds the dutu lrom u CLOB und díspíuys the
dutu on the screen, read_clob_example() perlorms the loííowíng tusks:
Cuíís get_clob_locator() to get u íocutor und stores ít ín v_clob
Lses READ() to reud the contents ol v_clob ínto u VARCHAR2 vuríubíe numed
v_char_buffer
Díspíuys the contents ol v_char_buffer on the screen
CREATE PROCEDURE read_clob_example(
p_id IN INTEGER
) AS
v_clob CLOB;
v_offset INTEGER := 1;
v_amount INTEGER := 50;
v_char_buffer VARCHAR2(50);
BEGIN
-- get the LOB locator and store it in v_clob
get_clob_locator(v_clob, p_id);
Chupter l4: Lurge Cb¡ects

-- read the contents of v_clob into v_char_buffer, starting at
-- the v_offset position and read a total of v_amount characters
DBMS_LOB.READ(v_clob, v_amount, v_offset, v_char_buffer);
-- display the contents of v_char_buffer
DBMS_OUTPUT.PUT_LINE('v_char_buffer = ' || v_char_buffer);
DBMS_OUTPUT.PUT_LINE('v_amount = ' || v_amount);
END read_clob_example;
/
1he loííowíng exumpíe turns the server output on und cuíís read_clob_example():
SET SERVEROUTPUT ON
CALL read_clob_example(1);
v_char_buffer = Creeps in this petty pace
v_amount = 25
1he loííowíng read_blob_example() procedure reuds the dutu lrom u BLOB, read_
blob_example() perlorms the loííowíng tusks:
Cuíís get_blob_locator()to get the íocutor und stores ít ín v_blob
Cuíís READ() to reud the contents ol v_blob ínto u RAW vuríubíe numed v_binary_
buffer
Díspíuys the contents ol v_binary_buffer on the screen
CREATE PROCEDURE read_blob_example(
p_id IN INTEGER
) AS
v_blob BLOB;
v_offset INTEGER := 1;
v_amount INTEGER := 25;
v_binary_buffer RAW(25);
BEGIN
-- get the LOB locator and store it in v_blob
get_blob_locator(v_blob, p_id);
-- read the contents of v_blob into v_binary_buffer, starting at
-- the v_offset position and read a total of v_amount bytes
DBMS_LOB.READ(v_blob, v_amount, v_offset, v_binary_buffer);
-- display the contents of v_binary_buffer
DBMS_OUTPUT.PUT_LINE('v_binary_buffer = ' || v_binary_buffer);
DBMS_OUTPUT.PUT_LINE('v_amount = ' || v_amount);
END read_blob_example;
/
1he loííowíng exumpíe cuíís read_blob_example():
CALL read_blob_example(1);
v_binary_buffer = 100111010101011111
v_amount = 9
S06
Crucíe Dutubuse ll SQL
Writing tu a ClOB
1he loííowíng write_example() procedure wrítes u stríng ín v_char_buffer to v_clob
usíng WRITE(), notíce thut the SELECT stutement ín the procedure uses the FOR UPDATE
cíuuse, whích ís used becuuse the CLOB ís wrítten to usíng WRITE():
CREATE PROCEDURE write_example(
p_id IN INTEGER
) AS
v_clob CLOB;
v_offset INTEGER := 7;
v_amount INTEGER := 6;
v_char_buffer VARCHAR2(10) := 'pretty';
BEGIN
-- get the LOB locator into v_clob for update (for update
-- because the LOB is written to using WRITE() later)
SELECT clob_column
INTO v_clob
FROM clob_content
WHERE id = p_id
FOR UPDATE;
-- read and display the contents of the CLOB
read_clob_example(p_id);
-- write the characters in v_char_buffer to v_clob, starting
-- at the v_offset position and write a total of v_amount characters
DBMS_LOB.WRITE(v_clob, v_amount, v_offset, v_char_buffer);
-- read and display the contents of the CLOB
-- and then rollback the write
read_clob_example(p_id);
ROLLBACK;
END write_example;
/
1he loííowíng exumpíe cuíís write_example():
CALL write_example(1);
v_char_buffer = Creeps in this petty pace
v_amount = 25
v_char_buffer = Creepsprettyis petty pace
v_amount = 25
Appcnding Data tu a ClOB
1he loííowíng append_example() procedure uses APPEND() to copy the dutu lrom v_src_
clob to the end ol v_dest_clob:
CREATE PROCEDURE append_example AS
v_src_clob CLOB;
v_dest_clob CLOB;
BEGIN
-- get the LOB locator for the CLOB in row #2 of
Chupter l4: Lurge Cb¡ects
S07
-- the clob_content table into v_src_clob
get_clob_locator(v_src_clob, 2);
-- get the LOB locator for the CLOB in row #1 of
-- the clob_content table into v_dest_clob for update
-- (for update because the CLOB will be added to using
-- APPEND() later)
SELECT clob_column
INTO v_dest_clob
FROM clob_content
WHERE id = 1
FOR UPDATE;
-- read and display the contents of CLOB #1
read_clob_example(1);
-- use APPEND() to copy the contents of v_src_clob to v_dest_clob
DBMS_LOB.APPEND(v_dest_clob, v_src_clob);
-- read and display the contents of CLOB #1
-- and then rollback the change
read_clob_example(1);
ROLLBACK;
END append_example;
/
1he loííowíng exumpíe cuíís append_example():
CALL append_example();
v_char_buffer = Creeps in this petty pace
v_amount = 25
v_char_buffer = Creeps in this petty pace from day to day
v_amount = 41
Cumparing thc Data in Twu ClOBs
1he loííowíng compare_example() procedure compures the dutu ín v_clob1 und v_clob2
usíng COMPARE():
CREATE PROCEDURE compare_example AS
v_clob1 CLOB;
v_clob2 CLOB;
v_return INTEGER;
BEGIN
-- get the LOB locators
get_clob_locator(v_clob1, 1);
get_clob_locator(v_clob2, 2);
-- compare v_clob1 with v_clob2 (COMPARE() returns 1
-- because the contents of v_clob1 and v_clob2 are different)
DBMS_OUTPUT.PUT_LINE('Comparing v_clob1 with v_clob2');
v_return := DBMS_LOB.COMPARE(v_clob1, v_clob2);
DBMS_OUTPUT.PUT_LINE('v_return = ' || v_return);
S08
Crucíe Dutubuse ll SQL
-- compare v_clob1 with v_clob1 (COMPARE() returns 0
-- because the contents are the same)
DBMS_OUTPUT.PUT_LINE('Comparing v_clob1 with v_clob1');
v_return := DBMS_LOB.COMPARE(v_clob1, v_clob1);
DBMS_OUTPUT.PUT_LINE('v_return = ' || v_return);
END compare_example;
/
1he loííowíng exumpíe cuíís compare_example():
CALL compare_example();
Comparing v_clob1 with v_clob2
v_return = 1
Comparing v_clob1 with v_clob1
v_return = 0
Notíce thut v_return ís l when compuríng v_clob1 wíth v_clob2, whích índícutes the
LCß dutu ís díllerent, v_return ís 0 when compuríng v_clob1 wíth v_clob1, whích índícutes
the LCß dutu ís the sume.
Cupying Data frum Onc ClOB tu Anuthcr
1he loííowíng copy_example() procedure copíes some churucters lrom v_src_clob to
v_dest_clob usíng COPY():
CREATE PROCEDURE copy_example AS
v_src_clob CLOB;
v_dest_clob CLOB;
v_src_offset INTEGER := 1;
v_dest_offset INTEGER := 7;
v_amount INTEGER := 5;
BEGIN
-- get the LOB locator for the CLOB in row #2 of
-- the clob_content table into v_dest_clob
get_clob_locator(v_src_clob, 2);
-- get the LOB locator for the CLOB in row #1 of
-- the clob_content table into v_dest_clob for update
-- (for update because the CLOB will be added to using
-- COPY() later)
SELECT clob_column
INTO v_dest_clob
FROM clob_content
WHERE id = 1
FOR UPDATE;
-- read and display the contents of CLOB #1
read_clob_example(1);
-- copy characters to v_dest_clob from v_src_clob using COPY(),
-- starting at the offsets specified by v_dest_offset and
-- v_src_offset for a total of v_amount characters
Chupter l4: Lurge Cb¡ects
S09
DBMS_LOB.COPY(
v_dest_clob, v_src_clob,
v_amount, v_dest_offset, v_src_offset
);
-- read and display the contents of CLOB #1
-- and then rollback the change
read_clob_example(1);
ROLLBACK;
END copy_example;
/
1he loííowíng exumpíe cuíís copy_example():
CALL copy_example();
v_char_buffer = Creeps in this petty pace
v_amount = 25
v_char_buffer = Creeps fromhis petty pace
v_amount = 25
Using Tcmpurary ClOBs
1he loííowíng temporary_lob_example() procedure íííustrutes the use ol u temporury CLOB:
CREATE PROCEDURE temporary_lob_example AS
v_clob CLOB;
v_amount INTEGER;
v_offset INTEGER := 1;
v_char_buffer VARCHAR2(17) := 'Juliet is the sun';
BEGIN
-- use CREATETEMPORARY() to create a temporary CLOB named v_clob
DBMS_LOB.CREATETEMPORARY(v_clob, TRUE);
-- use WRITE() to write the contents of v_char_buffer to v_clob
v_amount := LENGTH(v_char_buffer);
DBMS_LOB.WRITE(v_clob, v_amount, v_offset, v_char_buffer);
-- use ISTEMPORARY() to check if v_clob is temporary
IF (DBMS_LOB.ISTEMPORARY(v_clob) = 1) THEN
DBMS_OUTPUT.PUT_LINE('v_clob is temporary');
END IF;
-- use READ() to read the contents of v_clob into v_char_buffer
DBMS_LOB.READ(
v_clob, v_amount, v_offset, v_char_buffer
);
DBMS_OUTPUT.PUT_LINE('v_char_buffer = ' || v_char_buffer);
-- use FREETEMPORARY() to free v_clob
DBMS_LOB.FREETEMPORARY(v_clob);
END temporary_lob_example;
/
S10
Crucíe Dutubuse ll SQL
1he loííowíng exumpíe cuíís temporary_lob_example():
CALL temporary_lob_example();
v_clob is temporary
v_char_buffer = Juliet is the sun
frasing Data frum a ClOB
1he loííowíng erase_example() procedure eruses purt ol u CLOB usíng ERASE():
CREATE PROCEDURE erase_example IS
v_clob CLOB;
v_offset INTEGER := 2;
v_amount INTEGER := 5;
BEGIN
-- get the LOB locator for the CLOB in row #1 of
-- the clob_content table into v_dest_clob for update
-- (for update because the CLOB will be erased using
-- ERASE() later)
SELECT clob_column
INTO v_clob
FROM clob_content
WHERE id = 1
FOR UPDATE;
-- read and display the contents of CLOB #1
read_clob_example(1);
-- use ERASE() to erase a total of v_amount characters
-- from v_clob, starting at v_offset
DBMS_LOB.ERASE(v_clob, v_amount, v_offset);
-- read and display the contents of CLOB #1
-- and then rollback the change
read_clob_example(1);
ROLLBACK;
END erase_example;
/
1he loííowíng exumpíe cuíís erase_example():
CALL erase_example();
v_char_buffer = Creeps in this petty pace
v_amount = 25
v_char_buffer = C in this petty pace
v_amount = 25
Scarching thc Data in a ClOB
1he loííowíng instr_example() procedure uses INSTR() to seurch the churucter dutu stored
ín u CLOB:
Chupter l4: Lurge Cb¡ects

CREATE PROCEDURE instr_example AS
v_clob CLOB;
v_char_buffer VARCHAR2(50) := 'It is the east and Juliet is the sun';
v_pattern VARCHAR2(5);
v_offset INTEGER := 1;
v_amount INTEGER;
v_occurrence INTEGER;
v_return INTEGER;
BEGIN
-- use CREATETEMPORARY() to create a temporary CLOB named v_clob
DBMS_LOB.CREATETEMPORARY(v_clob, TRUE);
-- use WRITE() to write the contents of v_char_buffer to v_clob
v_amount := LENGTH(v_char_buffer);
DBMS_LOB.WRITE(v_clob, v_amount, v_offset, v_char_buffer);
-- use READ() to read the contents of v_clob into v_char_buffer
DBMS_LOB.READ(v_clob, v_amount, v_offset, v_char_buffer);
DBMS_OUTPUT.PUT_LINE('v_char_buffer = ' || v_char_buffer);
-- use INSTR() to search v_clob for the second occurrence of is,
-- and INSTR() returns 27
DBMS_OUTPUT.PUT_LINE('Searching for second ''is''');
v_pattern := 'is';
v_occurrence := 2;
v_return := DBMS_LOB.INSTR(v_clob, v_pattern, v_offset, v_occurrence);
DBMS_OUTPUT.PUT_LINE('v_return = ' || v_return);
-- use INSTR() to search v_clob for the first occurrence of Moon,
-- and INSTR() returns 0 because Moon doesn't appear in v_clob
DBMS_OUTPUT.PUT_LINE('Searching for ''Moon''');
v_pattern := 'Moon';
v_occurrence := 1;
v_return := DBMS_LOB.INSTR(v_clob, v_pattern, v_offset, v_occurrence);
DBMS_OUTPUT.PUT_LINE('v_return = ' || v_return);
-- use FREETEMPORARY() to free v_clob
DBMS_LOB.FREETEMPORARY(v_clob);
END instr_example;
/
1he loííowíng exumpíe cuíís instr_example():
CALL instr_example();
v_char_buffer = It is the east and Juliet is the sun
Searching for second 'is'
v_return = 27
Searching for 'Moon'
v_return = 0
S12
Crucíe Dutubuse ll SQL
Cupying Data frum a fiIc intu a ClOB and a BlOB
1he loííowíng copy_file_data_to_clob() procedure shows how to reud text lrom u lííe und
store ít ín u CLOB:
CREATE PROCEDURE copy_file_data_to_clob(
p_clob_id INTEGER,
p_directory VARCHAR2,
p_file_name VARCHAR2
) AS
v_file UTL_FILE.FILE_TYPE;
v_chars_read INTEGER;
v_dest_clob CLOB;
v_amount INTEGER := 32767;
v_char_buffer VARCHAR2(32767);
BEGIN
-- insert an empty CLOB
INSERT INTO clob_content(
id, clob_column
) VALUES (
p_clob_id, EMPTY_CLOB()
);
-- get the LOB locator of the CLOB
SELECT clob_column
INTO v_dest_clob
FROM clob_content
WHERE id = p_clob_id
FOR UPDATE;
-- open the file for reading of text (up to v_amount characters per line)
v_file := UTL_FILE.FOPEN(p_directory, p_file_name, 'r', v_amount);
-- copy the data from the file into v_dest_clob one line at a time
LOOP
BEGIN
-- read a line from the file into v_char_buffer;
-- GET_LINE() does not copy the newline character into
-- v_char_buffer
UTL_FILE.GET_LINE(v_file, v_char_buffer);
v_chars_read := LENGTH(v_char_buffer);
-- append the line to v_dest_clob
DBMS_LOB.WRITEAPPEND(v_dest_clob, v_chars_read, v_char_buffer);
-- append a newline to v_dest_clob because v_char_buffer;
-- the ASCII value for newline is 10, so CHR(10) returns newline
DBMS_LOB.WRITEAPPEND(v_dest_clob, 1, CHR(10));
EXCEPTION
-- when there is no more data in the file then exit
Chupter l4: Lurge Cb¡ects

WHEN NO_DATA_FOUND THEN
EXIT;
END;
END LOOP;
-- close the file
UTL_FILE.FCLOSE(v_file);
DBMS_OUTPUT.PUT_LINE('Copy successfully completed.');
END copy_file_data_to_clob;
/
1here ure u number ol thíngs to note ubout thís procedure:
UTL_FILE ís u puckuge íncíuded wíth the dutubuse und contuíns methods und types thut
enubíe you to reud und wríte lííes. lor exumpíe, UTL_FILE.FILE_TYPE ís un ob¡ect
type used to represent u lííe.
1he v_amount vuríubíe ís set to 32767, whích ís the muxímum number ol churucters
thut cun be reud lrom u lííe duríng euch reud operutíon.
1he v_char_buffer vuríubíe ís used to store the resuíts reud lrom the lííe belore they
ure uppended to v_dest_clob. 1he muxímum íength ol v_char_buffer ís set to
32767, thís íength ís íurge enough to store the muxímum number ol churucters reud lrom
the lííe duríng euch reud operutíon.
UTL_FILE.FOPEN(directory, file_name, open_mode, amount) opens u lííe,
open_mode cun be set to one ol the loííowíng modes:
r to reud text
w to wríte text
a to uppend text
rb to reud bytes
wb to wríte bytes
ab to uppend bytes
UTL_FILE.GET_LINE(v_file, v_char_buffer) gets u ííne ol text lrom v_file
ínto v_char_buffer. GET_LINE() does not udd the newííne to v_char_buffer,
becuuse l wunt the newííne, l udd ít usíng DBMS_LOB.WRITEAPPEND(v_dest_clob,
1, CHR(10)).
1he loííowíng exumpíe cuíís copy_file_data_to_clob() to copy the contents ol the lííe
textContent.txt to u new CLOB wíth un id ol 3:
CALL copy_file_data_to_clob(3, 'SAMPLE_FILES_DIR', 'textContent.txt');
Copy successfully completed.

Crucíe Dutubuse ll SQL
1he loííowíng copy_file_data_to_blob() procedure shows how to reud bínury dutu
lrom u lííe und store ít ín u BLOB, notíce thut u RAW urruy ís used to store the bínury dutu reud
lrom the lííe:
CREATE PROCEDURE copy_file_data_to_blob(
p_blob_id INTEGER,
p_directory VARCHAR2,
p_file_name VARCHAR2
) AS
v_file UTL_FILE.FILE_TYPE;
v_bytes_read INTEGER;
v_dest_blob BLOB;
v_amount INTEGER := 32767;
v_binary_buffer RAW(32767);
BEGIN
-- insert an empty BLOB
INSERT INTO blob_content(
id, blob_column
) VALUES (
p_blob_id, EMPTY_BLOB()
);
-- get the LOB locator of the BLOB
SELECT blob_column
INTO v_dest_blob
FROM blob_content
WHERE id = p_blob_id
FOR UPDATE;
-- open the file for reading of bytes (up to v_amount bytes at a time)
v_file := UTL_FILE.FOPEN(p_directory, p_file_name, 'rb', v_amount);
-- copy the data from the file into v_dest_blob
LOOP
BEGIN
-- read binary data from the file into v_binary_buffer
UTL_FILE.GET_RAW(v_file, v_binary_buffer, v_amount);
v_bytes_read := LENGTH(v_binary_buffer);
-- append v_binary_buffer to v_dest_blob
DBMS_LOB.WRITEAPPEND(v_dest_blob, v_bytes_read/2,
v_binary_buffer);
EXCEPTION
-- when there is no more data in the file then exit
WHEN NO_DATA_FOUND THEN
EXIT;
END;
END LOOP;
-- close the file
UTL_FILE.FCLOSE(v_file);
Chupter l4: Lurge Cb¡ects
S1S
DBMS_OUTPUT.PUT_LINE('Copy successfully completed.');
END copy_file_data_to_blob;
/
1he loííowíng exumpíe cuíís copy_file_data_to_blob() to copy the contents ol the lííe
binaryContent.doc to u new BLOB wíth un id ol 3:
CALL copy_file_data_to_blob(3, 'SAMPLE_FILES_DIR', 'binaryContent.doc');
Copy successfully completed.
Cl course, copy_file_data_to_blob() cun be used to wríte uny bínury dutu contuíned
ín u lííe to u BLOB. 1he bínury dutu cun contuín musíc, vídeo, ímuges, executubíes, und so on. Co
uheud und try thís usíng your own lííes.
TlP
You can aí·o buí|-íoad da|a ín|o a íCß u·íng |hc Cracíc SÇí*íoadcr
and Da|a íump u|ííí|íc·, ·cc |hc Crucíe Dutubuse Lurge Cb¡ects
Deveíoper's Cuíde pubíí·hcd b, Cracíc Corpora|íon |or dc|aíí·.
Cupying Data frum a ClOB and a BlOB tu a fiIc
1he loííowíng copy_clob_data_to_file() procedure shows how to reud text lrom u CLOB
und suve ít to u lííe:
CREATE PROCEDURE copy_clob_data_to_file(
p_clob_id INTEGER,
p_directory VARCHAR2,
p_file_name VARCHAR2
) AS
v_src_clob CLOB;
v_file UTL_FILE.FILE_TYPE;
v_offset INTEGER := 1;
v_amount INTEGER := 32767;
v_char_buffer VARCHAR2(32767);
BEGIN
-- get the LOB locator of the CLOB
SELECT clob_column
INTO v_src_clob
FROM clob_content
WHERE id = p_clob_id;
-- open the file for writing of text (up to v_amount characters at a time)
v_file := UTL_FILE.FOPEN(p_directory, p_file_name, 'w', v_amount);
-- copy the data from v_src_clob to the file
LOOP
BEGIN
-- read characters from v_src_clob into v_char_buffer
DBMS_LOB.READ(v_src_clob, v_amount, v_offset, v_char_buffer);
-- copy the characters from v_char_buffer to the file
UTL_FILE.PUT(v_file, v_char_buffer);

Crucíe Dutubuse ll SQL
-- add v_amount to v_offset
v_offset := v_offset + v_amount;
EXCEPTION
-- when there is no more data in the file then exit
WHEN NO_DATA_FOUND THEN
EXIT;
END;
END LOOP;
-- flush any remaining data to the file
UTL_FILE.FFLUSH(v_file);
-- close the file
UTL_FILE.FCLOSE(v_file);
DBMS_OUTPUT.PUT_LINE('Copy successfully completed.');
END copy_clob_data_to_file;
/
1he loííowíng exumpíe cuíís copy_clob_data_to_file() to copy the contents ol CLOB
r3 to u new lííe numed textContent2.txt:
CALL copy_clob_data_to_file(3, 'SAMPLE_FILES_DIR', 'textContent2.txt');
Copy successfully completed.
ll you íook ín the C:\sample_files dírectory, you wííí línd the new textContent2.txt
lííe. 1hís lííe contuíns ídentícuí text to textContent.txt.
1he loííowíng copy_blob_data_to_file() procedure shows how to reud bínury dutu
lrom u BLOB und suve ít to u lííe:
CREATE PROCEDURE copy_blob_data_to_file(
p_blob_id INTEGER,
p_directory VARCHAR2,
p_file_name VARCHAR2
) AS
v_src_blob BLOB;
v_file UTL_FILE.FILE_TYPE;
v_offset INTEGER := 1;
v_amount INTEGER := 32767;
v_binary_buffer RAW(32767);
BEGIN
-- get the LOB locator of the BLOB
SELECT blob_column
INTO v_src_blob
FROM blob_content
WHERE id = p_blob_id;
-- open the file for writing of bytes (up to v_amount bytes at a time)
v_file := UTL_FILE.FOPEN(p_directory, p_file_name, 'wb', v_amount);
-- copy the data from v_src_blob to the file
Chupter l4: Lurge Cb¡ects
S17
LOOP
BEGIN
-- read characters from v_src_blob into v_binary_buffer
DBMS_LOB.READ(v_src_blob, v_amount, v_offset, v_binary_buffer);
-- copy the binary data from v_binary_buffer to the file
UTL_FILE.PUT_RAW(v_file, v_binary_buffer);
-- add v_amount to v_offset
v_offset := v_offset + v_amount;
EXCEPTION
-- when there is no more data in the file then exit
WHEN NO_DATA_FOUND THEN
EXIT;
END;
END LOOP;
-- flush any remaining data to the file
UTL_FILE.FFLUSH(v_file);
-- close the file
UTL_FILE.FCLOSE(v_file);
DBMS_OUTPUT.PUT_LINE('Copy successfully completed.');
END copy_blob_data_to_file;
/
1he loííowíng exumpíe cuíís copy_blob_data_to_file() to copy the contents ol BLOB
r3 to u new lííe numed binaryContent2.doc:
CALL copy_blob_data_to_file(3, 'SAMPLE_FILES_DIR', 'binaryContent2.doc');
Copy successfully completed.
ll you íook ín the C:\sample_files dírectory, you wííí línd the new binaryContent2
.doc lííe. 1hís lííe contuíns ídentícuí text to binaryContent.doc.
Cl course, copy_blob_data_to_file() cun be used to wríte uny bínury dutu contuíned
ín u BLOB to u lííe. 1he bínury dutu cun contuín musíc, vídeo, ímuges, executubíes, und so on.
Cupying Data frum a Bfllf tu a ClOB and a BlOB
1he loííowíng copy_bfile_data_to_clob() procedure shows how to reud text lrom u
BFILE und suve ít to u CLOB:
CREATE PROCEDURE copy_bfile_data_to_clob(
p_bfile_id INTEGER,
p_clob_id INTEGER
) AS
v_src_bfile BFILE;
v_directory VARCHAR2(200);
v_filename VARCHAR2(200);
v_length INTEGER;
v_dest_clob CLOB;

Crucíe Dutubuse ll SQL
v_amount INTEGER := DBMS_LOB.LOBMAXSIZE;
v_dest_offset INTEGER := 1;
v_src_offset INTEGER := 1;
v_src_csid INTEGER := DBMS_LOB.DEFAULT_CSID;
v_lang_context INTEGER := DBMS_LOB.DEFAULT_LANG_CTX;
v_warning INTEGER;
BEGIN
-- get the locator of the BFILE
SELECT bfile_column
INTO v_src_bfile
FROM bfile_content
WHERE id = p_bfile_id;
-- use FILEEXISTS() to check if the file exists
-- (FILEEXISTS() returns 1 if the file exists)
IF (DBMS_LOB.FILEEXISTS(v_src_bfile) = 1) THEN
-- use OPEN() to open the file
DBMS_LOB.OPEN(v_src_bfile);
-- use FILEGETNAME() to get the name of the file and the directory
DBMS_LOB.FILEGETNAME(v_src_bfile, v_directory, v_filename);
DBMS_OUTPUT.PUT_LINE('Directory = ' || v_directory);
DBMS_OUTPUT.PUT_LINE('Filename = ' || v_filename);
-- insert an empty CLOB
INSERT INTO clob_content(
id, clob_column
) VALUES (
p_clob_id, EMPTY_CLOB()
);
-- get the LOB locator of the CLOB (for update)
SELECT clob_column
INTO v_dest_clob
FROM clob_content
WHERE id = p_clob_id
FOR UPDATE;
-- use LOADCLOBFROMFILE() to get up to v_amount characters
-- from v_src_bfile and store them in v_dest_clob, starting
-- at offset 1 in v_src_bfile and v_dest_clob
DBMS_LOB.LOADCLOBFROMFILE(
v_dest_clob, v_src_bfile,
v_amount, v_dest_offset, v_src_offset,
v_src_csid, v_lang_context, v_warning
);
-- check v_warning for an inconvertible character
IF (v_warning = DBMS_LOB.WARN_INCONVERTIBLE_CHAR) THEN
DBMS_OUTPUT.PUT_LINE('Warning! Inconvertible character.');
END IF;
Chupter l4: Lurge Cb¡ects

-- use CLOSE() to close v_src_bfile
DBMS_LOB.CLOSE(v_src_bfile);
DBMS_OUTPUT.PUT_LINE('Copy successfully completed.');
ELSE
DBMS_OUTPUT.PUT_LINE('File does not exist');
END IF;
END copy_bfile_data_to_clob;
/
1he loííowíng exumpíe cuíís copy_bfile_data_to_clob() to copy the contents ol
BFILE rl to u new CLOB wíth un id ol 4:
CALL copy_bfile_data_to_clob(1, 4);
Copy successfully completed.
1he next exumpíe cuíís copy_clob_data_to_file() to copy the contents ol CLOB r4 to
u new lííe numed textContent3.txt:
CALL copy_clob_data_to_file(4, 'SAMPLE_FILES_DIR', 'textContent3.txt');
Copy successfully completed.
ll you íook ín the C:\sample_files dírectory, you wííí línd the new textContent3.txt
lííe. 1hís lííe contuíns ídentícuí text to textContent.txt.
1he loííowíng copy_bfile_data_to_blob() procedure shows how to reud bínury dutu
lrom u BFILE und suve ít to u BLOB:
CREATE PROCEDURE copy_bfile_data_to_blob(
p_bfile_id INTEGER,
p_blob_id INTEGER
) AS
v_src_bfile BFILE;
v_directory VARCHAR2(200);
v_filename VARCHAR2(200);
v_length INTEGER;
v_dest_blob BLOB;
v_amount INTEGER := DBMS_LOB.LOBMAXSIZE;
v_dest_offset INTEGER := 1;
v_src_offset INTEGER := 1;
BEGIN
-- get the locator of the BFILE
SELECT bfile_column
INTO v_src_bfile
FROM bfile_content
WHERE id = p_bfile_id;
-- use FILEEXISTS() to check if the file exists
-- (FILEEXISTS() returns 1 if the file exists)
IF (DBMS_LOB.FILEEXISTS(v_src_bfile) = 1) THEN
-- use OPEN() to open the file
DBMS_LOB.OPEN(v_src_bfile);
-- use FILEGETNAME() to get the name of the file and

Crucíe Dutubuse ll SQL
-- the directory
DBMS_LOB.FILEGETNAME(v_src_bfile, v_directory, v_filename);
DBMS_OUTPUT.PUT_LINE('Directory = ' || v_directory);
DBMS_OUTPUT.PUT_LINE('Filename = ' || v_filename);
-- insert an empty BLOB
INSERT INTO blob_content(
id, blob_column
) VALUES (
p_blob_id, EMPTY_BLOB()
);
-- get the LOB locator of the BLOB (for update)
SELECT blob_column
INTO v_dest_blob
FROM blob_content
WHERE id = p_blob_id
FOR UPDATE;
-- use LOADBLOBFROMFILE() to get up to v_amount bytes
-- from v_src_bfile and store them in v_dest_blob, starting
-- at offset 1 in v_src_bfile and v_dest_blob
DBMS_LOB.LOADBLOBFROMFILE(
v_dest_blob, v_src_bfile,
v_amount, v_dest_offset, v_src_offset
);
-- use CLOSE() to close v_src_bfile
DBMS_LOB.CLOSE(v_src_bfile);
DBMS_OUTPUT.PUT_LINE('Copy successfully completed.');
ELSE
DBMS_OUTPUT.PUT_LINE('File does not exist');
END IF;
END copy_bfile_data_to_blob;
/
1he loííowíng exumpíe cuíís copy_bfile_data_to_blob() to copy the contents ol
BFILE r2 to u new BLOB wíth un id ol 4:
CALL copy_bfile_data_to_blob(2, 4);
Copy successfully completed.
1he next exumpíe cuíís copy_blob_data_to_file() to copy the contents ol BLOB r4 to
u new lííe numed binaryContent3.doc:
CALL copy_blob_data_to_file(4, 'SAMPLE_FILES_DIR', 'binaryContent3.doc');
Copy successfully completed.
ll you íook ín the C:\sample_files dírectory, you wííí línd the new binaryContent3
.doc lííe. 1hís lííe contuíns ídentícuí text to binaryContent.doc.
1hís ís the end ol the coveruge on íurge ob¡ects. ln the next sectíon, you'íí íeurn ubout the
LONG und LONG RAW types.
Chupter l4: Lurge Cb¡ects
S21
lONG and lONG RAW Typcs
l mentíoned ut the sturt ol thís chupter thut LCßs ure the prelerred storuge type lor íurge bíocks ol
dutu, but you muy encounter dutubuses thut stííí use the loííowíng types:
LONG Lsed to store up to 2 gígubytes ol churucter dutu
LONG RAW Lsed to store up to 2 gígubytes ol bínury dutu
RAW Lsed to store up to 4 kííobytes ol bínury dutu
ln thís sectíon, you'íí íeurn how to use LONG und LONG RAW types. RAW ís used ín the sume
wuy us u LONG RAW, so l've omítted coveruge ol RAW.
Thc fxampIc TabIcs
ln thís sectíon, you'íí see the use ol the loííowíng two tubíes:
long_content Contuíns u LONG coíumn numed long_column
long_raw_content Contuíns u LONG RAW coíumn numed long_raw_column
1hese two tubíes ure creuted by the lob_schema.sql scrípt usíng the loííowíng stutements:
CREATE TABLE long_content (
id INTEGER PRIMARY KEY,
long_column LONG NOT NULL
);
CREATE TABLE long_raw_content (
id INTEGER PRIMARY KEY,
long_raw_column LONG RAW NOT NULL
);
Adding Data tu lONG and lONG RAW CuIumns
1he loííowíng INSERT stutements udd rows to the long_content tubíe:
INSERT INTO long_content (
id, long_column
) VALUES (
1, 'Creeps in this petty pace'
);
INSERT INTO long_content (
id, long_column
) VALUES (
2, ' from day to day'
);
1he loííowíng INSERT stutements udd rows to the long_raw_content tubíe (the lírst
INSERT contuíns u bínury number, the second u hexudecímuí number):
INSERT INTO long_raw_content (
id, long_raw_column
S22
Crucíe Dutubuse llg SQL
) VALUES (
1, '100111010101011111'
);
INSERT INTO long_raw_content (
id, long_raw_column
) VALUES (
2, 'A0FFB71CF90DE'
);
ln the next sectíon, you'íí see how to convert LONG und LONG RAW coíumns to LCßs.
Cunvcrting lONG and lONG RAW CuIumns tu lOBs
You cun convert u LONG to u CLOB usíng the TO_LOB() lunctíon. lor exumpíe, the loííowíng
stutement converts long_column to u CLOB usíng TO_LOB() und stores the resuíts ín the
clob_content tubíe:
INSERT INTO clob_content
SELECT 10 + id, TO_LOB(long_column)
FROM long_content;
2 rows created.
You cun convert u LONG RAW to u BLOB usíng the TO_LOB() lunctíon. lor exumpíe, the
loííowíng stutement converts long_raw_column to u BLOB usíng TO_LOB() und stores
the resuíts ín the blob_content tubíe:
INSERT INTO blob_content
SELECT 10 + id, TO_LOB(long_raw_column)
FROM long_raw_content;
2 rows created.
You cun uíso use the ALTER TABLE stutement to convert LONG und LONG RAW coíumns
dírectíy. lor exumpíe, the loííowíng stutement converts long_column to u CLOB:
ALTER TABLE long_content MODIFY (long_column CLOB);
1he next exumpíe converts long_raw_column to u BLOB:
ALTER TABLE long_raw_content MODIFY (long_raw_column BLOB);
CAUTlON
You ·houíd no| modí|, |abíc· |ha| arc currcn|í, u·cd ín a produc|íon
appííca|íon.
Cnce u LONG or LONG RAW coíumn ís converted to u LCß, you cun use the rích lL/SQL
methods descríbed eurííer to uccess the LCß.
Chupter l4: Lurge Cb¡ects
S23
OracIc Databasc 10 fnhanccmcnts
tu largc Objccts
ln thís sectíon, you'íí íeurn ubout the loííowíng enhuncements mude to íurge ob¡ects ín Crucíe
Dutubuse l0:
lmpíícít conversíon between CLOB und NCLOB ob¡ects
Lse ol the :new uttríbute when usíng LCßs ín u trígger
l've províded un SQL*líus scrípt numed lob_schema2.sql ín the SQL dírectory. 1hís scrípt
cun be run usíng Crucíe Dutubuse l0 und hígher. 1he scrípt creutes u user numed lob_user2
wíth u pussword ol lob_password und creutes the tubíes und lL/SQL code used ín thís sectíon.
Alter the scrípt compíetes, you wííí be íogged ín us lob_user2.
lmpIicit Cunvcrsiun Bctwccn ClOB and NClOB Objccts
ln toduy's gíobuí busíness envíronment, you míght huve to deuí wíth conversíons between
Lnícode und u nutíonuí íunguuge churucter set. Lnícode ís u uníversuí churucter set thut enubíes
you to store text thut cun be converted ínto uny íunguuge, ít does thís by provídíng u uníque code
lor every churucter, regurdíess ol the íunguuge. A nutíonuí churucter set stores text ín u specílíc
íunguuge.
ln versíons ol the dutubuse beíow Crucíe Dutubuse l0, you huve to expíícítíy convert between
Lnícode text und the nutíonuí churucter set text usíng the TO_CLOB() und TO_NCLOB() lunctíons.
TO_CLOB() uííows you to convert text stored ín u VARCHAR2, NVARCHAR2, or NCLOB to u CLOB.
Símííuríy, TO_NCLOB() uííows you to convert text stored ín u VARCHAR2, NVARCHAR2, or CLOB to
un NCLOB.
Crucíe Dutubuse l0 und hígher ímpíícítíy converts Lnícode text und nutíonuí churucter set
text ín CLOB und NCLOB ob¡ects, whích suves you lrom usíng TO_CLOB() und TO_NCLOB().
You cun use thís ímpíícít conversíon lor IN und OUT vuríubíes ín queríes und DML stutements us
weíí us lor lL/SQL method purumeters und vuríubíe ussígnments.
Let's tuke u íook ut un exumpíe. 1he loííowíng stutement creutes u tubíe numed nclob_
content thut contuíns un NCLOB coíumn numed nclob_column:
CREATE TABLE nclob_content (
id INTEGER PRIMARY KEY,
nclob_column NCLOB
);
1he loííowíng nclob_example() procedure shows the ímpíícít conversíon ol u CLOB to un
NCLOB, und více versu:
CREATE PROCEDURE nclob_example
AS
v_clob CLOB := 'It is the east and Juliet is the sun';
v_nclob NCLOB;
BEGIN
S24
Crucíe Dutubuse ll SQL
-- insert v_clob into nclob_column; this implicitly
-- converts the CLOB v_clob to an NCLOB, storing
-- the contents of v_clob in the nclob_content table
INSERT INTO nclob_content (
id, nclob_column
) VALUES (
1, v_clob
);
-- select nclob_column into v_clob; this implicitly
-- converts the NCLOB stored in nclob_column to a
-- CLOB, retrieving the contents of nclob_column
-- into v_clob
SELECT nclob_column
INTO v_clob
FROM nclob_content
WHERE id = 1;
-- display the contents of v_clob
DBMS_OUTPUT.PUT_LINE('v_clob = ' || v_clob);
END nclob_example;
/
1he loííowíng exumpíe turns the server output on und cuíís nclob_example():
SET SERVEROUTPUT ON
CALL nclob_example();
v_clob = It is the east and Juliet is the sun
Usc uf thc :ncw Attributc Whcn Using lOBs in a Triggcr
ln Crucíe Dutubuse l0 und hígher, you cun use the :new uttríbute when relerencíng LCßs ín u
BEFORE UPDATE or BEFORE INSERT row íeveí trígger. 1he loííowíng exumpíe creutes u trígger
numed before_clob_content_update, the trígger líres when the clob_content tubíe ís
upduted und díspíuys the íength ol the new dutu ín clob_column, notíce thut :new ís used to
uccess the new dutu ín clob_column:
CREATE TRIGGER before_clob_content_update
BEFORE UPDATE
ON clob_content
FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE('clob_content changed');
DBMS_OUTPUT.PUT_LINE(
'Length = ' || DBMS_LOB.GETLENGTH(:new.clob_column)
);
END before_clob_content_update;
/
1he loííowíng exumpíe updutes the clob_content tubíe, cuusíng the trígger to be líred:
Chupter l4: Lurge Cb¡ects
S2S
UPDATE clob_content
SET clob_column = 'Creeps in this petty pace'
WHERE id = 1;
clob_content changed
Length = 25
OracIc Databasc 11 fnhanccmcnts
tu largc Objccts
ln thís sectíon, you'íí íeurn ubout the loííowíng enhuncements mude to íurge ob¡ects ín Crucíe
Dutubuse ll:
Lncryptíon ol BLOB, CLOB, und NCLOB dutu, whích prevents unuuthorízed víewíng und
modílícutíon ol the dutu
Compressíon to squeeze BLOB, CLOB, und NCLOB dutu
De-dupíícutíon ol BLOB, CLOB, und NCLOB dutu to uutomutícuííy detect und remove
repeuted dutu
fncrypting lOB Data
You cun dísguíse your dutu usíng encryptíon so thut unuuthorízed users cunnot víew or modíly
ít. You shouíd encrypt sensítíve dutu such us credít curd numbers, socíuí securíty numbers, und
so on.
ßelore you cun encrypt dutu, eíther you or u dutubuse udmínístrutor needs to set up u ºwuííet¨
to store securíty detuíís. 1he dutu ín u wuííet íncíudes u prívute key lor encryptíng und decryptíng
dutu. ln thís sectíon, you'íí see how to creute u wuííet, encrypt LCß dutu, und encrypt reguíur
coíumn dutu.
Crcating a WaIIct
1o creute u wuííet, you must lírst creute u dírectory cuííed wallet ín the dírectory $ORACLE_
BASE\admin\$ORACLE_SID, where ORACLE_BASE ís the buse dírectory where the Crucíe
dutubuse soltwure ís ínstuííed, und ORACLE_SID ís the system ídentílíer lor the dutubuse ín whích
the wuííet ís to be creuted. lor exumpíe, on my computer runníng \índows Xl und Crucíe
Dutubuse ll, l creuted my wallet directory ín C:\oracle_11g\admin\orcl.
Cnce the wuííet dírectory ís creuted, you need to run SQL*líus, connect to the dutubuse usíng
u prívííeged user uccount (lor exumpíe, system), und run un ALTER SYSTEM commund to set
the pussword lor the wuííet encryptíon key, us shown here:
SQL> CONNECT system/manager
SQL> ALTER SYSTEM SET ENCRYPTION KEY IDENTIFIED BY "testpassword123";
System altered.
Cnce thís ís done, u lííe cuííed ewallet.p12 uppeurs ín the wallet dírectory, und the
dutubuse uutomutícuííy opens the wuííet. 1he encryptíon key pussword ís stored ín the wuííet,
und ís used to encrypt und decrypt dutu behínd the scenes.
S26
Crucíe Dutubuse ll SQL
l've províded un SQL*líus scrípt numed lob_schema3.sql ín the SQL dírectory. 1hís scrípt
muy be run usíng Crucíe Dutubuse ll. 1he scrípt creutes u user numed lob_user3 wíth u
pussword ol lob_password, und ít uíso creutes the tubíes used íuter ín thís sectíon. Alter the
scrípt compíetes, you wííí be íogged ín us lob_user3.
fncrypting lOB Data
You cun encrypt the dutu stored ín u BLOB, CLOB, or NCLOB to prevent unuuthorízed uccess to
thut dutu, you cunnot encrypt u BFILE, becuuse the lííe ítseíl ís stored outsíde the dutubuse.
You cun use the loííowíng uígoríthms to encrypt dutu:
3DfS168 1he 1rípíe-DLS (Dutu Lncryptíon Stundurd) uígoríthm wíth u key íength ol
l68 bíts.
AfS128 1he Advunced Lncryptíon Stundurd uígoríthm wíth u key íength ol l28 bíts.
1he ALS uígoríthms were deveíoped to repíuce the oíder uígoríthms bused on DLS.
AfS192 1he Advunced Lncryptíon Stundurd uígoríthm wíth u key íength ol l92 bíts.
AfS2S6 1he Advunced Lncryptíon Stundurd uígoríthm wíth u key íength ol 256 bíts.
1hís ís the most secure encryptíon uígoríthm supported by the Crucíe dutubuse.
1he loííowíng stutement creutes u tubíe wíth u CLOB whose contents ure to be encrypted
usíng the ALSl28 uígoríthm, notíce the use ol the ENCRYPT und SECUREFILE keywords, whích
ure requíred when encryptíng dutu:
CREATE TABLE clob_content (
id INTEGER PRIMARY KEY,
clob_column CLOB ENCRYPT USING 'AES128'
) LOB(clob_column) STORE AS SECUREFILE (
CACHE
);
As you cun see, the contents ol clob_column wííí be encrypted usíng the ALSl28 uígoríthm.
ll you omít the USING keyword und the uígoríthm, then the deluuít ALSl92 uígoríthm ís used.
1he CACHE keyword ín the CREATE TABLE stutement índícutes thut the dutubuse píuces dutu
lrom the LCß ínto the buller cuche lor luster uccess. 1he optíons you cun use lor buller cuchíng
ure us loííows:
CACHE READS Lse when the LCß dutu wííí be lrequentíy reud, but wrítten oníy once
or occusíonuííy.
CACHE Lse when the LCß dutu wííí be lrequentíy reud und lrequentíy wrítten.
NOCACHE Lse when the LCß dutu wííí be reud once or occusíonuííy und wrítten once
or occusíonuííy. 1hís ís the deluuít optíon.
1he loííowíng INSERT stutements udd two rows to the clob_content tubíe:
INSERT INTO clob_content (
id, clob_column
) VALUES (
1, TO_CLOB('Creeps in this petty pace')
Chupter l4: Lurge Cb¡ects

);
INSERT INTO clob_content (
id, clob_column
) VALUES (
2, TO_CLOB(' from day to day')
);
1he dutu suppííed to clob_column ín these stutements ure uutomutícuííy encrypted behínd
the scenes by the dutubuse.
1he loííowíng query retríeves the rows lrom the clob_content tubíe:
SELECT *
FROM clob_content;
ID
----------
CLOB_COLUMN
-------------------------
1
Creeps in this petty pace
2
from day to day
\hen the dutu ís retríeved, ít ís uutomutícuííy decrypted by the dutubuse und then returned to
SQL*líus.
As íong us the wuííet ís open, you cun store und retríeve encrypted dutu, when the wuííet ís
cíosed, you cunnot. Let's see whut huppens when the wuííet ís cíosed, the loííowíng stutements
connect us the system user und cíose the wuííet:
CONNECT system/manager
ALTER SYSTEM SET WALLET CLOSE;
ll you now uttempt to connect us lob_user3 und retríeve clob_column lrom the clob_
content tubíe, you get the error ORA-28365: wallet is not open:
CONNECT lob_user3/lob_password
SELECT clob_column
FROM clob_content;
ORA-28365: wallet is not open
You cun stííí retríeve und modíly the contents ol unencrypted coíumns, lor exumpíe, the
loííowíng query retríeves the id coíumn lrom the clob_content tubíe:
SELECT id
FROM clob_content;
ID
----------
1
2
S28
Crucíe Dutubuse llg SQL
1he loííowíng stutements connect us the system user und re-open the wuííet:
CONNECT system/manager
ALTER SYSTEM SET WALLET OPEN IDENTIFIED BY "testpassword123";
Cnce thís ís done, you cun retríeve und modíly the contents ol clob_column lrom the clob_
content tubíe.
fncrypting CuIumn Data
You cun uíso encrypt reguíur coíumn dutu. 1hís leuture wus íntroduced ín Crucíe Dutubuse l0g
Reíeuse 2. lor exumpíe, the loííowíng stutement creutes u tubíe numed credit_cards wíth un
encrypted coíumn numed card_number:
CREATE TABLE credit_cards (
card_number NUMBER(16, 0) ENCRYPT,
first_name VARCHAR2(10),
last_name VARCHAR2(10),
expiration DATE
);
You cun use the sume uígoríthms to encrypt u coíumn us lor u LCß: 3DLSl68, ALSl28,
ALSl92 (the deluuít), und ALS256. ßecuuse l dídn't specíly un uígoríthm ulter the ENCRYPT
keyword lor the card_number coíumn, the deluuít ALSl92 uígoríthm ís used.
1he loííowíng INSERT stutements udd two rows to the credit_cards tubíe:
INSERT INTO credit_cards (
card_number, first_name, last_name, expiration
) VALUES (
1234, 'Jason', 'Bond', '03-FEB-2008'
);
INSERT INTO credit_cards (
card_number, first_name, last_name, expiration
) VALUES (
5768, 'Steve', 'Edwards', '07-MAR-2009'
);
As íong us the wuííet ís open, you cun retríeve und modíly the contents ol the card_number
coíumn. ll the wuííet ís cíosed, you get the error ORA-28365: wallet is not open. You
suw exumpíes thut íííustrute these concepts ín the prevíous sectíon, so l won't repeut símííur
exumpíes here.
Accessíng dutu ín un encrypted coíumn íntroduces uddítíonuí overheud. 1he overheud lor
encryptíng or decryptíng u coíumn ís estímuted by Crucíe Corporutíon to be ubout 5 percent, thís
meuns u SELECT or un INSERT tukes ubout 5 percent more tíme to compíete. 1he totuí overheud
depends on the number ol encrypted coíumns und theír lrequency ol uccess, therelore, you
shouíd oníy encrypt coíumns thut contuín sensítíve dutu.
NOTf
í| ,ou arc ín|crc·|cd ín ícarníng morc abou| vaííc|· and da|aba·c
·ccurí|, gcncraíí,, ,ou ·houíd rcad |hc Advunced Securíty
Admínístrutor's Cuíde pubíí·hcd b, Cracíc Corpora|íon.
Chupter l4: Lurge Cb¡ects
S29
Cumprcssing lOB Data
You cun compress the dutu stored ín u BLOB, CLOB, or NCLOB to reduce storuge spuce. lor
exumpíe, the loííowíng stutement creutes u tubíe wíth u CLOB whose contents ure to be compressed,
notíce the use ol the COMPRESS keyword:
CREATE TABLE clob_content3 (
id INTEGER PRIMARY KEY,
clob_column CLOB
) LOB(clob_column) STORE AS SECUREFILE (
COMPRESS
CACHE
);
NOTf
ívcn |hough |hc |abíc doc· no| con|aín cncr,p|cd da|a, |hc
SECUREFILE cíau·c mu·| bc u·cd.
\hen you udd dutu to the LCß, ít wííí be uutomutícuííy compressed by the dutubuse,
símííuríy, when you reud dutu lrom u LCß, ít wííí be uutomutícuííy decompressed. You cun use
COMPRESS HIGH lor muxímum dutu compressíon, the deluuít ís COMPRESS MEDIUM, und the
MEDIUM keyword ís optíonuí. 1he hígher the compressíon, the hígher the overheud when reudíng
und wrítíng LCß dutu.
Rcmuving DupIicatc lOB Data
You cun conlígure u BLOB, CLOB, or NCLOB so thut uny dupíícute dutu suppííed to ít ís uutomutícuííy
removed, thís process ís known us de-dupíícutíng dutu und cun suve storuge spuce. lor exumpíe,
the loííowíng stutement creutes u tubíe wíth u CLOB whose contents ure to be de-dupíícuted,
notíce the use ol the DEDUPLICATE LOB keywords:
CREATE TABLE clob_content2 (
id INTEGER PRIMARY KEY,
clob_column CLOB
) LOB(clob_column) STORE AS SECUREFILE (
DEDUPLICATE LOB
CACHE
);
Any dupíícute dutu udded to the LCß wííí be uutomutícuííy removed by the dutubuse. 1he
dutubuse uses the SHAl secure hush uígoríthm to detect dupíícute dutu.
You cun íeurn even more ubout íurge ob¡ects ín the Cracíc Da|aba·c íargc Cb]cc|·
Dcvcíopcr'· Cuídc pubííshed by Crucíe Corporutíon.
Summary
ln thís chupter, you huve íeurned the loííowíng:
LCßs muy be used to store bínury dutu, churucter dutu, und relerences to externuí lííes.
LCßs cun store up to l28 terubytes ol dutu.

Crucíe Dutubuse ll SQL
1here ure lour LCß types: CLOB, NCLOB, BLOB, und BFILE.
A CLOB stores churucter dutu.
An NCLOB stores muítípíe byte churucter dutu.
A BLOB stores bínury dutu.
A BFILE stores u poínter to u lííe íocuted ín the lííe system.
A LCß consísts ol two purts: u íocutor, whích specílíes the íocutíon ol the LCß dutu, und
the dutu ítseíl.
1he DBMS_LOB lL/SQL puckuge contuíns methods lor uccessíng LCßs.
ln the next chupter, you'íí íeurn how to run SQL stutements lrom u }uvu progrum.
\IAI1II

Runníng SQL Lsíng }uvu
53l
S32
Crucíe Dutubuse llg SQL
n thís chupter, you wííí do the loííowíng:
Leurn how to run SQL lrom }uvu progrums usíng the }uvu Dutubuse Connectívíty (}DßC)
Appíícutíon lrogrummíng lnterluce (All)
Lxumíne the vuríous Crucíe }DßC drívers thut muy be used to connect to un Crucíe
dutubuse
lerlorm queríes und SQL DML stutements to uccess dutubuse tubíes
Lse the vuríous }uvu types to get und set coíumn vuíues ín the dutubuse
Lxumíne how to perlorm trunsuctíon controí stutements und SQL DDL stutements
Hundíe dutubuse exceptíons thut muy occur when u }uvu progrum runs
Lxumíne the Crucíe dutubuse soltwure extensíons to }DßC
See compíete }uvu progrums thut íííustrute the use ol }DßC
NOTf
Thí· chap|cr gívc· an ín|roduc|íon |o }DßC. íor |uíí dc|aíí· on u·íng
}DßC ví|h an Cracíc da|aba·c, ,ou ·houíd rcad m, boo| Crucíe9í
}DßC lrogrummíng (\cCrav-Hííí/C·bornc, 2002).
Gctting Startcd
lríor to runníng the exumpíes ín thís chupter, you'íí need to ínstuíí u versíon ol Sun's }uvu Soltwure
Deveíopment Kít (SDK). You cun downíoud the SDK und víew luíí ínstuííutíon ínstructíons lrom
Sun's }uvu websíte ut ¡uvu.sun.com.
NOTf
í u·cd }ava 1.ó.0 vhcn vrí|íng |hí· chap|cr, vhích í· ín·|aíícd ví|h }ava
íí ´ SDK Lpda|c 2.
1he dírectory where you ínstuííed the Crucíe soltwure on your muchíne ís cuííed the
CRACLL_HCML dírectory. Cn my \índows computer, thís dírectory ís L:\orucíe_llg\
product\ll.l.0\dbl. lnsíde CRACLL_HCML ure muny subdírectoríes, one ol whích ís the
¡dbc dírectory. 1he ¡dbc dírectory contuíns the loííowíng:
A text lííe numed Reudme.txt. You shouíd open und reud thís lííe, us ít contuíns ímportunt
ítems such us reíeuse ínlormutíon und the íutest ínstuííutíon ínstructíons.
A dírectory numed ííb, whích contuíns u number ol }uvu Archíve (}AR) lííes.

Chupter l5: Runníng SQL Lsíng }uvu
S33
Cunfiguring Yuur Cumputcr
Cnce you've downíouded und ínstuííed the requíred soltwure, your next step ís to conlígure your
computer to deveíop und run }uvu progrums contuíníng }DßC stutements. You must set lour
envíronment vuríubíes on your muchíne:
ORACLE_HOME
JAVA_HOME
PATH
CLASSPATH
ll you're usíng Lníx or Línux, you'íí uíso need to set the uddítíonuí LD_LIBRARY_PATH
envíronment vuríubíe. You'íí íeurn how to set these envíronment vuríubíes ín the loííowíng
sectíons.
CAUTlON
Thc ín|orma|íon ín |hí· ·cc|íon va· corrcc| a| |ímc o| vrí|íng. You nccd
|o rcad |hc Rcadmc.|x| |ííc ín |hc CRACíí_HC\í']dbc dírcc|or, |o
chcc| |hc ía|c·| rcíca·c no|c· and ín·|aíía|íon ín·|ruc|íon·.
Sctting thc ORAClf_HOMf fnvirunmcnt VariabIc
1he CRACLL_HCML subdírectory ís íocuted ín the dírectory where you ínstuííed the Crucíe
soltwure. You'íí need to set un envíronment vuríubíe numed ORACLE_HOME on your muchíne
thut specílíes thís dírectory.
Sctting an fnvirunmcnt VariabIc in Winduws XP
1o set un envíronment vuríubíe ín \índows Xl, you perlorm the loííowíng steps:
1. Cpen the Controí luneí.
2. Doubíe-cííck System. 1hís díspíuys the System lropertíes díuíog box.
3. Seíect the Advunced tub.
4. Cííck the Lnvíronment Vuríubíes button. 1hís díspíuys the Lnvíronment Vuríubíes díuíog box.
S. Cííck the New button ín the System Vuríubíes ureu (the íower pune ol the díuíog box).
6. Set the vuríubíe nume to ORACLE_HOME und set the vuíue to your CRACLL_HCML
dírectory. (Cn my \índows Xl muchíne, l huve ORACLE_HOME set to L:\orucíe_llg\
product\ll.l.0\dbl.)
Sctting an fnvirunmcnt VariabIc with Unix ur linux
1o set un envíronment vuríubíe ín Lníx or Línux, you need to udd íínes to u specíuí lííe, the lííe
you need to modíly depends on whích sheíí you're usíng. ll you're usíng the ßourne, Korn, or
ßush sheíí, then you udd íínes símííur to the loííowíng ones to your .prolííe (when usíng ßourne
or Korn sheíí) or your .bush_prolííe (ßush sheíí):
ORACLE_HOME=/u01/app/oracle/product/11.1.0/db_1
export ORACLE_HOME
S34
Crucíe Dutubuse llg SQL
NOTf
You'íí nccd |o rcpíacc |hc dírcc|or, ·hovn ín |hc prcvíou· cxampíc
ví|h |hc corrcc| CRACíí_HC\í |or ,our ·c|up.
ll you're usíng the C sheíí, you udd the loííowíng ííne to your .íogín lííe:
setenv ORACLE_HOME /u01/app/oracle/product/11.1.0/db_1
Sctting thc |AVA_HOMf fnvirunmcnt VariabIc
1he JAVA_HOME envíronment vuríubíe specílíes the dírectory where you ínstuííed the }uvu SDK.
lor exumpíe, íl you ínstuííed the }uvu SDK ín the L:\¡uvu\¡dk dírectory, you creute u JAVA_HOME
system vuríubíe und set ít to L:\¡uvu\¡dk. 1o do thís, you cun use símííur steps to those shown ín
the prevíous sectíon.
Sctting thc PATH fnvirunmcnt VariabIc
1he PATH envíronment vuríubíe contuíns u ííst ol dírectoríes. \hen you enter u commund usíng
the operutíng system commund ííne, the computer seurches the dírectoríes ín the PATH lor the
executubíe you ure tryíng to run. You need to udd the loííowíng two dírectoríes to your exístíng
PATH:
1he bín subdírectory where you ínstuííed the }uvu SDK
1he ßlN subdírectory ol CRACLL_HCML
lor exumpíe, íl you ínstuííed the }uvu SDK ín the L:\¡uvu\¡dk dírectory, und your CRACLL_
HCML ís L:\orucíe_llg\product\ll.l.0\dbl, then you udd L:\¡uvu\¡dk\bín, L:\orucíe_llg\
product\ll.l.0\dbl to your PATH (notíce u semícoíon sepurutes the two dírectoríes). 1o udd
the dírectoríes to the PATH ín \índows Xl, you cun use steps símííur to those shown eurííer.
1o udd to un exístíng PATH ín Lníx or Línux, you need to modíly the uppropríute lííe lor your
sheíí. lor exumpíe, íl you're usíng the ßush sheíí wíth Línux, then you udd íínes to the .bush_
prolííe lííe thut ure símííur to the loííowíng:
PATH=$PATH:$JAVA_HOME/bin:$ORACLE_HOME/BIN
export PATH
Notíce thut u coíon (:) sepurutes the dírectoríes.
Sctting thc ClASSPATH fnvirunmcnt VariabIc
1he CLASSPATH envíronment vuríubíe contuíns u ííst ol íocutíons where }uvu cíuss puckuges ure
lound. A íocutíon cun be u dírectory nume or the nume ol u Zíp lííe or }AR lííe contuíníng cíusses.
1he CRACLL_HCML\¡dbc\ííb dírectory contuíns u number ol }AR lííes, whích ones you udd to
your CLASSPATH depends on whut }uvu SDK you're usíng.
At tíme ol wrítíng, the loííowíng wus correct lor settíng u CLASSPATH:
ll you're usíng }DK l.6 (or hígher), udd CRACLL_HCML\¡dbc\ííb\o¡dbc6.¡ur to your
CLASSPATH.
ll you're usíng }DK l.5, udd CRACLL_HCML\¡dbc\ííb\o¡dbc5.¡ur to your CLASSPATH.
ll you need Nutíonuí Lunguuge support, udd CRACLL_HCML\¡ííb\oruíl8n.¡ur to your
CLASSPATH.
Chupter l5: Runníng SQL Lsíng }uvu
S3S
ll you need the }1A und }NDl leutures, udd CRACLL_HCML\¡ííb\¡tu.¡ur und CRACLL_
HCML\¡ííb\¡ndí.¡ur to your CLASSPATH. }NDl ís the }ava ^amíng and Dírcc|or, ín|cr|acc.
}1A ís the }ava Tran·ac|íon Aíí.
You uíso need to udd the current dírectory to your CLASSPATH. You do thís by uddíng
u períod (.) to your CLASSPATH. 1hut wuy, the cíusses ín your current dírectory wííí be
lound by }uvu when you run your progrums.
\hen }uvu l.6 ís used und the CRACLL_HCML ís L:\orucíe_llg\product\ll.l.0\dbl, un
exumpíe CLASSPATH lor \índows Xl ís us loííows:
.;E:\oracle_11g\product\11.1.0\db1\jdbc\lib\ojdbc6.jar;
E:\oracle_11g\product\11.1.0\db1\jlib\orai18n.jar
ll you're usíng \índows Xl, you use the steps descríbed eurííer to creute u system
envíronment vuríubíe cuííed CLASSPATH. ll you're usíng Línux und }uvu l.6, you shouíd udd the
loííowíng íínes to your .bush_prolííe:
CLASSPATH=$CLASSPATH:.:$ORACLE_HOME/jdbc/lib/ojdbc6.jar:
$ORACLE_HOME/jlib/orai18n.jar
export CLASSPATH
Sctting thc lD_llBRARY_PATH fnvirunmcnt VariabIc
ll you're usíng Lníx or Línux, you'íí uíso need to set the LD_LIBRARY_PATH envíronment vuríubíe
to SCRACLL_HCML/¡dbc/ííb. 1hís dírectory contuíns shured ííbruríes thut ure used by the }DßC
CCl dríver. You udd LD_LIBRARY_PATH to the uppropríute lííe, lor exumpíe:
LD_LIBRARY_PATH=$ORACLE_HOME/jdbc/lib
export CLASSPATH
1hut concíudes conlíguríng your computer. You'íí íeurn ubout the Crucíe }DßC drívers next.
Thc OracIc |DBC Drivcrs
ln thís sectíon, you'íí íeurn ubout the vuríous Crucíe }DßC drívers. 1hese drívers enubíe the }DßC
stutements ín u }uvu progrum to uccess un Crucíe dutubuse. 1here ure lour Crucíe }DßC drívers:
1hín dríver
CCl dríver
Server-síde ínternuí dríver
Server-síde 1hín dríver
1he loííowíng sectíons descríbe euch ol these drívers.
Thc Thin Drivcr
1he 1hín dríver hus the smuííest lootprínt ol uíí the drívers, meuníng thut ít requíres the íeust
umount ol system resources to run. 1he 1hín dríver ís wrítten entíreíy ín }uvu. ll you ure wrítíng u
}uvu uppíet, you shouíd use the 1hín dríver. 1he 1hín dríver muy uíso be used ín stund-uíone }uvu
S36
Crucíe Dutubuse llg SQL
uppíícutíons und muy be used to uccess uíí versíons ol the Crucíe dutubuse. 1he 1hín dríver works
oníy wíth 1Cl/ll und requíres thut Crucíe Net be up und runníng. lor detuíís on Crucíe Net, you
cun reud the Cracíc Da|aba·c ^c| Scrvícc· Admíní·|ra|or'· Cuídc pubííshed by Crucíe Corporutíon.
NOTf
You don'| havc |o ín·|aíí an,|híng on |hc cíícn| compu|cr |o u·c |hc
Thín drívcr, and |hcrc|orc ,ou can u·c í| |or appíc|·.
Thc OCl Drivcr
1he CCl dríver requíres more resources thun the 1hín dríver, but ít generuííy hus better perlormunce.
1he CCl dríver ís suítubíe lor progrums depíoyed on the míddíe tíeru web server, lor exumpíe.
NOTf
Thc CCí drívcr rcquírc· |ha| ,ou ín·|aíí í| on |hc cíícn| compu|cr and
í· |hcrc|orc no| ·uí|abíc |or appíc|·.
1he CCl dríver hus u number ol perlormunce enhuncíng leutures, íncíudíng the ubíííty to pooí
dutubuse connectíons und preletch rows lrom the dutubuse. 1he CCl dríver works wíth uíí versíons
ol the dutubuse und uíí ol the supported Crucíe Net protocoís.
Thc Scrvcr-Sidc lntcrnaI Drivcr
1he server-síde ínternuí dríver provídes dírect uccess to the dutubuse, und ít ís used by the Crucíe
}VM to communícute wíth thut dutubuse 1he Crucíe }VM ís u }uvu Vírtuuí Muchíne thut ís íntegruted
wíth the dutubuse. You cun íoud u }uvu cíuss ínto the dutubuse, then pubíísh und run methods
contuíned ín thut cíuss usíng the Crucíe }VM, the }uvu code runs on the dutubuse server und cun
uccess dutu lrom u síngíe Crucíe sessíon.
Thc Scrvcr-Sidc Thin Drivcr
1he server-síde 1hín dríver ís uíso used by the Crucíe }VM und provídes uccess to remote dutubuses.
Líke the 1hín dríver, thís dríver ís uíso wrítten entíreíy ín }uvu. }uvu code thut uses the server-síde
1hín dríver cun uccess unother sessíon on the sume dutubuse server or u remote server.
lmpurting thc |DBC Packagcs
ln order lor your progrums to use }DßC, you must ímport the requíred }DßC puckuges ínto your
}uvu progrums. 1here ure two sets ol }DßC puckuges:
Stundurd }DßC puckuges lrom Sun Mícrosystems
Lxtensíon puckuges lrom Crucíe Corporutíon
1he stundurd }DßC puckuges enubíe your }uvu progrums to uccess the busíc leutures ol most
dutubuses, íncíudíng the Crucíe dutubuse, SQL Server, Dß2, und MySQL. 1he Crucíe extensíons
to }DßC enubíe your progrums to uccess uíí ol the Crucíe-specílíc leutures us weíí us the Crucíe-
specílíc perlormunce extensíons. You'íí íeurn ubout some ol the Crucíe-specílíc leutures íuter ín
thís chupter.
Chupter l5: Runníng SQL Lsíng }uvu
S37
1o use }DßC ín your progrums you shouíd ímport the stundurd java.sql.* puckuges, us
shown ín the loííowíng import stutement:
import java.sql.*;
Cl course, ímportíng java.sql.* ímports  ol the stundurd }DßC puckuges. As you
become prolícíent ín }DßC, you'íí línd thut you don't uíwuys need to ímport uíí the cíusses: you
cun ¡ust ímport those puckuges thut your progrum uctuuííy uses.
Rcgistcring thc OracIc |DBC Drivcrs
ßelore you cun open u dutubuse connectíon, you must lírst regíster the Crucíe }DßC drívers wíth
your }uvu progrum. As mentíoned eurííer, the }DßC drívers enubíe your }DßC stutements to uccess
the dutubuse.
1here ure two wuys to regíster the Crucíe }DßC drívers:
Lse the forName() method ol the cíuss java.lang.Class
Lse the registerDriver() method ol the }DßC DriverManager cíuss
1he loííowíng exumpíe íííustrutes the use ol the forName() method:
Class.forName("oracle.jdbc.OracleDriver");
1he second wuy to regíster the Crucíe }DßC drívers ís to use the registerDriver()
method ol the java.sql.DriverManager cíuss, us shown ín the loííowíng exumpíe:
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Cnce you huve regístered the Crucíe }DßC drívers, you cun open u connectíon to u dutubuse.
Opcning a Databasc Cunncctiun
ßelore you cun íssue SQL stutements ín your }uvu progrums, you must open u dutubuse
connectíon. 1here ure two muín wuys to open u dutubuse connectíon:
Lse the getConnection() method ol the DriverManager cíuss
Lse un Crucíe dutu source ob¡ect, whích must lírst be creuted und then connected to. 1hís
method uses u stundurdízed wuy ol settíng dutubuse connectíon detuíís, und un Crucíe
dutu source ob¡ect muy be used wíth the }uvu Numíng und Dírectory lnterluce (}NDl).
l'íí descríbe both ol these wuys to open u dutubuse connectíon ín the loííowíng sectíons,
sturtíng wíth the getConnection() method ol the DriverManager cíuss.
Cunnccting tu thc Databasc Using gctCunncctiun()
1he getConnection() method returns u }DßC Connection ob¡ect, whích shouíd be stored ín
your progrum so ít cun be relerenced íuter. 1he syntux ol u cuíí to the getConnection() method
ís us loííows:
DriverManager.getConnection(URL, username, password);
S38
Crucíe Dutubuse ll SQL
where
URL ís the dutubuse thut your progrum connects to, uíong wíth the }DßC dríver you wunt
to use. (See the loííowíng sectíon, º1he Dutubuse LRL,¨ lor detuíís on the LRL.)
username ís the nume ol the dutubuse user thut your progrum connects us.
password ís the pussword lor the usernume.
1he loííowíng exumpíe shows the getConnection() method beíng used to connect to u
dutubuse:
Connection myConnection = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:ORCL",
"store",
"store_password"
);
ln thís exumpíe, the connectíon ís mude to u dutubuse runníng on the muchíne ídentílíed us
localhost wíth un Crucíe System ldentílíer (SlD) ol ORCL, the Crucíe }DßC 1hín dríver ís used.
1he connectíon ís mude wíth the usernume store und the pussword store_password. 1he
Connection ob¡ect returned by the cuíí to getConnection() ís stored ín myConnection.
1he connectíon to u dutubuse ís mude through Crucíe Net, whích shouíd be up und runníng
when the progrum ííne ís run.
Thc Databasc URl
1he dutubuse LRL specílíes the íocutíon ol the dutubuse. 1he structure ol the dutubuse LRL ís
dependent on the vendor who provídes the }DßC drívers. ln the cuse ol Crucíe's }DßC drívers,
the dutubuse LRL structure ís us loííows:
driver_name:@driver_information
where
driver_name ís the nume ol the Crucíe }DßC dríver thut your progrum uses. 1hís muy
be set to one ol the loííowíng:
jdbc:oracle:thin 1he Crucíe }DßC 1hín dríver
jdbc:oracle:oci 1he Crucíe }DßC CCl dríver
driver_information 1he dríver-specílíc ínlormutíon requíred to connect to the
dutubuse. 1hís ís dependent on the dríver beíng used. ln the cuse ol the Crucíe }DßC
1hín dríver, the dríver-specílíc ínlormutíon muy be specílíed ín the loííowíng lormut:
host_name:port:database_SID \here host_name ís the nume ol the
computer, port ís the port to uccess the dutubuse, und database_SID ís the
dutubuse SlD
lor uíí the Crucíe }DßC drívers, íncíudíng the 1hín dríver und the vuríous CCl drívers, the
dríver-specílíc ínlormutíon muy uíso be specílíed usíng Crucíe Net keyword-vuíue puírs, whích
muy be specílíed ín the loííowíng lormut:
Chupter l5: Runníng SQL Lsíng }uvu
S39
(description=(address=(host=host_name)(protocol=tcp)(port=port))
(connect_data=(sid=database_SID)))
where
host_name ís the nume ol the computer on whích the dutubuse ís runníng.
port ís the port number on whích the Crucíe Net dutubuse íístener wuíts lor requests,
l52l ís the deluuít port number. Your DßA cun províde the port number.
database_SID ís the Crucíe SlD ol the dutubuse ínstunce to whích you wunt to
connect. Your DßA cun províde the dutubuse SlD.
1he loííowíng exumpíe shows the getConnection() method beíng used to connect to u
dutubuse usíng the Crucíe CCl dríver, wíth the dríver-specílíc ínlormutíon specílíed usíng Crucíe
Net keyword-vuíue puírs:
Connection myConnection = DriverManager.getConnection(
"jdbc:oracle:oci:@(description=(address=(host=localhost)" +
"(protocol=tcp)(port=1521))(connect_data=(sid=ORCL)))",
"store",
"store_password"
);
As you cun see, ín thís exumpíe u connectíon ís mude to u dutubuse runníng on the muchíne
ídentílíed us localhost, wíth un Crucíe SlD ol ORCL, usíng the Crucíe CCl dríver. 1he
connectíon to the dutubuse ís mude wíth the usernume store und wíth u pussword ol store_
password. 1he Connection ob¡ect returned by the cuíí to getConnection() ís stored ín
myConnection.
NOTf
íor |hc Cracíc CCí drívcr, ,ou ma, aí·o u·c an Cracíc ^c| T^S^A\íS
·|ríng. íor morc ín|orma|íon on |hí·, ·pca| ví|h ,our DßA or con·uí|
|hc Crucíe Dutubuse Net Servíces Admínístrutor's Cuíde pubíí·hcd b,
Cracíc Corpora|íon.
Cunnccting tu thc Databasc Using an OracIc Data Suurcc
You cun uíso use un Crucíe da|a ·ourcc to connect to u dutubuse. An Crucíe dutu source uses u
more stundurdízed wuy ol suppíyíng the vuríous purumeters to connect to u dutubuse thun the
prevíous method, whích used DriverManager.getConnection(). ln uddítíon, un Crucíe
dutu source muy uíso be regístered wíth }NDl. Lsíng }NDl wíth }DßC ís very useluí, becuuse ít
uííows you to regíster, or bínd, dutu sources, und then íoo| up those dutu sources ín your progrum
wíthout huvíng to províde the exuct dutubuse connectíon detuíís. 1hus, íl the dutubuse connectíon
detuíís chunge, oníy the }NDl ob¡ect must be chunged.
NOTf
You can ícarn abou| }^Dí ín m, boo| Crucíe9í }DßC lrogrummíng
(\cCrav-Hííí/C·bornc, 2002).
S40
Crucíe Dutubuse ll SQL
1here ure three steps thut must be perlormed to use un Crucíe dutu source:
1. Creute un Crucíe dutu source ob¡ect ol the oracle.jdbc.pool.OracleDataSource
cíuss.
2. Set the Crucíe dutu source ob¡ect uttríbutes usíng the set methods, whích ure delíned ín
the cíuss.
3. Connect to the dutubuse víu the Crucíe dutu source ob¡ect usíng the getConnection()
method.
1he loííowíng sectíons descríbe these three steps.
Stcp 1: Crcatc an OracIc Data Suurcc Objcct
1he lírst step ís to creute un Crucíe dutu source ob¡ect ol the oracle.jdbc.pool
.OracleDataSource cíuss. 1he loííowíng exumpíe creutes un OracleDataSource ob¡ect
numed myDataSource (you muy ussume thut the oracle.jdbc.pool.OracleDataSource
cíuss hus been ímported):
OracleDataSource myDataSource = new OracleDataSource();
Cnce you huve your OracleDataSource ob¡ect, the second step ís to set thut ob¡ect's
uttríbutes usíng the set methods.
Stcp 2: Sct thc OracIc Data Suurcc Objcct Attributcs
ßelore you cun use your OracleDataSource ob¡ect to connect to u dutubuse, you must set u
number ol uttríbutes ín thut ob¡ect to índícute the connectíon detuíís, usíng vuríous set methods
delíned ín the cíuss. 1hese detuíís íncíude ítems ííke the dutubuse nume, the }DßC dríver to use,
und so on, euch ol these detuíís hus u correspondíng uttríbute ín un OracleDataSource ob¡ect.
1he oracle.jdbc.pool.OracleDataSource cíuss uctuuííy ímpíements the javax
.sql.DataSource ínterluce províded wíth }DßC. 1he javax.sql.DataSource ínterluce
delínes u number ol uttríbutes, whích ure íísted ín 1ubíe l5-l. 1hís tubíe shows the nume,
descríptíon, und type ol euch uttríbute.
1he oracle.jdbc.pool.OracleDataSource cíuss provídes un uddítíonuí set ol
uttríbutes, whích ure íísted ín 1ubíe l5-2.
You muy use u number ol methods to reud lrom und wríte to euch ol the uttríbutes íísted ín
1ubíes l5-l und l5-2. 1he methods thut reud lrom the uttríbutes ure known us  methods, und
the methods thut wríte to the uttríbutes ure known us  methods.
1he set und get method numes ure eusy to remember: you tuke the uttríbute nume, convert
the lírst íetter to uppercuse, und udd the word ºset¨ or ºget¨ to the begínníng. lor exumpíe, to set
the dutubuse nume (stored ín the databaseName uttríbute), you use the setDatabaseName()
method, to get the nume ol the dutubuse currentíy set, you use the getDatabaseName()
method. 1here ís one exceptíon to thís: there ís no getPassword() method (thís ís lor securíty
reusonsyou don't wunt someone to be ubíe to get your pussword progrummutícuííy).
Most ol the uttríbutes ure }uvu String ob¡ects, so most ol the set methods uccept u síngíe
String purumeter, und most ol the get methods return u String. 1he exceptíon to thís ís the
portNumber uttríbute, whích ís un int. 1herelore, íts set method setPortNumber()
uccepts un int, und íts get method getPortNumber() returns un int.
Chupter l5: Runníng SQL Lsíng }uvu
S41
Attributc Namc Attributc Dcscriptiun Attributc Typc
databaseName
1he dutubuse nume (Crucíe SlD).
String
dataSourceName
1he nume ol the underíyíng dutu source cíuss.
String
description
Descríptíon ol the dutu source.
String
networkProtocol
1he network protocoí to use to communícute
wíth the dutubuse. 1hís uppííes oníy to the Crucíe
}DßC CCl drívers, und deluuíts to tcp. lor lurther
detuíís, reud the Cracíc Da|aba·c ^c| Scrvícc·
Admíní·|ra|or'· Cuídc pubííshed by Crucíe
Corporutíon.
String
password
1he pussword lor the suppííed usernume.
String
portNumber
1he port on whích the Crucíe Net íístener wuíts lor
dutubuse connectíon requests. 1he deluuít ís l52l.
int
serverName
1he dutubuse server muchíne nume (1Cl/ll
uddress or DNS uííus).
String
user
1he dutubuse usernume.
String
TABlf 1S-1 DataSource A||ríbu|c·
Attributc Namc Attributc Dcscriptiun Attributc Typc
driverType
1he }DßC dríver to use. ll you ure usíng the
server-síde ínternuí dríver, thís ís set to kprb,
und the other settíngs lor the uttríbutes ure
ígnored.
String
url
Muy be used to specíly un Crucíe dutubuse
LRL, whích cun be used us un uíternutíve to
settíng the dutubuse íocutíon. See the sectíon
eurííer on dutubuse LRLs lor detuíís.
String
tnsEntryName
Muy be used to specíly un Crucíe Net
1NSNAMLS stríng, whích cun uíso be used to
specíly the dutubuse íocutíon when usíng the
CCl drívers.
String
TABlf 1S-2 OracleDataSource A||ríbu|c·
S42
Crucíe Dutubuse ll SQL
1he loííowíng exumpíes íííustrute the use ol the set methods to wríte to the uttríbutes ol the
OracleDataSource ob¡ect myDataSource thut wus creuted eurííer ín Step l:
myDataSource.setServerName("localhost");
myDataSource.setDatabaseName("ORCL");
myDataSource.setDriverType("oci");
myDataSource.setNetworkProtocol("tcp");
myDataSource.setPortNumber(1521);
myDataSource.setUser("scott");
myDataSource.setPassword("tiger");
1he next exumpíes íííustrute the use ol some ol the get methods to reud the uttríbutes
prevíousíy set ín myDataSource:
String serverName = myDataSource.getServerName();
String databaseName = myDataSource.getDatabaseName();
String driverType = myDataSource.getDriverType();
String networkProtocol = myDataSource.getNetworkProtocol();
int portNumber = myDataSource.getPortNumber();
Cnce you've set your OracleDataSource ob¡ect uttríbutes, you cun use ít to connect to the
dutubuse.
Stcp 3: Cunncct tu thc Databasc via thc OracIc Data Suurcc Objcct
1he thírd step ís to connect to the dutubuse víu the OracleDataSource ob¡ect. You do
thís by cuíííng the getConnection() method ol your OracleDataSource ob¡ect. 1he
getConnection() method returns u }DßC Connection ob¡ect, whích must be stored.
1he loííowíng exumpíe shows how to cuíí the getConnection() method usíng the
myDataSource ob¡ect popuíuted ín the prevíous step:
Connection myConnection = myDataSource.getConnection();
1he Connection ob¡ect returned by getConnection() ís stored ín myConnection. You
cun uíso puss u usernume und pussword us purumeters to the getConnection() method, us
shown ín the loííowíng exumpíe:
Connection myConnection = myDataSource.getConnection(
"store", "store_password"
);
ln thís exumpíe, the usernume und pussword wííí overríde the usernume und pussword
prevíousíy set ín myDataSource. 1herelore, the connectíon to the dutubuse wííí be mude usíng
the usernume ol store wíth u pussword ol store_password, ruther thun scott und tiger,
whích were set ín myDataSource ín the prevíous sectíon.
Cnce you huve your Connection ob¡ect, you cun use ít to creute u }DßC Statement ob¡ect.
Crcating a |DBC Statcmcnt Objcct
Next, you need to creute u }DßC Statement ob¡ect ol the cíuss java.sql.Statement. A
Statement ob¡ect ís used to represent un SQL stutement, such us u query, u DML stutement
(INSERT, UPDATE, or DELETE), or u DDL stutement (such us CREATE TABLE). You'íí íeurn how
to íssue queríes, DML, und DDL stutements íuter ín thís chupter.
Chupter l5: Runníng SQL Lsíng }uvu
S43
1o creute u Statement ob¡ect, you use the createStatement() method ol u Connection
ob¡ect. ln the loííowíng exumpíe, u Statement ob¡ect numed myStatement ís creuted usíng
the createStatement() method ol the myConnection ob¡ect creuted ín the prevíous sectíon:
Statement myStatement = myConnection.createStatement();
1he method used ín the Statement cíuss to run the SQL stutement wííí depend on the SQL
stutement you wunt to perlorm. ll you wunt to perlorm u query, you use the executeQuery()
method. ll you wunt to perlorm un INSERT, UPDATE, or DELETE stutement, you use the
executeUpdate() method. ll you don't know uheud ol tíme whích type ol SQL stutement ís
to be perlormed, you cun use the execute() method, whích muy be used to perlorm uny SQL
stutement.
1here ís unother }DßC cíuss thut muy be used to represent un SQL stutement: the
PreparedStatement cíuss. 1hís ollers more udvunced lunctíonuííty thun the Statement
cíuss, l wííí díscuss the PreparedStatement cíuss ulter l huve expíuíned the use ol the
Statement cíuss.
Cnce you huve u Statement ob¡ect, you're reudy to íssue SQL stutements usíng }DßC.
Rctricving Ruws frum thc Databasc
1o perlorm u query usíng }DßC, you use the executeQuery() method ol the Statement
ob¡ect, whích uccepts u }uvu String contuíníng the text lor the query.
ßecuuse u query muy return more thun one row, the executeQuery() method returns un
ob¡ect thut stores the row(s) returned by your query. 1hís ob¡ect ís known us u }DßC  und
ís ol the java.sql.ResultSet cíuss. \hen usíng u ResultSet ob¡ect to reud rows lrom the
dutubuse, there ure three steps you loííow:
1. Creute u ResultSet ob¡ect und popuíute ít wíth the resuíts returned by u query.
2. Reud the coíumn vuíues lrom the ResultSet ob¡ect usíng get methods.
3. Cíose the ResultSet ob¡ect.
l wííí now wuík you through un exumpíe thut uses u ResultSet ob¡ect to retríeve the rows
lrom the customers tubíe.
Stcp 1: Crcatc and PupuIatc a RcsuItSct Objcct
You lírst creute u ResultSet ob¡ect und popuíute ít wíth the resuíts returned by u query. 1he
loííowíng exumpíe creutes u ResultSet ob¡ect numed customerResultSet und popuíutes
ít wíth the customer_id, first_name, last_name, dob, und phone coíumns lrom the
customers tubíe:
ResultSet customerResultSet = myStatement.executeQuery(
"SELECT customer_id, first_name, last_name, dob, phone " +
"FROM customers"
);
Alter thís stutement ís executed, the ResultSet ob¡ect wííí contuín the coíumn vuíues lor
the rows retríeved by the query. 1he ResultSet ob¡ect muy then be used to uccess the coíumn
vuíues lor the retríeved rows. ln the exumpíe, customerResultSet wííí contuín the líve rows
retríeved lrom the customers tubíe.
S44
Crucíe Dutubuse llg SQL
ßecuuse the execute() method uccepts u }uvu String, you cun buííd up your SQL
stutements when your progrum uctuuííy runs. 1hís meuns thut you cun do some luíríy powerluí
thíngs ín }DßC. lor exumpíe, you couíd huve the user ol your progrum type ín u stríng contuíníng
u WHERE cíuuse lor u query when they run the progrumor even enter the whoíe query. 1he
loííowíng exumpíe shows u WHERE cíuuse stríng:
String whereClause = "WHERE customer_id = 1";
ResultSet customerResultSet2 = myStatement.executeQuery(
"SELECT customer_id, first_name, last_name, dob, phone " +
"FROM customers " +
whereClause
);
You're not íímíted to queríes ín usíng thís dynumíc buííd-up method: you cun buííd up other
SQL stutements ín u símííur munner.
Stcp 2: Rcad thc CuIumn VaIucs frum thc RcsuItSct Objcct
1o reud the coíumn vuíues lor the rows stored ín u ResultSet ob¡ect, the ResultSet cíuss
provídes u seríes ol get methods. ßelore l get ínto the detuíís ol these get methods, you need to
understund how the dutu types used to represent vuíues ín Crucíe muy be mupped to computíbíe
}uvu dutu types.
OracIc and |ava Typcs
A }uvu progrum uses u díllerent set ol types lrom the Crucíe dutubuse types to represent vuíues.
lortunuteíy, the types used by Crucíe ure computíbíe wíth certuín }uvu types. 1hís uííows }uvu und
Crucíe to ínterchunge dutu stored ín theír respectíve types. 1ubíe l5-3 shows one set ol computíbíe
type muppíngs.
lrom thís tubíe, you cun see thut un Crucíe INTEGER ís computíbíe wíth u }uvu int. (l'íí tuík
ubout the other numeríc types íuter ín thís chupter ín the sectíon ºHundííng Numbers.¨) 1hís meuns
thut the customer_id coíumn ol the customers tubíe (whích ís delíned us un Crucíe INTEGER)
OracIc Typc |ava Typc
CHAR String
VARCHAR2 String
DATE java.sql.Date
java.sql.Time
java.sql.Timestamp
INTEGER short
int
long
NUMBER float
double
java.math.BigDecimal
TABlf 1S-3 Compa|íbíc T,pc \appíng·
Chupter l5: Runníng SQL Lsíng }uvu
S4S
muy be stored ín u }uvu int vuríubíe. Símííuríy, the first_name, last_name, und phone
coíumn vuíues (VARCHAR2s) muy be stored ín }uvu String vuríubíes.
1he Crucíe DATE type stores u yeur, month, duy, hour, mínute, und second. You muy use u
java.sql.Date ob¡ect to store the dute purt ol the dob coíumn vuíue und u java.sql.Time
vuríubíe to store the tíme purt. You muy uíso use u java.sql.Timestamp ob¡ect to store both
the dute und tíme purts ol the dob coíumn. Luter ín thís chupter, l'íí díscuss the oracle.sql
.DATE type, whích ís un Crucíe extensíon to the }DßC stundurd und provídes u superíor wuy ol
storíng dutes und tímes.
Cettíng buck to the exumpíe, the customer_id, first_name, last_name, dob, und
phone coíumns ure retríeved by the query ín the prevíous sectíon, und the loííowíng exumpíes
decíure }uvu vuríubíes und ob¡ects thut ure computíbíe wíth those coíumns:
int customerId = 0;
String firstName = null;
String lastName = null;
java.sql.Date dob = null;
String phone = null;
1he int und String types ure purt ol the core }uvu íunguuge, whííe java.sql.Date ís
purt ol }DßC und ís un extensíon ol the core }uvu íunguuge. }DßC provídes u number ol such types
thut uííow }uvu und u reíutíonuí dutubuse to exchunge dutu. However, }DßC doesn't huve types to
hundíe uíí ol the types used by Crucíe, one exumpíe ís the ROWID typeyou must use the
oracle.sql.ROWID type to store un Crucíe ROWID.
1o hundíe uíí ol the Crucíe types, Crucíe provídes u number ol uddítíonuí types, whích ure
delíned ín the oracle.sql puckuge. Aíso, Crucíe hus u number ol types thut muy be used us
un uíternutíve to the core }uvu und }DßC types, und ín some cuses these uíternutíves oller more
lunctíonuííty und better perlormunce thun the core }uvu und }DßC types. l'íí tuík more ubout the
Crucíe types delíned ín the oracle.sql puckuge íuter ín thís chupter.
Now thut you understund u ííttíe bít ubout computíbíe }uvu und Crucíe types, íet's contínue
wíth the exumpíe und see how to use the get methods to reud coíumn vuíues.
Using thc Gct Mcthuds tu Rcad CuIumn VaIucs
1he get methods ure used to reud vuíues stored ín u ResultSet ob¡ect. 1he nume ol euch get
method ís símpíe to understund: tuke the nume ol the }uvu type you wunt the coíumn vuíue to be
returned us und udd the word ºgetº to the begínníng. lor exumpíe, use getInt() to reud u coíumn
vuíue us u }uvu int, und use getString() to reud u coíumn vuíue us u }uvu String. 1o reud
the vuíue us u java.sql.Date, you wouíd use getDate(). Luch get method uccepts one
purumeter: eíther un int representíng the posítíon ol the coíumn ín the orígínuí query or u String
contuíníng the nume ol the coíumn. Let's exumíne some exumpíes bused on the eurííer exumpíe
thut retríeved the coíumns lrom the customers tubíe ín the customerResultSet ob¡ect.
1o get the vuíue ol the customer_id coíumn, whích wus the lírst coíumn specílíed ín the
query, you use getInt(1). You cun uíso use the nume ol the coíumn ín the get method, so
you couíd uíso use getInt("customer_id") to get the sume vuíue.
TlP
L·íng |hc coíumn namc ra|hcr |han |hc coíumn po·í|íon numbcr ín a
get mc|hod ma|c· ,our codc ca·ícr |o rcad.
S46
Crucíe Dutubuse ll SQL
1o get the vuíue ol the first_name coíumn, whích wus the second coíumn specílíed ín the
query, you use getString(2) or getString("first_name"). You use símííur method cuíís
to get the last_name und phone coíumn vuíues becuuse those coíumns ure uíso text stríngs. 1o
get the vuíue ol the dob coíumn, you couíd use getDate(4) or getDate("dob"). 1o uctuuííy
reud the vuíues stored ín u ResultSet ob¡ect, you must cuíí the get methods usíng thut
ResultSet ob¡ect.
ßecuuse u ResultSet ob¡ect muy contuín more thun one row, }DßC provídes u method
numed next() thut uííows you to step through euch row stored ín u ResultSet ob¡ect. You
must cuíí the next() method to uccess the lírst row ín the ResultSet ob¡ect, und euch
successíve cuíí to next() steps to the next row. \hen there ure no more rows ín the
ResultSet ob¡ect to reud, the next() method returns the ßooíeun false vuíue.
Ckuy, íet's get buck to our exumpíe: we huve u ResultSet ob¡ect numed
customerResultSet thut hus líve rows contuíníng the coíumn vuíues retríeved lrom
the customer_id, first_name, last_name, dob, und phone coíumns ín the customers
tubíe. 1he loííowíng exumpíe shows u while íoop thut reuds the coíumn vuíues lrom
customerResultSet ínto the customerId, firstName, lastName, dob, und phone
ob¡ects creuted eurííer:
while (customerResultSet.next()) {
customerId = customerResultSet.getInt("customer_id");
firstName = customerResultSet.getString("first_name");
lastName = customerResultSet.getString("last_name");
dob = customerResultSet.getDate("dob");
phone = customerResultSet.getString("phone");
System.out.println("customerId = " + customerId);
System.out.println("firstName = " + firstName);
System.out.println("lastName = " + lastName);
System.out.println("dob = " + dob);
System.out.println("phone = " + phone);
} // end of while loop
\hen there ure no more rows to reud lrom customerResultSet, the next() method
returns false und the íoop termínutes. You'íí notíce thut the exumpíe pusses the nume ol the
coíumn to be reud, ruther thun numeríc posítíons, to the get methods. Aíso, l've copíed
the coíumn vuíues ínto }uvu vuríubíes und ob¡ects, lor exumpíe, the vuíue returned lrom
customerResultSet.getInt("customer_id") ís copíed to customerId. You don't
huve to do thut copy: you couíd símpíy use the get method cuíí whenever you need the vuíue.
However, ít ís generuííy better íl you copy ít to u }uvu vuríubíe or ob¡ect, becuuse ít wííí suve tíme
íl you use thut vuíue more thun once (the tíme ís suved becuuse you don't huve to cuíí the get
method uguín).
Stcp 3: CIusc thc RcsuItSct Objcct
Cnce you've líníshed wíth your ResultSet ob¡ect, you must cíose thut ResultSet ob¡ect
usíng the close() method. 1he loííowíng exumpíe cíoses customerResultSet:
customerResultSet.close();
Chupter l5: Runníng SQL Lsíng }uvu
S47
NOTf
í| í· ímpor|an| |ha| ,ou rcmcmbcr |o cío·c ,our ResultSet ob]cc|
oncc ,ou'vc |íní·hcd ví|h í|. Doíng ·o cn·urc· |ha| |hc ob]cc| í·
·chcduícd |or garbagc coíícc|íon.
Now thut you've seen how to retríeve rows, l'íí show you how to udd rows to u dutubuse tubíe
usíng }DßC.
Adding Ruws tu thc Databasc
You use the SQL INSERT stutement to udd rows to u tubíe. 1here ure two muín wuys you cun
perlorm un INSERT stutement usíng }DßC:
Lse the executeUpdate() method delíned ín the Statement cíuss.
Lse the execute() method delíned ín the PreparedStatement cíuss. (l wííí díscuss
thís cíuss íuter ín thís chupter.)
1he exumpíes ín thís sectíon íííustrute how to udd u row to the customers tubíe. 1he
customer_id, first_name, last_name, dob, und phone coíumns lor thís new row wííí
be set to 6, }uson, lríce, lebruury 22, l969, und 800-555-l2l6, respectíveíy.
1o udd thís new row, l'íí use the sume Statement ob¡ect decíured eurííer (myStatement),
uíong wíth the sume vuríubíes und ob¡ects thut were used to retríeve the rows lrom the customers
tubíe ín the prevíous sectíon. lírst oll, l'íí set those vuríubíes und ob¡ects to the vuíues thut l wunt
to set the dutubuse coíumns to ín the customers tubíe:
customerId = 6;
firstName = "Jason";
lastName = "Red";
dob = java.sql.Date.valueOf("1969-02-22");
phone = "800-555-1216";
NOTf
Thc java.sql.Date cía·· ·|orc· da|c· u·íng |hc |orma| YYYY-MM-
DD, vhcrc YYYY í· |hc ,car, MM í· |hc mon|h numbcr, and DD í· |hc
da, numbcr. You can aí·o u·c |hc java.sql.Time and java.sql
.Timestamp cía··c· |o rcprc·cn| |ímc· and da|c· con|aíníng |ímc·,
rc·pcc|ívcí,.
\hen you uttempt to specíly u dute ín un SQL stutement, you lírst convert ít to u lormut thut
the dutubuse cun understund by usíng the TO_DATE() buíít-ín dutubuse lunctíon. TO_DATE()
uccepts u stríng contuíníng u dute, uíong wíth the lormut lor thut dute. You'íí see the use ol the
TO_DATE() lunctíon shortíy ín the INSERT stutement exumpíe. Luter ín thís chupter, l'íí díscuss
the Crucíe }DßC extensíons, und you'íí see u superíor wuy ol representíng Crucíe-specílíc dutes
usíng the oracle.sql.DATE type.
\e're reudy to perlorm un INSERT to udd the new row to the customers tubíe. 1he
myStatement ob¡ect ís used to perlorm the INSERT stutement, settíng the customer_id,
S48
Crucíe Dutubuse ll SQL
first_name, last_name, dob, und phone coíumn vuíues equuí to the vuíues prevíousíy
set ín the customerId, firstName, lastName, dob, und phone vuríubíes.
myStatement.executeUpdate(
"INSERT INTO customers " +
"(customer_id, first_name, last_name, dob, phone) VALUES (" +
customerId + ", '" + firstName + "', '" + lastName + "', " +
"TO_DATE('" + dob + "', 'YYYY, MM, DD'), '" + phone + "')"
);
Notíce the use ol the TO_DATE() lunctíon to convert the contents ol the dob ob¡ect to un
ucceptubíe Crucíe dutubuse dute. Cnce thís stutement hus compíeted, the customers tubíe wííí
contuín the new row.
Mudifying Ruws in thc Databasc
You use the SQL UPDATE stutement to modíly exístíng rows ín u tubíe. }ust us wíth perlormíng
un INSERT stutement wíth }DßC, you cun use the executeUpdate() method delíned ín the
Statement cíuss or the execute() method delíned ín the PreparedStatement cíuss. Lse
ol the PreparedStatement cíuss ís covered íuter ín thís chupter.
1he loííowíng exumpíe íííustrutes how to modíly the row where the customer_id coíumn ís
equuí to l:
first_name = "Jean";
myStatement.executeUpdate(
"UPDATE customers " +
"SET first_name = '" + firstName + "' " +
"WHERE customer_id = 1"
);
Alter thís stutement runs, customer rl's lírst nume wííí be set to "Jean".
DcIcting Ruws frum thc Databasc
You use the SQL DELETE stutement to deíete exístíng rows lrom u tubíe. You cun use the
executeUpdate() method delíned ín the Statement cíuss or the execute() method
delíned ín the PreparedStatement cíuss.
1he loííowíng exumpíe íííustrutes how to deíete customer r5 lrom the customers tubíe:
myStatement.executeUpdate(
"DELETE FROM customers " +
"WHERE customer_id = 5"
);
Alter thís stutement runs, the row lor customer r5 wííí huve been removed lrom the
customers tubíe.
Chupter l5: Runníng SQL Lsíng }uvu
S49
HandIing Numbcrs
1hís sectíon descríbes the íssues ussocíuted wíth storíng numbers ín your }uvu progrums. An Crucíe
dutubuse ís cupubíe ol storíng numbers wíth u precísíon ol up to 38 dígíts. ln the context ol number
representutíon, precísíon relers to the uccurucy wíth whích u líoutíng-poínt number muy be
represented ín u dígítuí computer's memory. 1he 38 dígíts íeveí ol precísíon ollered by the
dutubuse uííows you to store very íurge numbers.
1hut precísíon cupubíííty ís líne when workíng wíth numbers ín the dutubuse, but }uvu uses íts
own set ol types to represent numbers. 1hís meuns you must be cureluí when seíectíng the }uvu
type thut wííí be used to represent numbers ín your progrums, especíuííy íl those numbers ure
goíng to be stored ín u dutubuse.
1o store íntegers ín your }uvu progrum, you cun use the short, int, long, or java.math
.BigInteger types, dependíng on how bíg the ínteger you wunt to store ís. 1ubíe l5-4 shows
the number ol bíts used to store short, int, und long types, uíong wíth the íow und hígh
vuíues supported by euch type.
1o store líoutíng-poínt numbers ín your }uvu progrums, you cun use the float, double,
or java.math.BigDecimal types. 1ubíe l5-5 shows the sume coíumns us 1ubíe l5-4 lor the
float und double types, uíong wíth the precísíon supported by euch ol these types.
As you cun see, u float muy be used to store líoutíng-poínt numbers wíth u precísíon ol up
to 6 dígíts, und u double muy be used lor líoutíng-poínt numbers wíth u precísíon ol up to l5
dígíts. ll you huve u líoutíng-poínt number thut requíres more thun l5 dígíts ol precísíon lor storuge
ín your }uvu progrum, you cun use the java.math.BigDecimal type, whích cun store un
urbítrurííy íong líoutíng-poínt number.
ln uddítíon to these types, there ís one ol the Crucíe }DßC extensíon types you cun use to
store your íntegers or líoutíng-poínt numbers. 1hís type ís oracle.sql.NUMBER, und ít uííows
you to store numbers wíth up to 38 dígíts ol precísíon. You'íí íeurn more ubout the oracle.sql
.NUMBER type íuter ín thís chupter. ln Crucíe Dutubuse l0g und ubove, you cun use the oracle
.sql.BINARY_FLOAT und oracle.sql.BINARY_DOUBLE types. 1hese types uííow you to
store the BINARY_FLOAT und BINARY_DOUBLE numbers.
Let's tuke u íook ut some exumpíes ol usíng these ínteger und líoutíng-poínt types to store the
product_id und price coíumn vuíues lor u row retríeved lrom the products tubíe. Assume
thut u ResultSet ob¡ect numed productResultSet hus been popuíuted wíth the product_
id und price coíumns lor u row lrom the products tubíe. 1he product_id coíumn ís delíned
Typc Bits luw VaIuc High VaIuc
short
l6 32768 32767
int
32 2l47483648 2l47483647
long
64 9223372036854775808 9223372036854775807
TABlf 1S-4 Thc short, int, and long T,pc·
SS0
Crucíe Dutubuse llg SQL
us u dutubuse INTEGER, und the príce coíumn ís delíned us u dutubuse NUMBER. 1he loííowíng
exumpíe creutes vuríubíes ol the vuríous ínteger und líoutíng-poínt types und retríeves the
product_id und price coíumn vuíues ínto those vuríubíes:
short productIdShort = productResultSet.getShort("product_id");
int productIdInt = productResultSet.getInt("product_id");
long productIdLong = productResultSet.getLong("product_id");
float priceFloat = productResultSet.getFloat("price");
double priceDouble = productResultSet.getDouble("price");
java.math.BigDecimal priceBigDec = productResultSet.getBigDecimal("price");
Notíce the use ol the díllerent get methods to retríeve the coíumn vuíues us the díllerent
types, the output ol whích ís then stored ín u }uvu vuríubíe ol the uppropríute type.
HandIing Databasc NuII VaIucs
A coíumn ín u dutubuse tubíe muy be delíned us beíng NULL or NOT NULL. NULL índícutes thut
the coíumn muy store u NULL vuíue, NOT NULL índícutes thut the coíumn muy not contuín u
NULL vuíue. A NULL vuíue meuns thut the vuíue ís unknown. \hen u tubíe ís creuted ín the
dutubuse und you don't specíly thut u coíumn ís NULL or NOT NULL, the dutubuse ussumes you
meun NULL.
1he }uvu ob¡ect types, such us String, muy be used to store dutubuse NULL vuíues. \hen u
query ís used to retríeve u coíumn thut contuíns u NULL vuíue ínto u }uvu String, thut String
wííí contuín u }uvu null vuíue. lor exumpíe, the phone coíumn (u VARCHAR2) lor customer r5
ís NULL, und the loííowíng stutement uses the getString() method to reud thut vuíue ínto u
String numed phone:
phone = customerResultSet.getString("phone");
Cnce the stutement ís run, the phone }uvu String wííí contuín the }uvu null vuíue.
1hut method's líne lor NULL vuíues beíng stored ín }uvu ob¡ects, but whut ubout the }uvu
numeríc, íogícuí, und bít type types: ll you retríeve u NULL vuíue ínto u }uvu numeríc, íogícuí, or
bít vuríubíeint, float, boolean, or byte, lor exumpíethut vuríubíe wííí contuín the vuíue
zero. 1o the dutubuse, zero und NULL ure díllerent vuíues: zero ís u delíníte vuíue, NULL meuns
the vuíue ís unknown. 1hís cuuses u probíem íl you wunt to díllerentíute between zero und NULL
ín your }uvu progrum.
1here ure two wuys to get uround thís probíem:
You cun use the wasNull() method ín the ResultSet. 1he wasNull() method
returns true íl the vuíue retríeved lrom the dutubuse wus NULL, otherwíse, the method
returns false.
Typc Bits luw VaIuc High VaIuc Prccisiun
float
32 3.4L+38 3.4L+38 6 dígíts
double
64 l.7L+308 l.7L+308 l5 dígíts
TABlf 1S-S Thc float and double T,pc·
Chupter l5: Runníng SQL Lsíng }uvu

You cun use u }uvu vrappcr cía··. A wrupper cíuss ís u }uvu cíuss thut uííows you to delíne
u vrappcr ob]cc|, whích cun then be used to store the coíumn vuíue returned lrom the
dutubuse. A wrupper ob¡ect stores dutubuse NULL vuíues us }uvu null vuíues, und non-
NULL vuíues ure stored us reguíur vuíues.
Let's tuke u íook ut un exumpíe thut íííustrutes the use ol lírst techníque, usíng product rl2
lrom the products tubíe. 1hís row hus u NULL vuíue ín the product_type_id coíumn, und
thís coíumn ís delíned us u dutubuse INTEGER. Aíso, ussume thut u ResultSet ob¡ect numed
productResultSet hus been popuíuted wíth the product_id und product_type_id
coíumns lor product rl2 lrom the products tubíe. 1he loííowíng exumpíe uses the wasNull()
method to check íl the vuíue reud lor the product_type_id coíumn wus NULL:
System.out.println("product_type_id = " +
productResultSet.getInt("product_type_id"));
if (productResultSet.wasNull()) {
System.out.println("Last value read was NULL");
}
ßecuuse the product_type_id coíumn contuíns u NULL vuíue, wasNull() wííí return
true, und so the stríng "Last value read was NULL" wouíd be díspíuyed.
ßelore you see un exumpíe ol the second method thut uses the }uvu wrupper cíusses, l need
to expíuín whut these wrupper cíusses uctuuííy ure. 1he wrupper cíusses ure delíned ín the java
.lang puckuge, wíth the loííowíng seven wrupper cíusses beíng delíned ín thut puckuge:
java.lang.Short
java.lang.Integer
java.lang.Long
java.lang.Float
java.lang.Double
java.lang.Boolean
java.lang.Byte
Cb¡ects decíured usíng these wrupper cíusses cun be used to represent dutubuse NULL vuíues
lor the vuríous types ol numbers us weíí us lor the Boolean type. \hen u dutubuse NULL ís
retríeved ínto such un ob¡ect, ít wííí contuín the }uvu null vuíue. 1he loííowíng exumpíe decíures
u java.lang.Integer numed productTypeId:
java.lang.Integer productTypeId;
A dutubuse NULL muy then be stored ín productTypeId usíng u cuíí to the getObject()
method, us shown ín the loííowíng exumpíe:
productTypeId =
(java.lang.Integer) productResultSet.getObject("product_type_id");
1he getObject() method returns un ínstunce ol the java.lang.Object cíuss und must
be cust ínto un uppropríute type, ín thís cuse, to u java.lang.Integer. Assumíng thís exumpíe
SS2
Crucíe Dutubuse llg SQL
reuds the sume row lrom productResultSet us the prevíous exumpíe, getObject() wííí
return u }uvu null vuíue, und thís vuíue wííí be copíed ínto productTypeId. Cl course, íl the
vuíue retríeved lrom the dutubuse hud u vuíue other thun NULL, productTypeId wouíd contuín
thut vuíue. lor exumpíe, íl the vuíue retríeved lrom the dutubuse wus l, productTypeId wouíd
contuín the vuíue l.
You cun uíso use u wrupper ob¡ect ín u }DßC stutement thut perlorms un INSERT or UPDATE
to set u coíumn to u reguíur vuíue or u NULL vuíue. ll you wunt to set u coíumn vuíue to NULL
usíng u wrupper ob¡ect, you wouíd set thut wrupper ob¡ect to null und use ít ín un INSERT or
UPDATE stutement to set the dutubuse coíumn to NULL. 1he loííowíng exumpíe sets the price
coíumn lor product rl2 to NULL usíng u java.lang.Double ob¡ect thut ís set to null:
java.lang.Double price = null;
myStatement.executeUpdate(
"UPDATE products " +
"SET price = " + price + " " +
"WHERE product_id = 12"
);
CuntruIIing Databasc Transactiuns
ln Chupter 8 you íeurned ubout dutubuse trunsuctíons und how to use the SQL COMMIT stutement
to permunentíy record chunges you muke to the contents ol tubíes. You uíso suw how to use the
ROLLBACK stutement to undo chunges ín u dutubuse trunsuctíon. 1he sume concepts uppíy to
SQL stutements executed usíng }DßC stutements wíthín your }uvu progrums.
ßy deluuít, the resuíts ol your INSERT, UPDATE, und DELETE stutements executed usíng
}DßC ure ímmedíuteíy commítted. 1hís ís known us au|o-commí| mode. Ceneruííy, usíng uuto-
commít mode ís no| the prelerred wuy ol commíttíng chunges, becuuse ít ís counter to the ídeu
ol consíderíng trunsuctíons us íogícuí uníts ol work. \íth uuto-commít mode, uíí stutements ure
consídered us índívíduuí trunsuctíons, und thís ussumptíon ís usuuííy íncorrect. Aíso, uuto-commít
mode muy cuuse your SQL stutements to tuke íonger to compíete, due to the luct thut euch
stutement ís uíwuys commítted.
lortunuteíy, you cun enubíe or dísubíe uuto-commít mode usíng the setAutoCommit()
method ol the Connection cíuss, pussíng ít u ßooíeun true or false vuíue. 1he loííowíng
exumpíe dísubíes uuto-commít mode lor the Connection ob¡ect numed myConnection:
myConnection.setAutoCommit(false);
TlP
You ·houíd dí·abíc au|o-commí| modc. Doíng |hí· vííí u·uaíí, ma|c
,our program· run |a·|cr.
Cnce uuto-commít hus been dísubíed, you cun commít your trunsuctíon chunges usíng the
commit() method ol the Connection cíuss, or you cun roíí buck your chunges usíng the
rollback() method. ln the loííowíng exumpíe, the commit() method ís used to commít
chunges mude to the dutubuse usíng the myConnection ob¡ect:
myConnection.commit();
ln the next exumpíe, the rollback() method ís used to roíí buck chunges mude to the
dutubuse:
myConnection.rollback();
Chupter l5: Runníng SQL Lsíng }uvu
SS3
ll uuto-commít hus been dísubíed und you cíose your Connection ob¡ect, un ímpíícít
commít ís perlormed. 1herelore, uny DML stutements you huve perlormed up to thut poínt und
huven't uíreudy commítted wííí be commítted uutomutícuííy.
Pcrfurming Data Dcfinitiun languagc Statcmcnts
1he SQL Dutu Delínítíon Lunguuge (DDL) stutements ure used to creute dutubuse users, tubíes,
und muny other types ol dutubuse structures thut muke up u dutubuse. DDL consísts ol stutements
such us CREATE, ALTER, DROP, TRUNCATE, und RENAME. DDL stutements muy be perlormed
ín }DßC usíng the execute() method ol the Statement cíuss. ln the loííowíng exumpíe, the
CREATE TABLE stutement ís used to creute u tubíe numed addresses, whích muy be used to
store customer uddresses:
myStatement.execute(
"CREATE TABLE addresses (" +
" address_id INTEGER CONSTRAINT addresses_pk PRIMARY KEY," +
" customer_id INTEGER CONSTRAINT addresses_fk_customers " +
" REFERENCES customers(customer_id)," +
" street VARCHAR2(20) NOT NULL," +
" city VARCHAR2(20) NOT NULL," +
" state CHAR(2) NOT NULL" +
")"
);
NOTf
ícr|ormíng a DDí ·|a|cmcn| rc·uí|· ín an ímpíící| commí| bcíng
í··ucd. Thcrc|orc, í| ,ou'vc pcr|ormcd uncommí||cd D\í ·|a|cmcn|·
príor |o í··uíng a DDí ·|a|cmcn|, |ho·c D\í ·|a|cmcn|· vííí aí·o bc
commí||cd.
HandIing fxccptiuns
\hen un error occurs ín eíther the dutubuse or the }DßC dríver, u java.sql.SQLException
wííí be ruísed. 1he java.sql.SQLException cíuss ís u subcíuss ol the java.lang.Exception
cíuss. lor thís reuson, you must píuce uíí your }DßC stutements wíthín u try/catch stutement ín
order lor your code not to throw u java.sql.SQLException. \hen such un exceptíon occurs,
}uvu uttempts to íocute the uppropríute hundíer to process the exceptíon.
ll you íncíude u hundíer lor u java.sql.SQLException ín u catch cíuuse, when un error
occurs ín eíther the dutubuse or the }DßC dríver, }uvu wííí move to thut hundíer und run the
uppropríute code thut you've íncíuded ín thut catch cíuuse. ln the hundíer code, you cun do
thíngs ííke díspíuy the error code und error messuge, whích wííí heíp you determíne whut huppened.
1he loííowíng try/catch stutement contuíns u hundíer lor exceptíons ol type java.sql
.SQLException thut muy occur ín the try stutement:
try {
...
} catch (SQLException e) {
...
}
SS4
Crucíe Dutubuse llg SQL
NOTf
í'm a··umíng java.sql.* ha· bccn ímpor|cd, ·o í can ·ímpí, u·c
SQLException ín |hc ca|ch, ra|hcr |han havíng |o rc|crcncc java
.sql.SQLException.
1he try stutement wííí contuín your }DßC stutements thut muy cuuse un SQLException to
be thrown, und the catch cíuuse wííí contuín your error hundííng code.
1he SQLException cíuss delínes lour methods thut ure useluí lor líndíng out whut cuused
the exceptíon to occur:
getErrorCode() ln the cuse ol errors thut occur ín the dutubuse or the }DßC dríver,
thís method returns the Crucíe error code, whích ís u líve-dígít number.
getMessage() ln the cuse ol errors thut occur ín the dutubuse, thís method returns the
error messuge uíong wíth the líve-dígít Crucíe error code. ln the cuse ol errors thut occur
ín the }DßC dríver, thís method returns ¡ust the error messuge.
getSQLState() ln the cuse ol errors thut occur ín the dutubuse, thís method returns
u líve-dígít code contuíníng the SQL stute. ln the cuse ol errors thut occur ín the }DßC
dríver, thís method doesn't return unythíng ol ínterest.
printStackTrace() 1hís method díspíuys the contents ol the stuck when the
exceptíon occurred. 1hís ínlormutíon muy lurther ussíst you ín líndíng out whut went wrong.
1he loííowíng try/catch stutement íííustrutes the use ol these lour methods:
try {
...
} catch (SQLException e) {
System.out.println("Error code = " + e.getErrorCode());
System.out.println("Error message = " + e.getMessage());
System.out.println("SQL state = " + e.getSQLState());
e.printStackTrace();
}
ll your code throws un SQLException ruther thun hundííng ít íocuííy us ¡ust shown, }uvu wííí
seurch lor un uppropríute hundíer ín the cuíííng procedure or lunctíon untíí one ís lound. ll none
ís lound, the exceptíon wííí be hundíed by the deluuít exceptíon hundíer, whích díspíuys the
Crucíe error code, the error messuge, und the stuck truce.
CIusing Yuur |DBC Objccts
ln the exumpíes shown ín thís chupter, l've creuted u number ol }DßC ob¡ects: u Connection
ob¡ect numed myConnection, u Statement ob¡ect numed myStatement, und two
ResultSet ob¡ects numed customerResultSet und productResultSet. ResultSet
ob¡ects shouíd be cíosed when they ure no íonger needed usíng the close() method. Símííuríy,
you shouíd uíso cíose the Statement und Connection ob¡ects when those ob¡ects ure no
íonger needed.
ln the loííowíng exumpíe, the myStatement und myConnection ob¡ects ure cíosed usíng
the close() method:
Chupter l5: Runníng SQL Lsíng }uvu

myStatement.close();
myConnection.close();
You shouíd typícuííy cíose your Statement und Connection ob¡ects ín u finally cíuuse.
Any code contuíned ín u finally cíuuse ís guurunteed to be run, no mutter how controí íeuves
the try stutement. ll you wunt to udd u finally cíuuse to cíose your Statement und
Connection ob¡ects, those ob¡ects shouíd be decíured belore the lírst try/catch stutement
used to trup exceptíons. 1he loííowíng exumpíe shows how to structure the main() method
so thut the Statement und Connection ob¡ects muy be cíosed ín u finally cíuuse:
public static void main (String args []) {
// declare Connection and Statement objects
Connection myConnection = null;
Statement myStatement = null;
try {
// register the Oracle JDBC drivers
DriverManager.registerDriver(
new oracle.jdbc.driver.OracleDriver()
);
// connect to the database as store
// using the Oracle JDBC Thin driver
myConnection = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:ORCL",
"store",
"store_password"
);
// create a Statement object
myStatement = myConnection.createStatement();
// more of your code goes here
...
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
// close the Statement object using the close() method
if (myStatement != null) {
myStatement.close();
}
// close the Connection object using the close() method
if (myConnection != null) {
myConnection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
} // end of main()
SS6
Crucíe Dutubuse ll SQL
Notíce thut the code ín the finally cíuuse checks to see íl the Statement und Connection
ob¡ects ure not equuí to null belore cíosíng them usíng the close() method. ll they ure equuí
to null, there ís no need to cíose them. ßecuuse the code ín the finally cíuuse ís the íust thíng
to be run und ís guurunteed to be run, the Statement und Connection ob¡ects ure uíwuys
cíosed, regurdíess ol whut eíse huppens ín your progrum. lor the suke ol brevíty, oníy the
lírst progrum leutured ín thís chupter uses u finally cíuuse to cíose the Statement und
Connection ob¡ects.
You huve now seen how to wríte }DßC stutements thut connect to u dutubuse, run DML und
DDL stutements, controí trunsuctíons, hundíe exceptíons, und cíose }DßC ob¡ects. 1he loííowíng
sectíon contuíns u compíete progrum thut íííustrutes the use ol }DßC.
fxampIc Prugram: BasicfxampIc1.java
1he BasicExample1.java progrum íííustrutes the concepts covered ín thís chupter so lur. 1hís
progrum und the other progrums leutured ín thís chupter muy be lound ín the Java loíder where you
extructed thís book's Zíp lííe. Aíí the progrums contuín detuííed comments thut you shouíd study.
/*
BasicExample1.java shows how to:
- import the JDBC packages
- load the Oracle JDBC drivers
- connect to a database
- perform DML statements
- control transactions
- use ResultSet objects to retrieve rows
- use the get methods
- perform DDL statements
*/
// import the JDBC packages
import java.sql.*;
public class BasicExample1 {
public static void main (String args []) {
// declare Connection and Statement objects
Connection myConnection = null;
Statement myStatement = null;
try {
// register the Oracle JDBC drivers
DriverManager.registerDriver(
new oracle.jdbc.OracleDriver()
);
// EDIT AS NECESSARY TO CONNECT TO YOUR DATABASE
// create a Connection object, and connect to the database
// as the store user using the Oracle JDBC Thin driver
myConnection = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:ORCL",
"store",
Chupter l5: Runníng SQL Lsíng }uvu

"store_password"
);
// disable auto-commit mode
myConnection.setAutoCommit(false);
// create a Statement object
myStatement = myConnection.createStatement();
// create variables and objects used to represent
// column values
int customerId = 6;
String firstName = "Jason";
String lastName = "Red";
java.sql.Date dob = java.sql.Date.valueOf("1969-02-22");
java.sql.Time dobTime;
java.sql.Timestamp dobTimestamp;
String phone = "800-555-1216";
// perform SQL INSERT statement to add a new row to the
// customers table using the values set in the previous
// step - the executeUpdate() method of the Statement
// object is used to perform the INSERT
myStatement.executeUpdate(
"INSERT INTO customers " +
"(customer_id, first_name, last_name, dob, phone) VALUES (" +
customerId + ", '" + firstName + "', '" + lastName + "', " +
"TO_DATE('" + dob + "', 'YYYY, MM, DD'), '" + phone + "')"
);
System.out.println("Added row to customers table");
// perform SQL UPDATE statement to modify the first_name
// column of customer #1
firstName = "Jean";
myStatement.executeUpdate(
"UPDATE customers " +
"SET first_name = '" + firstName + "' " +
"WHERE customer_id = 1"
);
System.out.println("Updated row in customers table");
// perform SQL DELETE statement to remove customer #5
myStatement.executeUpdate(
"DELETE FROM customers " +
"WHERE customer_id = 5"
);
System.out.println("Deleted row from customers table");
// create a ResultSet object, and populate it with the
// result of a SELECT statement that retrieves the
// customer_id, first_name, last_name, dob, and phone columns

Crucíe Dutubuse ll SQL
// for all the rows from the customers table - the
// executeQuery() method of the Statement object is used
// to perform the SELECT
ResultSet customerResultSet = myStatement.executeQuery(
"SELECT customer_id, first_name, last_name, dob, phone " +
"FROM customers"
);
System.out.println("Retrieved rows from customers table");
// loop through the rows in the ResultSet object using the
// next() method, and use the get methods to read the values
// retrieved from the database columns
while (customerResultSet.next()) {
customerId = customerResultSet.getInt("customer_id");
firstName = customerResultSet.getString("first_name");
lastName = customerResultSet.getString("last_name");
dob = customerResultSet.getDate("dob");
dobTime = customerResultSet.getTime("dob");
dobTimestamp = customerResultSet.getTimestamp("dob");
phone = customerResultSet.getString("phone");
System.out.println("customerId = " + customerId);
System.out.println("firstName = " + firstName);
System.out.println("lastName = " + lastName);
System.out.println("dob = " + dob);
System.out.println("dobTime = " + dobTime);
System.out.println("dobTimestamp = " + dobTimestamp);
System.out.println("phone = " + phone);
} // end of while loop
// close the ResultSet object using the close() method
customerResultSet.close();
// roll back the changes made to the database
myConnection.rollback();
// create numeric variables to store the product_id and price columns
short productIdShort;
int productIdInt;
long productIdLong;
float priceFloat;
double priceDouble;
java.math.BigDecimal priceBigDec;
// create another ResultSet object and retrieve the
// product_id, product_type_id, and price columns for product #12
// (this row has a NULL value in the product_type_id column)
ResultSet productResultSet = myStatement.executeQuery(
"SELECT product_id, product_type_id, price " +
"FROM products " +
"WHERE product_id = 12"
);
Chupter l5: Runníng SQL Lsíng }uvu

System.out.println("Retrieved row from products table");
while (productResultSet.next()) {
System.out.println("product_id = " +
productResultSet.getInt("product_id"));
System.out.println("product_type_id = " +
productResultSet.getInt("product_type_id"));
// check if the value just read by the get method was NULL
if (productResultSet.wasNull()) {
System.out.println("Last value read was NULL");
}
// use the getObject() method to read the value, and convert it
// to a wrapper object - this converts a database NULL value to a
// Java null value
java.lang.Integer productTypeId =
(java.lang.Integer) productResultSet.getObject("product_type_id");
System.out.println("productTypeId = " + productTypeId);
// retrieve the product_id and price column values into
// the various numeric variables created earlier
productIdShort = productResultSet.getShort("product_id");
productIdInt = productResultSet.getInt("product_id");
productIdLong = productResultSet.getLong("product_id");
priceFloat = productResultSet.getFloat("price");
priceDouble = productResultSet.getDouble("price");
priceBigDec = productResultSet.getBigDecimal("price");
System.out.println("productIdShort = " + productIdShort);
System.out.println("productIdInt = " + productIdInt);
System.out.println("productIdLong = " + productIdLong);
System.out.println("priceFloat = " + priceFloat);
System.out.println("priceDouble = " + priceDouble);
System.out.println("priceBigDec = " + priceBigDec);
} // end of while loop
// close the ResultSet object
productResultSet.close();
// perform SQL DDL CREATE TABLE statement to create a new table
// that may be used to store customer addresses
myStatement.execute(
"CREATE TABLE addresses (" +
" address_id INTEGER CONSTRAINT addresses_pk PRIMARY KEY," +
" customer_id INTEGER CONSTRAINT addresses_fk_customers " +
" REFERENCES customers(customer_id)," +
" street VARCHAR2(20) NOT NULL," +
" city VARCHAR2(20) NOT NULL," +
" state CHAR(2) NOT NULL" +
")"
);
System.out.println("Created addresses table");
S60
Crucíe Dutubuse llg SQL
// drop this table using the SQL DDL DROP TABLE statement
myStatement.execute("DROP TABLE addresses");
System.out.println("Dropped addresses table");
} catch (SQLException e) {
System.out.println("Error code = " + e.getErrorCode());
System.out.println("Error message = " + e.getMessage());
System.out.println("SQL state = " + e.getSQLState());
e.printStackTrace();
} finally {
try {
// close the Statement object using the close() method
if (myStatement != null) {
myStatement.close();
}
// close the Connection object using the close() method
if (myConnection != null) {
myConnection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
} // end of main()
}
NOTf
You ma, nccd |o cdí| |hc íínc íabcícd ví|h |hc |cx| EDIT AS
NECESSARY... ví|h |hc corrcc| ·c||íng· |o accc·· ,our da|aba·c.
CumpiIc BasicfxampIc1
1o compííe BasicExample1.java, you type the loííowíng commund usíng your operutíng
system commund prompt:
javac BasicExample1.java
ll you huven't set the CLASSPATH envíronment vuríubíe properíy, you'íí get the loííowíng
error messuge when tryíng to compííe the FirstExample.java progrum:
FirstExample.java:22: cannot resolve symbol
symbol : class OracleDriver
location: package jdbc
new oracle.jdbc.OracleDriver()
^
1 error
You shouíd check the settíng lor your CLASSPATH envíronment vuríubíeít's ííkeíy your
CLASSPATH ís míssíng the Crucíe }DßC cíusses lííe (ojdbc6.jar, lor exumpíe). Reler to the
eurííer sectíon ºSettíng the CLASSlA1H Lnvíronment Vuríubíe.¨
TlP
You can cn|cr javac -help |o gc| hcíp on |hc }ava compíícr.
Chupter l5: Runníng SQL Lsíng }uvu
S61
Run BasicfxampIc1
Cnce BasicExample1.java ís compííed, you cun run the resuítíng executubíe cíuss lííe
(numed BasicExample1.class) by enteríng the loííowíng commund:
java BasicExample1
CAUTlON
}ava í· ca·c-·cn·í|ívc, ·o ma|c ·urc ,ou cn|cr BasicExample1 ví|h
uppcrca·c ß and í charac|cr·.
ll the progrum luíís wíth the loííowíng error code und messuge, ít meuns the store user wíth
u pussword ol store_password doesn't exíst ín your dutubuse:
Error code = 1017
Error message = ORA-01017: invalid username/password; logon denied
ll you get thís error, check thut the store user ís ín the dutubuse.
1he progrum muy uíso be unubíe to línd your dutubuse, ín whích cuse you'íí get the loííowíng
error:
Error code = 17002
Error message = Io exception: The Network Adapter could not establish
the connection
1ypícuííy, there ure two reusons why you míght get thís error:
1here ís no dutubuse runníng on your localhost muchíne wíth the Crucíe SlD ol ORCL.
Crucíe Net ís not runníng or ís not íísteníng lor connectíons on port l52l.
You shouíd ensure thut you huve the ríght connectíon stríng ín the progrum und uíso thut the
dutubuse und Crucíe Net ure runníng.
Assumíng the progrum runs, you shouíd get the loííowíng output:
Added row to customers table
Updated row in customers table
Deleted row from customers table
Retrieved rows from customers table
customerId = 1
firstName = Jean
lastName = Brown
dob = 1965-01-01
dobTime = 00:00:00
dobTimestamp = 1965-01-01 00:00:00.0
phone = 800-555-1211
customerId = 2
firstName = Cynthia
lastName = Green
dob = 1968-02-05
dobTime = 00:00:00
dobTimestamp = 1968-02-05 00:00:00.0
phone = 800-555-1212
S62
Crucíe Dutubuse llg SQL
customerId = 3
firstName = Steve
lastName = White
dob = 1971-03-16
dobTime = 00:00:00
dobTimestamp = 1971-03-16 00:00:00.0
phone = 800-555-1213
customerId = 4
firstName = Gail
lastName = Black
dob = null
dobTime = null
dobTimestamp = null
phone = 800-555-1214
customerId = 6
firstName = Jason
lastName = Red
dob = 1969-02-22
dobTime = 00:00:00
dobTimestamp = 1969-02-22 00:00:00.0
phone = 800-555-1216
Retrieved row from products table
product_id = 12
product_type_id = 0
Last value read was NULL
productTypeId = null
productIdShort = 12
productIdInt = 12
productIdLong = 12
priceFloat = 13.49
priceDouble = 13.49
priceBigDec = 13.49
Created addresses table
Dropped addresses table
Prcparcd SQl Statcmcnts
\hen you send un SQL stutement to the dutubuse, the dutubuse soltwure reuds the SQL stutement
und verílíes thut ít ís correct. 1hís ís known us par·íng the SQL stutement. 1he dutubuse soltwure
then buííds u píun, known us the cxccu|íon pían, to uctuuííy run the stutement. So lur, uíí the SQL
stutements sent to the dutubuse through }DßC huve requíred u new executíon píun to be buíít.
1hís ís becuuse euch SQL stutement sent to the dutubuse hus been díllerent.
Suppose you hud u }uvu uppíícutíon thut wus perlormíng the sume INSERT stutement repeutedíy,
un exumpíe ís íoudíng muny new products to our exumpíe store, u process thut wouíd requíre
uddíng íots ol rows to the products tubíe usíng INSERT stutements. Let's see }uvu stutements
thut wouíd uctuuííy do thís. Assume thut u cíuss numed Product hus been delíned us loííows:
class Product {
int productId;
int productTypeId;
String name;
Chupter l5: Runníng SQL Lsíng }uvu

String description;
double price;
}
1he loííowíng code creutes un urruy ol líve Product ob¡ects. ßecuuse the products tubíe
uíreudy contuíns rows wíth product_id vuíues lrom l to l2, the productId uttríbutes lor the
new Product ob¡ects sturt ut l3:
Product [] productArray = new Product[5];
for (int counter = 0; counter < productArray.length; counter ++) {
productArray[counter] = new Product();
productArray[counter].productId = counter + 13; //start at 13
productArray[counter].productTypeId = 1;
productArray[counter].name = "Test product";
productArray[counter].description = "Test product";
productArray[counter].price = 19.95;
} // end of for loop
1o udd the rows to the products tubíe, l'íí use u for íoop thut contuíns u }DßC stutement to
perlorm un INSERT stutement, und the coíumn vuíues wííí come lrom productArray:
Statement myStatement = myConnection.createStatement();
for (int counter = 0; counter < productArray.length; counter ++) {
myStatement.executeUpdate(
"INSERT INTO products " +
"(product_id, product_type_id, name, description, price) VALUES (" +
productArray[counter]. productId + ", " +
productArray[counter]. productTypeId + ", '" +
productArray[counter].name + "', '" +
productArray[counter].description + "', " +
productArray[counter].price + ")"
);
} // end of for loop
Luch íterutíon through the íoop resuíts ín un INSERT stutement beíng sent to the dutubuse.
ßecuuse the stríng representíng euch INSERT stutement contuíns díllerent vuíues, the uctuuí
INSERT sent to the dutubuse ís sííghtíy díllerent euch tíme. 1hís meuns thut the dutubuse creutes
u díllerent executíon píun lor every INSERT stutementvery ínellícíent.
You'íí be gíud to know thut }DßC provídes u better wuy to run such SQL stutements.
lnsteud ol usíng u }DßC Statement ob¡ect to run your SQL stutements, you cun use u }DßC
PreparedStatement ob¡ect. A PreparedStatement ob¡ect uííows you to perlorm the sume
SQL stutement but suppíy díllerent vuíues lor uctuuí executíon ol thut stutement. 1hís ís more
ellícíent becuuse the sume executíon píun ís used by the dutubuse when the SQL stutement ís run.
1he loííowíng exumpíe creutes u PreparedStatement ob¡ect contuíníng un INSERT stutement
símííur to the one used ín the prevíous íoop:
PreparedStatement myPrepStatement = myConnection.prepareStatement(
"INSERT INTO products " +
"(product_id, product_type_id, name, description, price) VALUES (" +
"?, ?, ?, ?, ?"
")"
);

Crucíe Dutubuse llg SQL
1here ure two thíngs you shouíd notíce ubout thís exumpíe:
1he prepareStatement() method ís used to specíly the SQL stutement.
Questíon murk churucters (:) ure used to índícute the posítíons where you wííí íuter
províde vuríubíes to be used when the SQL stutement ís uctuuííy run.
1he posítíons ol the questíon murks ure ímportunt: they ure relerenced uccordíng to theír
posítíon, wíth the lírst questíon murk beíng relerenced usíng number l, the second us number 2,
und so on.
1he process ol suppíyíng }uvu vuríubíes to u prepured stutement ís known us bíndíng the
vuríubíes to the stutement, und the vuríubíes themseíves ure known us bínd varíabíc·. 1o uctuuííy
suppíy vuríubíes to the prepured SQL stutement, you must use set methods. 1hese methods ure
símííur to the get methods díscussed eurííer, except thut set methods ure used to suppíy vuríubíe
vuíues, ruther thun reud them.
lor exumpíe, to bínd u }uvu int vuríubíe numed intVar to the product_id coíumn
ín the PreparedStatement ob¡ect, you use setInt(1, intVar). 1he lírst purumeter
índícutes the numeríc posítíon ol the questíon murk (:) ín the stríng prevíousíy specílíed ín the
prepareStatement() method cuíí. lor thís exumpíe, the vuíue l corresponds to the lírst
questíon murk, whích suppííes u vuíue to the product_id coíumn ín the INSERT stutement.
Símííuríy, to bínd u }uvu String vuríubíe numed stringVar to the name coíumn, you use
setString(3, stringVar), becuuse the thírd questíon murk corresponds to the name
coíumn. Cther methods you cun cuíí ín u PreparedStatement ob¡ect íncíude setFloat()
und setDouble(), whích ure used lor settíng síngíe-precísíon líoutíng-poínt und doubíe-
precísíon líoutíng-poínt numbers.
1he loííowíng exumpíe leutures u íoop thut shows the use ol set methods to bínd the
uttríbutes ol the Product ob¡ects ín productArray to the PreparedStatement ob¡ect,
notíce the execute() method ís used to uctuuííy run the SQL stutement:
for (int counter = 0; counter < productArray.length; counter ++) {
myPrepStatement.setInt(1, productArray[counter]. productId);
myPrepStatement.setInt(2, productArray[counter]. productTypeId);
myPrepStatement.setString(3, productArray[counter].name);
myPrepStatement.setString(4, productArray[counter].description);
myPrepStatement.setDouble(5, productArray[counter].price);
myPrepStatement.execute();
} // end of for loop
Alter thís code ís executed, the products tubíe wííí contuín líve new rows.
1o set u dutubuse coíumn to NULL usíng u PreparedStatement ob¡ect, you muy use the
setNull() method. lor exumpíe, the loííowíng stutement sets the description coíumn
to NULL:
myPrepStatement.setNull(4, java.sql.Types.VARCHAR);
1he lírst purumeter ín the cuíí to setNull() ís the numeríc posítíon ol the coíumn you wunt to
set to NULL. 1he second purumeter ís un int thut corresponds to the dutubuse type ol the coíumn
thut ís to be set to NULL. 1hís second purumeter shouíd be specílíed usíng one ol the constunts
delíned ín the java.sql.Types cíuss. lor u VARCHAR2 coíumn (the description coíumn ís
u VARCHAR2), you shouíd use java.sql.Types.VARCHAR.
Chupter l5: Runníng SQL Lsíng }uvu
S6S
fxampIc Prugram: BasicfxampIc2.java
1he loííowíng BasicExample2.java progrum contuíns the stutements shown ín the prevíous
sectíons.
/*
BasicExample2.java shows how to use prepared SQL statements
*/
// import the JDBC packages
import java.sql.*;
class Product {
int productId;
int productTypeId;
String name;
String description;
double price;
}
public class BasicExample2 {
public static void main (String args []) {
try {
// register the Oracle JDBC drivers
DriverManager.registerDriver(
new oracle.jdbc.OracleDriver()
);
// EDIT AS NECESSARY TO CONNECT TO YOUR DATABASE
// create a Connection object, and connect to the database
// as the store user using the Oracle JDBC Thin driver
Connection myConnection = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:ORCL",
"store",
"store_password"
);
// disable auto-commit mode
myConnection.setAutoCommit(false);
Product [] productArray = new Product[5];
for (int counter = 0; counter < productArray.length; counter ++) {
productArray[counter] = new Product();
productArray[counter].productId = counter + 13;
productArray[counter].productTypeId = 1;
productArray[counter].name = "Test product";
productArray[counter].description = "Test product";
productArray[counter].price = 19.95;
} // end of for loop
// create a PreparedStatement object

Crucíe Dutubuse ll SQL
PreparedStatement myPrepStatement = myConnection.prepareStatement(
"INSERT INTO products " +
"(product_id, product_type_id, name, description, price) VALUES (" +
"?, ?, ?, ?, ?" +
")"
);
// initialize the values for the new rows using the
// appropriate set methods
for (int counter = 0; counter < productArray.length; counter ++) {
myPrepStatement.setInt(1, productArray[counter].productId);
myPrepStatement.setInt(2, productArray[counter].productTypeId);
myPrepStatement.setString(3, productArray[counter].name);
myPrepStatement.setString(4, productArray[counter].description);
myPrepStatement.setDouble(5, productArray[counter].price);
myPrepStatement.execute();
} // end of for loop
// close the PreparedStatement object
myPrepStatement.close();
// retrieve the product_id, product_type_id, name, description, and
// price columns for these new rows using a ResultSet object
Statement myStatement = myConnection.createStatement();
ResultSet productResultSet = myStatement.executeQuery(
"SELECT product_id, product_type_id, " +
" name, description, price " +
"FROM products " +
"WHERE product_id > 12"
);
// display the column values
while (productResultSet.next()) {
System.out.println("product_id = " +
productResultSet.getInt("product_id"));
System.out.println("product_type_id = " +
productResultSet.getInt("product_type_id"));
System.out.println("name = " +
productResultSet.getString("name"));
System.out.println("description = " +
productResultSet.getString("description"));
System.out.println("price = " +
productResultSet.getDouble("price"));
} // end of while loop
// close the ResultSet object using the close() method
productResultSet.close();
// roll back the changes made to the database
myConnection.rollback();
// close the other JDBC objects
Chupter l5: Runníng SQL Lsíng }uvu
S67
myStatement.close();
myConnection.close();
} catch (SQLException e) {
System.out.println("Error code = " + e.getErrorCode());
System.out.println("Error message = " + e.getMessage());
System.out.println("SQL state = " + e.getSQLState());
e.printStackTrace();
}
} // end of main()
}
1he output lrom thís progrum ís us loííows:
product_id = 13
product_type_id = 1
name = Test product
description = Test product
price = 19.95
product_id = 14
product_type_id = 1
name = Test product
description = Test product
price = 19.95
product_id = 15
product_type_id = 1
name = Test product
description = Test product
price = 19.95
product_id = 16
product_type_id = 1
name = Test product
description = Test product
price = 19.95
product_id = 17
product_type_id = 1
name = Test product
description = Test product
price = 19.95
Thc OracIc |DBC fxtcnsiuns
1he Crucíe extensíons to }DßC enubíe you to uccess uíí ol the dutu types províded by Crucíe,
uíong wíth Crucíe-specílíc perlormunce extensíons. You'íí íeurn ubout hundííng ol stríngs,
numbers, dutes, und row ídentílíers ín thís sectíon. You muy reud my book Cracíc9í }DßC
írogrammíng lor uíí ol the Crucíe types und perlormunce enhuncements.
1here ure two }DßC extensíon puckuges suppííed by Crucíe Corporutíon:
oracle.sql contuíns the cíusses thut support uíí the Crucíe dutubuse types.
oracle.jdbc contuíns the ínterluces thut support uccess to un Crucíe dutubuse.
S68
Crucíe Dutubuse llg SQL
1o ímport the Crucíe }DßC puckuges ínto your }uvu progrums, you udd the loííowíng import
stutements to your progrum:
import oracle.sql.*;
import oracle.jdbc.*;
Cl course, you don't huve to ímport uíí the puckugesyou couíd ¡ust ímport the cíusses und
ínterluces you uctuuííy use ín your progrum. ln the loííowíng sectíons, you'íí íeurn the key leutures
ol the oracle.sql und oracle.jdbc puckuges.
Thc uracIc.sqI Packagc
1he oracle.sql puckuge contuíns the cíusses thut support uíí ol the Crucíe dutubuse types.
Lsíng ob¡ects ol the cíusses delíned ín thís puckuge to store dutubuse vuíues ís more ellícíent thun
usíng reguíur }uvu ob¡ects. 1hís ís becuuse the dutubuse vuíues don't need to be converted to un
uppropríute buse }uvu type lírst. Aíso, usíng u }uvu float or double to represent u líoutíng-poínt
number muy resuít ín u íoss ol precísíon lor thut number. ll you use un oracle.sql.NUMBER
ob¡ect, your numbers never íose precísíon.
TlP
í| ,ou arc vrí|íng a program |ha| movc· a ío| o| da|a around ín |hc
da|aba·c, ,ou ·houíd u·c |hc oracle.sql.* cía··c·.
1he oracle.sql cíusses extend the oracle.sql.Datum cíuss, whích contuíns the
lunctíonuííty thut ís common to uíí the cíusses. 1ubíe l5-6 shows u subset ol the oracle.sql
cíusses, uíong wíth the muppíng to the computíbíe Crucíe dutubuse types.
lrom 1ubíe l5-6, you cun see thut un oracle.sql.NUMBER ob¡ect ís computíbíe wíth u
dutubuse INTEGER or NUMBER type. An oracle.sql.CHAR ob¡ect ís computíbíe wíth u dutubuse
CHAR, VARCHAR2, NCHAR, und NVARCHAR2 (NCHAR und NVARCHAR2 ure typícuííy used to store
non-Lngíísh churucters).
CIass CumpatibIc Databasc Typc
oracle.sql.NUMBER INTEGER
NUMBER
oracle.sql.CHAR CHAR
VARCHAR2
NCHAR
NVARCHAR2
oracle.sql.DATE DATE
oracle.sql.BINARY_FLOAT BINARY_FLOAT
oracle.sql.BINARY_DOUBLE BINARY_DOUBLE
oracle.sql.ROWID ROWID
TABlf 1S-6 Cía··c· and Compa|íbíc Cracíc Da|aba·c T,pc·
Chupter l5: Runníng SQL Lsíng }uvu
S69
Cb¡ects decíured usíng the oracle.sql cíusses store dutu us byte urruysuíso known
us SÇí |orma|und don't relormut the dutu retríeved lrom the dutubuse. 1hís meuns thut no
ínlormutíon ís íost when convertíng between un SQL lormut ob¡ect und u vuíue stored ín the
dutubuse.
Luch oracle.sql ob¡ect hus u getBytes() method thut returns the bínury dutu stored ín
the ob¡ect. Luch ob¡ect uíso hus u toJdbc() method thut returns the bínury dutu us u computíbíe
}uvu type (un exceptíon to thís ís the oracle.sql.ROWID, where toJdbc() uíwuys returns un
oracle.sql.ROWID).
Luch oracle.sql cíuss uíso provídes methods to convert theír SQL lormut bínury dutu to u
core }uvu type. lor exumpíe, stringValue() returns the vuíue us }uvu String, intValue()
returns u }uvu int, floatValue() returns u float, doubleValue() returns u double,
bigDecimalValue() returns u java.math.BigDecimal, dateValue() returns u java
.sql.Date, und so on. You use these methods when you wunt to store the SQL lormut dutu ín u
core }uvu type or to díspíuy the SQL dutu on the screen. Luch oracle.sql cíuss uíso contuíns u
constructor thut uccepts u }uvu vuríubíe, ob¡ect, or byte urruy us ínput.
As you wííí see íuter, the oracle.jdbc.OraclePreparedStatement cíuss contuíns u
number ol set methods thut you use to specíly vuíues lor oracle.sql ob¡ects. 1he
OracleResultSet cíuss delínes u number ol get methods thut you use to reud vuíues lrom
oracle.sql ob¡ects.
1he loííowíng sectíons descríbe the muín oracle.sql cíusses.
Thc uracIc.sqI.NUMBfR CIass
1he oracle.sql.NUMBER cíuss ís computíbíe wíth the dutubuse INTEGER und NUMBER types.
1he oracle.sql.NUMBER cíuss muy be used to represent u number wíth up to 38 dígíts ol
precísíon. 1he loííowíng exumpíe creutes un oracle.sql.NUMBER ob¡ect numed customerId,
whích ís set to the vuíue 6 usíng the constructor:
oracle.sql.NUMBER customerId = new oracle.sql.NUMBER(6);
You cun reud the vuíue stored ín customerId usíng the intValue() method, whích
returns the vuíue us u }uvu int. lor exumpíe:
int customerIdInt = customerId.intValue();
You cun uíso set un oracle.sql.NUMBER ob¡ect to u líoutíng-poínt number. 1he next
exumpíe pusses the vuíue l9.95 to the constructor ol un ob¡ect numed price:
oracle.sql.NUMBER price = new oracle.sql.NUMBER(19.95);
You cun reud the líoutíng-poínt number stored ín price usíng the floatValue(),
doubleValue(), und bigDecimalValue() methods, whích return u }uvu float, double,
und bigDecimal respectíveíy. You cun uíso get u líoutíng-poínt number truncuted to un int
usíng intValue() (lor exumpíe, l9.95 wouíd be returned us l9). 1he loííowíng exumpíes show
the use ol these methods:
float priceFloat = price.floatValue();
double priceDouble = price.doubleValue();
java.math.BigDecimal priceBigDec = price.bigDecimalValue();
int priceInt = price.intValue();
S70
Crucíe Dutubuse llg SQL
1he stringValue() method returns the vuíue us u }uvu String:
String priceString = price.stringValue();
Thc uracIc.sqI.CHAR CIass
1he oracle.sql.CHAR cíuss ís computíbíe wíth the dutubuse CHAR, VARCHAR2, NCHAR,
und NVARCHAR2 types. ßoth the Crucíe dutubuse und the oracle.sql.CHAR cíuss contuín
gíobuíízutíon support lor muny díllerent íunguuges. lor luíí detuíís ol the vuríous íunguuges
supported by Crucíe, see the Cracíc Da|aba·c Cíobaíí2a|íon Suppor| Cuídc pubííshed by Crucíe
Corporutíon.
\hen you retríeve churucter dutu lrom the dutubuse ínto un oracle.sql.CHAR ob¡ect, the
Crucíe }DßC dríver returns thut ob¡ect usíng eíther the dutubuse churucter set (the deluuít), the
\L8lSC8859ll churucter set (lSC 8859-l \est Luropeun), or the L1l8 churucter set (Lnícode
3.0 L1l-8 Lníversuí).
\hen pussíng un oracle.sql.CHAR ob¡ect to the dutubuse, there ure restríctíons on the
churucter set lor the ob¡ect. 1he churucter set depends on the dutubuse coíumn type thut the
ob¡ect wííí be stored ín. ll you ure storíng the oracle.sql.CHAR ob¡ect ín u CHAR or VARCHAR2
coíumn, you must use LS7ASCll (ASCll 7-bít Amerícun), \L8lSC8859ll (lSC 8859-l \est
Luropeun), or L1l8 (Lnícode 3.0 L1l-8 Lníversuí). ll you ure storíng the oracle.sql.CHAR
ob¡ect ín un NCHAR or NVARCHAR2 coíumn, you must use the churucter set used by the dutubuse.
\hen creutíng your own oracle.sql.CHAR ob¡ect, there ure two steps you must loííow:
1. Creute un oracle.sql.CharacterSet ob¡ect wíth the churucter set you wísh to use.
2. Creute un oracle.sql.CHAR ob¡ect through the oracle.sql.CharacterSet ob¡ect.
1he loííowíng sectíons cover these steps.
5tep 1: Create an orac|e.sq|.Character5et 0bject 1he loííowíng exumpíe creutes un oracle
.sql.CharacterSet ob¡ect numed myCharSet:
oracle.sql.CharacterSet myCharSet =
CharacterSet.make(CharacterSet.US7ASCII_CHARSET);
1he make() method uccepts un int thut specílíes the churucter set. ln the exumpíe, the
constunt US7ASCII_CHARSET (delíned ín the oracle.sql.CharacterSet cíuss) specílíes
the LS7ASCll churucter set. Cther int vuíues íncíude UTF8_CHARSET (lor L1l8) und
DEFAULT_CHARSET (lor the churucter set used by the dutubuse).
5tep 2: Create an orac|e.sq|.Chkk 0bject 1he next exumpíe creutes un oracle.sql.CHAR
ob¡ect numed firstName, usíng the myCharSet ob¡ect creuted ín the prevíous step:
oracle.sql.CHAR firstName = new oracle.sql.CHAR("Jason", myCharSet);
1he firstName ob¡ect ís popuíuted wíth the stríng Jason. You cun reud thís stríng usíng the
stringValue() method, lor exumpíe:
String firstNameString = firstName.stringValue();
System.out.println("firstNameString = " + firstNameString);
Chupter l5: Runníng SQL Lsíng }uvu
S71
1hís wííí díspíuy firstNameString = Jason.
Símííuríy, the loííowíng exumpíe creutes unother oracle.sql.CHAR ob¡ect numed lastName:
oracle.sql.CHAR lastName = new oracle.sql.CHAR("Price", myCharSet);
You cun uíso díspíuy the vuíue ín un oracle.sql.CHAR ob¡ect dírectíy, us shown ín the
loííowíng exumpíe:
System.out.println("lastName = " + lastName);
1hís stutement díspíuys the loííowíng:
lastName = Price
Thc uracIc.sqI.DATf CIass
1he oracle.sql.DATE cíuss ís computíbíe wíth the dutubuse DATE type. 1he loííowíng
exumpíe creutes un oracle.sql.DATE ob¡ect numed dob:
oracle.sql.DATE dob = new oracle.sql.DATE("1969-02-22 13:54:12");
Notíce thut the constructor muy uccept u stríng ín the lormut YYYY-MM-DD HH:MI:SS, where
YYYY ís the yeur, MM ís the month, DD ís the duy, HH ís the hour, MI ís the mínute, und SS ís the
second. You cun reud the vuíue stored ín dob us u }uvu String usíng the stringValue()
method, us shown ín the loííowíng exumpíe:
String dobString = dob.stringValue();
ln thís exumpíe, dobString wííí contuín 2/22/1969 13:54:12 (the lormut chunges to
MM/DD/YYYY HH:MI:SS when usíng u }uvu String).
You cun uíso puss u java.sql.Date ob¡ect to the oracle.sql.DATE constructor, us
shown ín the loííowíng exumpíe:
oracle.sql.DATE anotherDob =
new oracle.sql.DATE(java.sql.Date.valueOf("1969-02-22"));
ln thís exumpíe, anotherDob wííí contuín the oracle.sql.DATE 1969-02-22
00:00:00.
Thc uracIc.sqI.ROWlD CIass
1he oracle.sql.ROWID cíuss ís computíbíe wíth the dutubuse ROWID type. 1he ROWID
contuíns the physícuí uddress ol u row ín the dutubuse. 1he loííowíng exumpíe creutes un
oracle.sql.ROWID ob¡ect numed rowid:
oracle.sql.ROWID rowid;
Thc uracIc.jdbc Packagc
1he cíusses und ínterluces ol the oracle.jdbc puckuge uííow you to reud und wríte coíumn
vuíues ín the dutubuse víu oracle.sql ob¡ects. 1he oracle.jdbc puckuge uíso contuíns u
number ol perlormunce enhuncements. ln thís sectíon, you'íí íeurn ubout the contents ol the
oracle.jdbc puckuge und see how to creute u row ín the customers tubíe. 1hen you'íí íeurn
how to reud thut row usíng oracle.sql ob¡ects.
S72
Crucíe Dutubuse ll SQL
Thc CIasscs and lntcrfaccs uf thc uracIc.jdbc Packagc
1ubíe l5-7 shows the cíusses und ínterluces ol the oracle.jdbc puckuge.
Using an OracIcPrcparcdStatcmcnt Objcct
1he OraclePreparedStatement ínterluce ímpíements java.sql.PreparedStatement.
1hís ínterluce supports the vuríous set methods lor bíndíng oracle.sql ob¡ects.
ln the prevíous sectíon, you suw the loííowíng oracle.sql ob¡ects:
An oracle.sql.NUMBER ob¡ect numed customerId, whích wus set to 6
An oracle.sql.CHAR ob¡ect numed firstName, whích wus set to Jason
Another oracle.sql.CHAR ob¡ect numed lastName, whích wus set to Price
An oracle.sql.DATE ob¡ect numed dob, whích wus set to 1969-02-22 13:54:12
1o use these ob¡ects ín un SQL DML stutement, you must use un
OraclePreparedStatement ob¡ect, whích contuíns set methods to hundíe oracle.sql
ob¡ects. 1he loííowíng exumpíe creutes un OraclePreparedStatement numed
myPrepStatement, whích wííí be used íuter to udd u row to the customers tubíe:
OraclePreparedStatement myPrepStatement =
(OraclePreparedStatement) myConnection.prepareStatement(
"INSERT INTO customers " +
"(customer_id, first_name, last_name, dob, phone) VALUES (" +
"?, ?, ?, ?, ?" +
")"
);
Notíce thut the PreparedStatement ob¡ect returned by the prepareStatement()
method ís cust to un OraclePreparedStatement ob¡ect und ís stored ín myPrepStatement.
1he next step ís to bínd the oracle.sql ob¡ects to myPrepStatement usíng the set
methods. 1hís ínvoíves ussígníng vuíues to the píucehoíders murked by questíon murk (?)
churucters ín myPrepStatement. }ust us you use set methods ííke setInt(), setFloat(),
setString(), und setDate() to bínd }uvu vuríubíes to u PreparedStatement ob¡ect, you
uíso use set methods to bínd oracle.sql ob¡ects to un OraclePreparedStatement ob¡ect
(these set methods íncíude setNUMBER(), setCHAR(), setDATE(), und so on).
1he loííowíng exumpíe íííustrute how to bínd the customerId, firstName, lastName,
und dob ob¡ects to myPrepStatement usíng the uppropríute set methods:
myPrepStatement.setNUMBER(1, customerId);
myPrepStatement.setCHAR(2, firstName);
myPrepStatement.setCHAR(3, lastName);
myPrepStatement.setDATE(4, dob);
1he next exumpíe sets the lílth questíon murk (?) ín myPrepStatement to NULL (the lílth
questíon murk (?) corresponds to the phone coíumn ín the customers tubíe):
myPrepStatement.setNull(5, OracleTypes.CHAR);
Chupter l5: Runníng SQL Lsíng }uvu
S73
Namc CIass ur lntcrfacc Dcscriptiun
OracleDriver
Cíuss lmpíements java.sql.Driver.
You ínput un ob¡ect ol thís cíuss when
regísteríng the Crucíe }DßC drívers usíng
the registerDriver() method ol the
java.sql.DriverManager cíuss.
OracleConnection
lnterluce lmpíements java.sql.Connection.
1hís ínterluce extends the stundurd
}DßC connectíon lunctíonuííty to use
OracleStatement ob¡ects. lt uíso
ímproves perlormunce over the stundurd
}DßC lunctíons.
OracleStatement lnterluce lmpíements java.sql.Statement
und ís the supercíuss ol the
OraclePreparedStatement und
OracleCallableStatement cíusses.
OraclePreparedStatement
lnterluce lmpíements java.sql
.PreparedStatement,
und ís the supercíuss ol
OracleCallableStatement. 1hís
ínterluce supports the vuríous set
methods lor bíndíng oracle.sql
ob¡ects.
OracleCallableStatement lnterluce lmpíements java.sql
.CallableStatement. 1hís ínterluce
contuíns vuríous get und set methods
lor bíndíng oracle.sql ob¡ects.
OracleResultSet
lnterluce lmpíements java.sql.ResultSet.
1hís ínterluce contuíns vuríous get
methods lor bíndíng oracle.sql
ob¡ects.
OracleResultSetMetaData
lnterluce lmpíements java.sql
.ResultSetMetaData. 1hís ínterluce
contuíns methods lor retríevíng metu dutu
ubout Crucíe resuít sets (such us coíumn
numes und theír types).
OracleDatabaseMetaData Cíuss lmpíements java.sql
.DatabaseMetaData. 1hís cíuss
contuíns methods lor retríevíng metu dutu
ubout the Crucíe dutubuse (such us the
dutubuse soltwure versíon).
OracleTypes Cíuss Delínes ínteger constunts lor the dutubuse
types. 1hís cíuss dupíícutes the stundurd
java.sql.Types cíuss und contuíns
uddítíonuí ínteger constunts lor uíí ol the
Crucíe types.
TABlf 1S-7 Cía··c· and ín|cr|acc· o| |hc oracle.jdbc íac|agc
S74
Crucíe Dutubuse ll SQL
1he int constunt OracleTypes.CHAR specílíes thut the dutubuse type ís computíbíe wíth
the oracle.sql.CHAR type, OracleTypes.CHAR ís used becuuse the phone coíumn ís u
VARCHAR2.
1he oníy thíng íelt to do ís to run the INSERT stutement usíng the execute() method:
myPrepStatement.execute();
Doíng thís udds the row to the customers tubíe.
Using an OracIcRcsuItSct Objcct
1he OracleResultSet ínterluce ímpíements java.sql.ResultSet und contuíns get methods
to hundíe oracle.sql ob¡ects. ln thís sectíon, you'íí see how to use un OracleResultSet ob¡ect
to retríeve the row prevíousíy udded to the customers tubíe.
1he lírst thíng needed ís u }DßC Statement ob¡ect through whích un SQL stutement muy be run:
Statement myStatement = myConnection.createStatement();
Next, the loííowíng exumpíe creutes un OracleResultSet ob¡ect numed
customerResultSet, whích ís popuíuted wíth the ROWID, customer_id, first_
name, last_dob, und phone coíumns retríeved lrom customer r6:
OracleResultSet customerResultSet =
(OracleResultSet) myStatement.executeQuery(
"SELECT ROWID, customer_id, first_name, last_name, dob, phone " +
"FROM customers " +
"WHERE customer_id = 6"
);
l delíned the loííowíng oracle.sql ob¡ects eurííer: rowid, customerId, firstName,
lastName, und dob. 1hese muy be used to hoíd the lírst líve coíumn vuíues. ln order to store
the vuíue lor the phone coíumn, un oracle.sql.CHAR ob¡ect ís needed:
oracle.sql.CHAR phone = new oracle.sql.CHAR("", myCharSet);
An OracleResultSet ob¡ect contuíns get methods thut return oracle.sql ob¡ects.
You use getCHAR() to get un oracle.sql.CHAR, getNUMBER() to get un oracle.sql
.NUMBER, getDATE() to get un oracle.sql.DATE, und so on.
1he loííowíng while íoop contuíns cuíís to the uppropríute get methods to copy the vuíues
lrom customerResultSet to rowid, customerId, firstName, lastName, dob, und phone:
while (customerResultSet.next()) {
rowid = customerResultSet.getROWID("ROWID");
customerId = customerResultSet.getNUMBER("customer_id");
firstName = customerResultSet.getCHAR("first_name");
lastName = customerResultSet.getCHAR("last_name");
dob = customerResultSet.getDATE("dob");
phone = customerResultSet.getCHAR("phone");
System.out.println("rowid = " + rowid.stringValue());
System.out.println("customerId = " + customerId.stringValue());
System.out.println("firstName = " + firstName);
System.out.println("lastName = " + lastName);
System.out.println("dob = " + dob.stringValue());
Chupter l5: Runníng SQL Lsíng }uvu
S7S
System.out.println("phone = " + phone);
} // end of while loop
1o díspíuy the vuíues, the exumpíe uses cuíís to the stringValue() method to convert the
rowid, customerId, und dob ob¡ects to }uvu String vuíues. lor the firstName, lastName,
und phone ob¡ects, the exumpíe símpíy uses these ob¡ects dírectíy ín the System.out
.println() cuíís.
1he loííowíng sectíon shows u compíete progrum contuíníng the stutements shown ín the
prevíous sectíons.
fxampIc Prugram: BasicfxampIc3.java
1he loííowíng BasicExample3.java progrum contuíns the stutements shown ín the prevíous
sectíons:
/*
BasicExample3.java shows how to use the Oracle JDBC extensions
to add a row to the customers table, and then retrieve that row
*/
// import the JDBC packages
import java.sql.*;
// import the Oracle JDBC extension packages
import oracle.sql.*;
import oracle.jdbc.*;
public class BasicExample3 {
public static void main (String args []) {
try {
// register the Oracle JDBC drivers
DriverManager.registerDriver(
new oracle.jdbc.OracleDriver()
);
// EDIT AS NECESSARY TO CONNECT TO YOUR DATABASE
// create a Connection object, and connect to the database
// as the store user using the Oracle JDBC Thin driver
Connection myConnection = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:ORCL",
"store",
"store_password"
);
// disable auto-commit mode
myConnection.setAutoCommit(false);
// create an oracle.sql.NUMBER object
oracle.sql.NUMBER customerId = new oracle.sql.NUMBER(6);
int customerIdInt = customerId.intValue();
System.out.println("customerIdInt = " + customerIdInt);
// create two oracle.sql.CHAR objects

Crucíe Dutubuse ll SQL
oracle.sql.CharacterSet myCharSet =
CharacterSet.make(CharacterSet.US7ASCII_CHARSET);
oracle.sql.CHAR firstName = new oracle.sql.CHAR("Jason", myCharSet);
String firstNameString = firstName.stringValue();
System.out.println("firstNameString = " + firstNameString);
oracle.sql.CHAR lastName = new oracle.sql.CHAR("Price", myCharSet);
System.out.println("lastName = " + lastName);
// create an oracle.sql.DATE object
oracle.sql.DATE dob = new oracle.sql.DATE("1969-02-22 13:54:12");
String dobString = dob.stringValue();
System.out.println("dobString = " + dobString);
// create an OraclePreparedStatement object
OraclePreparedStatement myPrepStatement =
(OraclePreparedStatement) myConnection.prepareStatement(
"INSERT INTO customers " +
"(customer_id, first_name, last_name, dob, phone) VALUES (" +
"?, ?, ?, ?, ?" +
")"
);
// bind the objects to the OraclePreparedStatement using the
// appropriate set methods
myPrepStatement.setNUMBER(1, customerId);
myPrepStatement.setCHAR(2, firstName);
myPrepStatement.setCHAR(3, lastName);
myPrepStatement.setDATE(4, dob);
// set the phone column to NULL
myPrepStatement.setNull(5, OracleTypes.CHAR);
// run the PreparedStatement
myPrepStatement.execute();
System.out.println("Added row to customers table");
// retrieve the ROWID, customer_id, first_name, last_name, dob, and
// phone columns for this new row using an OracleResultSet
// object
Statement myStatement = myConnection.createStatement();
OracleResultSet customerResultSet =
(OracleResultSet) myStatement.executeQuery(
"SELECT ROWID, customer_id, first_name, last_name, dob, phone " +
"FROM customers " +
"WHERE customer_id = 6"
);
System.out.println("Retrieved row from customers table");
// declare an oracle.sql.ROWID object to store the ROWID, and
// an oracle.sql.CHAR object to store the phone column
oracle.sql.ROWID rowid;
oracle.sql.CHAR phone = new oracle.sql.CHAR("", myCharSet);
Chupter l5: Runníng SQL Lsíng }uvu

// display the column values for row using the
// get methods to read the values
while (customerResultSet.next()) {
rowid = customerResultSet.getROWID("ROWID");
customerId = customerResultSet.getNUMBER("customer_id");
firstName = customerResultSet.getCHAR("first_name");
lastName = customerResultSet.getCHAR("last_name");
dob = customerResultSet.getDATE("dob");
phone = customerResultSet.getCHAR("phone");
System.out.println("rowid = " + rowid.stringValue());
System.out.println("customerId = " + customerId.stringValue());
System.out.println("firstName = " + firstName);
System.out.println("lastName = " + lastName);
System.out.println("dob = " + dob.stringValue());
System.out.println("phone = " + phone);
} // end of while loop
// close the OracleResultSet object using the close() method
customerResultSet.close();
// roll back the changes made to the database
myConnection.rollback();
// close the other JDBC objects
myPrepStatement.close();
myConnection.close();
} catch (SQLException e) {
System.out.println("Error code = " + e.getErrorCode());
System.out.println("Error message = " + e.getMessage());
System.out.println("SQL state = " + e.getSQLState());
e.printStackTrace();
}
} // end of main()
}
1he output lrom thís progrum ís us loííows:
customerIdInt = 6
firstNameString = Jason
lastName = Price
dobString = 2/22/1969 13:54:12
Added row to customers table
Retrieved row from customers table
rowid = AAARk5AAEAAAAGPAAF
customerId = 6
firstName = Jason
lastName = Price
dob = 2/22/1969 13:54:12
phone = null
dobString2 = 2/22/1969 0:0:0
S78
Crucíe Dutubuse ll SQL
Summary
ln thís chupter, you huve íeurned the loííowíng:
1he }DßC All enubíes u }uvu progrum to uccess u dutubuse.
1he Crucíe }DßC drívers ure used to connect to un Crucíe dutubuse.
SQL stutements muy be executed usíng }DßC.
Crucíe hus deveíoped u number ol extensíons to stundurd }DßC thut uííow you to guín
uccess to uíí ol the Crucíe dutubuse types.
ln the next chupter, you'íí íeurn how to tune your SQL stutements lor muxímum perlormunce.
\IAI1II
1o
SQL 1uníng
579
S80
Crucíe Dutubuse ll SQL
n thís chupter, you wííí do the loííowíng:
Leurn ubout SQL tuníng
See SQL tuníng típs thut you cun use to shorten the íength ol tíme your queríes tuke
to execute
Leurn ubout the Crucíe optímízer
See how to compure the cost ol perlormíng queríes
Lxumíne optímízer hínts
Leurn ubout some uddítíonuí tuníng tooís
lntruducing SQl Tuning
Cne ol the muín strengths ol SQL ís thut you don't huve to teíí the dutubuse exuctíy how to obtuín
the dutu requested. You símpíy run u query specílyíng the ínlormutíon you wunt, und the dutubuse
soltwure lígures out the best wuy to get ít. Sometímes, you cun ímprove the perlormunce ol your
SQL stutements by ºtuníng¨ them. ln the loííowíng sectíons, you'íí see tuníng típs thut cun muke
your queríes run luster, íuter, you'íí see more udvunced tuníng techníques.
Usc a WHfRf CIausc tu fiItcr Ruws
Muny novíces retríeve uíí the rows lrom u tubíe when they oníy wunt one row (or u lew rows). 1hís
ís very wusteluí. A better upprouch ís to udd u WHERE cíuuse to u query. 1hut wuy, you restríct the
rows retríeved to ¡ust those uctuuííy needed.
lor exumpíe, suy you wunt the detuíís lor customer rl und r2. 1he loííowíng query retríeves
uíí the rows lrom the customers tubíe ín the store schemu (wusteluí):
-- BAD (retrieves all rows from the customers table)
SELECT *
FROM customers;
CUSTOMER_ID FIRST_NAME LAST_NAME DOB PHONE
----------- ---------- ---------- --------- ------------
1 John Brown 01-JAN-65 800-555-1211
2 Cynthia Green 05-FEB-68 800-555-1212
3 Steve White 16-MAR-71 800-555-1213
4 Gail Black 800-555-1214
5 Doreen Blue 20-MAY-70
1he next query udds u WHERE cíuuse to the prevíous exumpíe to ¡ust get customer rl und r2:
-- GOOD (uses a WHERE clause to limit the rows retrieved)
SELECT *
FROM customers
WHERE customer_id IN (1, 2);

Chupter l6: SQL 1uníng
S81
CUSTOMER_ID FIRST_NAME LAST_NAME DOB PHONE
----------- ---------- ---------- --------- ------------
1 John Brown 01-JAN-65 800-555-1211
2 Cynthia Green 05-FEB-68 800-555-1212
You shouíd uvoíd usíng lunctíons ín the WHERE cíuuse, us thut íncreuses executíon tíme.
Usc TabIc |uins Rathcr than MuItipIc Qucrics
ll you need ínlormutíon lrom muítípíe reíuted tubíes, you shouíd use ¡oín condítíons ruther thun
muítípíe queríes. ln the loííowíng bud exumpíe, two queríes ure used to get the product nume und
the product type nume lor product rl (usíng two queríes ís wusteluí). 1he lírst query gets the name
und product_type_id coíumn vuíues lrom the products tubíe lor product rl. 1he second
query then uses thut product_type_id to get the name coíumn lrom the product_types tubíe.
-- BAD (two separate queries when one would work)
SELECT name, product_type_id
FROM products
WHERE product_id = 1;
NAME PRODUCT_TYPE_ID
------------------------------ ---------------
Modern Science 1
SELECT name
FROM product_types
WHERE product_type_id = 1;
NAME
----------
Book
lnsteud ol usíng the two queríes, you shouíd wríte one query thut uses u ¡oín between the
products und product_types tubíes. 1he loííowíng good query shows thís:
-- GOOD (one query with a join)
SELECT p.name, pt.name
FROM products p, product_types pt
WHERE p.product_type_id = pt.product_type_id
AND p.product_id = 1;
NAME NAME
------------------------------ ----------
Modern Science Book
1hís query resuíts ín the sume product nume und product type nume beíng retríeved us ín the
lírst exumpíe, but the resuíts ure obtuíned usíng one query. Cne query ís generuííy more ellícíent
thun two.
You shouíd choose the ¡oín order ín your query so thut you ¡oín lewer rows to tubíes íuter ín
the ¡oín order. lor exumpíe, suy you were ¡oíníng three reíuted tubíes numed tab1, tab2, und
tab3. Assume tab1 contuíns l,000 rows, tab2 l00 rows, und tab3 l0 rows. You shouíd ¡oín
tab1 wíth tab2 lírst, loííowed by tab2 und tab3.
S82
Crucíe Dutubuse ll SQL
Aíso, uvoíd ¡oíníng compíex víews ín your queríes, becuuse doíng so cuuses the queríes lor
the víews to be run lírst, loííowed by your uctuuí query. lnsteud, wríte your query usíng the tubíes
ruther thun the víews.
Usc fuIIy QuaIificd CuIumn Rcfcrcnccs Whcn
Pcrfurming |uins
Aíwuys íncíude tubíe uííuses ín your queríes und use the uííus lor euch coíumn ín your query (thís
ís known us ºluííy quuíílyíng¨ your coíumn relerences). 1hut wuy, the dutubuse doesn't huve to
seurch lor euch coíumn ín the tubíes used ín your query.
1he loííowíng bud exumpíe uses the uííuses p und pt lor the products und product_
types tubíes, respectíveíy, but the query doesn't luííy quuííly the description und price
coíumns:
-- BAD (description and price columns not fully qualified)
SELECT p.name, pt.name, description, price
FROM products p, product_types pt
WHERE p.product_type_id = pt.product_type_id
AND p.product_id = 1;
NAME NAME
------------------------------ ----------
DESCRIPTION PRICE
-------------------------------------------------- ----------
Modern Science Book
A description of modern science 19.95
1hís exumpíe works, but the dutubuse hus to seurch both the products und product_types
tubíes lor the description und price coíumns, thut's becuuse there's no uííus thut teíís the
dutubuse whích tubíe those coíumns ure ín. 1he extru tíme spent by the dutubuse huvíng to do the
seurch ís wusted tíme.
1he loííowíng good exumpíe íncíudes the tubíe uííus p to luííy quuííly the description und
price coíumns:
-- GOOD (all columns are fully qualified)
SELECT p.name, pt.name, p.description, p.price
FROM products p, product_types pt
WHERE p.product_type_id = pt.product_type_id
AND p.product_id = 1;
NAME NAME
------------------------------ ----------
DESCRIPTION PRICE
-------------------------------------------------- ----------
Modern Science Book
A description of modern science 19.95
ßecuuse uíí relerences to coíumns íncíude u tubíe uííus, the dutubuse doesn't huve to wuste
tíme seurchíng the tubíes lor the coíumns, und executíon tíme ís reduced.
Chupter l6: SQL 1uníng
S83
Usc CASf fxprcssiuns Rathcr than MuItipIc Qucrics
Lse CASE expressíons ruther thun muítípíe queríes when you need to perlorm muny cuícuíutíons
on the sume rows ín u tubíe. 1he loííowíng bud exumpíe uses muítípíe queríes to count the
number ol products wíthín vuríous príce runges:
-- BAD (three separate queries when one CASE statement would work)
SELECT COUNT(*)
FROM products
WHERE price < 13;
COUNT(*)
----------
2
SELECT COUNT(*)
FROM products
WHERE price BETWEEN 13 AND 15;
COUNT(*)
----------
5
SELECT COUNT(*)
FROM products
WHERE price > 15;
COUNT(*)
----------
5
Ruther thun usíng three queríes, you shouíd wríte one query thut uses CASE expressíons. 1hís
ís shown ín the loííowíng good exumpíe:
-- GOOD (one query with a CASE expression)
SELECT
COUNT(CASE WHEN price < 13 THEN 1 ELSE null END) low,
COUNT(CASE WHEN price BETWEEN 13 AND 15 THEN 1 ELSE null END) med,
COUNT(CASE WHEN price > 15 THEN 1 ELSE null END) high
FROM products;
LOW MED HIGH
---------- ---------- ----------
2 5 5
Notíce thut the counts ol the products wíth príces íess thun Sl3 ure íubeíed us low, products
between Sl3 und Sl5 ure íubeíed med, und products greuter thun Sl5 ure íubeíed high.
NOTf
You can, o| cour·c, u·c ovcríappíng rangc· and dí||crcn| |unc|íon· ín
,our CASE cxprc··íon·.
S84
Crucíe Dutubuse llg SQL
Add lndcxcs tu TabIcs
\hen íookíng lor u purtícuíur topíc ín u book, you cun eíther scun the whoíe book or use the índex
to línd the íocutíon. An índex lor u dutubuse tubíe ís símííur ín concept to u book índex, except
thut dutubuse índexes ure used to línd specílíc rows ín u tubíe. 1he downsíde ol índexes ís thut
when u row ís udded to the tubíe, uddítíonuí tíme ís requíred to updute the índex lor the new row.
Ceneruííy, you shouíd creute un índex on u coíumn when you ure retríevíng u smuíí number
ol rows lrom u tubíe contuíníng muny rows. A good ruíe ol thumb ís
Crca|c an índcx vhcn a qucr, rc|rícvc· <= 10 pcrccn| o| |hc |o|aí rov· ín a |abíc.
1hís meuns the coíumn lor the índex shouíd contuín u wíde runge ol vuíues. A good cundídute
lor índexíng wouíd be u coíumn contuíníng u uníque vuíue lor euch row (lor exumpíe, u socíuí
securíty number). A poor cundídute lor índexíng wouíd be u coíumn thut contuíns oníy u smuíí
runge ol vuíues (lor exumpíe, N, S, L, \ or l, 2, 3, 4, 5, 6). An Crucíe dutubuse uutomutícuííy
creutes un índex lor the prímury key ol u tubíe und lor coíumns íncíuded ín u uníque construínt.
ln uddítíon, íl your dutubuse ís uccessed usíng u íot ol híerurchícuí queríes (thut ís, u query
contuíníng u CONNECT BY), you shouíd udd índexes to the coíumns relerenced ín the START
WITH und CONNECT BY cíuuses (see Chupter 7 lor detuíís on híerurchícuí queríes).
línuííy, lor u coíumn thut contuíns u smuíí runge ol vuíues und ís lrequentíy used ín the WHERE
cíuuse ol queríes, you shouíd consíder uddíng u bítmup índex to thut coíumn. ßítmup índexes ure
typícuííy used ín dutu wurehouses, whích ure dutubuses contuíníng very íurge umounts ol dutu.
1he dutu ín u dutu wurehouse ís typícuííy reud usíng muny queríes, but the dutu ís not modílíed
by muny concurrent trunsuctíons.
Normuííy, u dutubuse udmínístrutor ís responsíbíe lor creutíng índexes. However, us un
uppíícutíon deveíoper, you'íí be ubíe to províde the DßA wíth leedbuck on whích coíumns ure
good cundídutes lor índexíng, becuuse you muy know more ubout the uppíícutíon thun the DßA.
Chupter l0 covers índexes ín depth, und you shouíd re-reud the sectíon on índexes íl necessury.
Usc WHfRf Rathcr than HAVlNG
You use the WHERE cíuuse to lííter rows, you use the HAVING cíuuse to lííter groups ol rows.
ßecuuse the HAVING cíuuse lííters groups ol rows a||cr they huve been grouped together (whích
tukes some tíme to do), you shouíd lírst lííter rows usíng u WHERE cíuuse whenever possíbíe. 1hut
wuy, you uvoíd the tíme tuken to group the líítered rows together ín the lírst píuce.
1he loííowíng bud query retríeves the product_type_id und uveruge príce lor products
whose product_type_id ís l or 2. 1o do thís, the query perlorms the loííowíng:
lt uses the GROUP BY cíuuse to group rows ínto bíocks wíth the sume product_type_id.
lt uses the HAVING cíuuse to lííter the returned resuíts to those groups thut huve u
product_type_id ín l or 2 (thís ís bud, becuuse u WHERE cíuuse wouíd work).
-- BAD (uses HAVING rather than WHERE)
SELECT product_type_id, AVG(price)
FROM products
GROUP BY product_type_id
HAVING product_type_id IN (1, 2);
Chupter l6: SQL 1uníng
S8S
PRODUCT_TYPE_ID AVG(PRICE)
--------------- ----------
1 24.975
2 26.22
1he loííowíng good query rewrítes the prevíous exumpíe to use WHERE ruther thun HAVING to
lírst lííter the rows to those whose product_type_id ís l or 2:
-- GOOD (uses WHERE rather than HAVING)
SELECT product_type_id, AVG(price)
FROM products
WHERE product_type_id IN (1, 2)
GROUP BY product_type_id;
PRODUCT_TYPE_ID AVG(PRICE)
--------------- ----------
1 24.975
2 26.22
Usc UNlON All Rathcr than UNlON
You use UNION ALL to get uíí the rows retríeved by two queríes, íncíudíng dupíícute rows, you
use UNION to get uíí non-dupíícute rows retríeved by the queríes. ßecuuse UNION removes
dupíícute rows (whích tukes some tíme to do), you shouíd use UNION ALL whenever possíbíe.
1he loííowíng bud query uses UNION (bud becuuse UNION ALL wouíd work) to get the rows
lrom the products und more_products tubíes, notíce thut uíí non-dupíícute rows lrom
products und more_products ure retríeved:
-- BAD (uses UNION rather than UNION ALL)
SELECT product_id, product_type_id, name
FROM products
UNION
SELECT prd_id, prd_type_id, name
FROM more_products;
PRODUCT_ID PRODUCT_TYPE_ID NAME
---------- --------------- -------------------
1 1 Modern Science
2 1 Chemistry
3 2 Supernova
3 Supernova
4 2 Lunar Landing
4 2 Tank War
5 2 Submarine
5 2 Z Files
6 2 2412: The Return
7 3 Space Force 9
8 3 From Another Planet
9 4 Classical Music
10 4 Pop 3
11 4 Creative Yell
12 My Front Line
S86
Crucíe Dutubuse ll SQL
1he loííowíng good query rewrítes the prevíous exumpíe to use UNION ALL, notíce thut uíí
the rows lrom products und more_products ure retríeved, íncíudíng dupíícutes:
-- GOOD (uses UNION ALL rather than UNION)
SELECT product_id, product_type_id, name
FROM products
UNION ALL
SELECT prd_id, prd_type_id, name
FROM more_products;
PRODUCT_ID PRODUCT_TYPE_ID NAME
---------- --------------- ------------------------------
1 1 Modern Science
2 1 Chemistry
3 2 Supernova
4 2 Tank War
5 2 Z Files
6 2 2412: The Return
7 3 Space Force 9
8 3 From Another Planet
9 4 Classical Music
10 4 Pop 3
11 4 Creative Yell
12 My Front Line
1 1 Modern Science
2 1 Chemistry
3 Supernova
4 2 Lunar Landing
5 2 Submarine
Usc fXlSTS Rathcr than lN
You use IN to check íl u vuíue ís contuíned ín u ííst. You use EXISTS to check lor the exístence ol
rows returned by u subquery. EXISTS ís díllerent lrom IN: EXISTS ¡ust checks lor the exístence
ol rows, whereus IN checks uctuuí vuíues. EXISTS typícuííy ollers better perlormunce thun IN
wíth subqueríes. 1herelore, you shouíd use EXISTS ruther thun IN whenever possíbíe.
You shouíd reler buck to the sectíon entítíed ºLsíng LXlS1S und NC1 LXlS1S wíth u Correíuted
Subquery¨ ín Chupter 6 lor luíí detuíís on when you shouíd use EXISTS wíth u correíuted subquery
(un ímportunt poínt to remember ís thut correíuted subqueríes cun resoíve nuíí vuíues).
1he loííowíng bud query uses IN (bud becuuse EXISTS wouíd work) to retríeve products thut
huve been purchused:
-- BAD (uses IN rather than EXISTS)
SELECT product_id, name
FROM products
WHERE product_id IN
(SELECT product_id
FROM purchases);
PRODUCT_ID NAME
---------- -----------------------------
1 Modern Science
Chupter l6: SQL 1uníng
S87
2 Chemistry
3 Supernova
1he loííowíng good query rewrítes the prevíous exumpíe to use EXISTS:
-- GOOD (uses EXISTS rather than IN)
SELECT product_id, name
FROM products outer
WHERE EXISTS
(SELECT 1
FROM purchases inner
WHERE inner.product_id = outer.product_id);
PRODUCT_ID NAME
---------- -----------------------------
1 Modern Science
2 Chemistry
3 Supernova
Usc fXlSTS Rathcr than DlSTlNCT
You cun suppress the díspíuy ol dupíícute rows usíng DISTINCT. You use EXISTS to check lor the
exístence ol rows returned by u subquery. \henever possíbíe, you shouíd use EXISTS ruther thun
DISTINCT, becuuse DISTINCT sorts the retríeved rows belore suppressíng the dupíícute rows.
1he loííowíng bud query uses DISTINCT (bud becuuse EXISTS wouíd work) to retríeve
products thut huve been purchused:
-- BAD (uses DISTINCT when EXISTS would work)
SELECT DISTINCT pr.product_id, pr.name
FROM products pr, purchases pu
WHERE pr.product_id = pu.product_id;
PRODUCT_ID NAME
---------- -----------------------------
1 Modern Science
2 Chemistry
3 Supernova
1he loííowíng good query rewrítes the prevíous exumpíe to use EXISTS ruther thun DISTINCT:
-- GOOD (uses EXISTS rather than DISTINCT)
SELECT product_id, name
FROM products outer
WHERE EXISTS
(SELECT 1
FROM purchases inner
WHERE inner.product_id = outer.product_id);
PRODUCT_ID NAME
---------- -----------------------------
1 Modern Science
2 Chemistry
3 Supernova
S88
Crucíe Dutubuse llg SQL
Usc GROUPlNG SfTS Rathcr than CUBf
1he GROUPING SETS cíuuse typícuííy ollers better perlormunce thun CUBE. 1herelore, you
shouíd use GROUPING SETS ruther thun CUBE wherever possíbíe. 1hís ís luííy covered ín the
sectíon entítíed ºLsíng the CRCLllNC SL1S Cíuuse¨ ín Chupter 7.
Usc Bind VariabIcs
1he Crucíe dutubuse soltwure cuches SQL stutements, u cuched SQL stutement ís reused íl un
ídentícuí stutement ís submítted to the dutubuse. \hen un SQL stutement ís reused, the executíon
tíme ís reduced. However, the SQL stutement must be ab·oíu|cí, ídcn|ícaí ín order lor ít to be
reused. 1hís meuns thut
Aíí churucters ín the SQL stutement must be the sume.
Aíí íetters ín the SQL stutement must be ín the sume cuse.
Aíí spuces ín the SQL stutement must be the sume.
ll you need to suppíy díllerent coíumn vuíues ín u stutement, you cun use bínd vuríubíes
ínsteud ol ííteruí coíumn vuíues. You'íí see exumpíes thut cíuríly these ídeus next.
Nun-ldcnticaI SQl Statcmcnts
ln thís sectíon, you'íí see some non-ídentícuí SQL stutements. 1he loííowíng non-ídentícuí queríes
retríeve products rl und r2:
SELECT * FROM products WHERE product_id = 1;
SELECT * FROM products WHERE product_id = 2;
1hese queríes ure not ídentícuí, becuuse the vuíue l ís used ín the lírst stutement, but the
vuíue 2 ís used ín the second.
1he loííowíng non-ídentícuí queríes huve spuces ín díllerent posítíons:
SELECT * FROM products WHERE product_id = 1;
SELECT * FROM products WHERE product_id = 1;
1he loííowíng non-ídentícuí queríes use u díllerent cuse lor some ol the churucters:
select * from products where product_id = 1;
SELECT * FROM products WHERE product_id = 1;
Now thut you've seen some non-ídentícuí stutements, íet's tuke u íook ut ídentícuí SQL
stutements thut use bínd vuríubíes.
ldcnticaI SQl Statcmcnts That Usc Bind VariabIcs
You cun ensure thut u stutement ís ídentícuí by usíng bínd vuríubíes to represent coíumn vuíues.
You creute u bínd vuríubíe usíng the SQL*líus VARIABLE commund. lor exumpíe, the loííowíng
commund creutes u vuríubíe numed v_product_id ol type NUMBER:
VARIABLE v_product_id NUMBER
Chupter l6: SQL 1uníng
S89
NOTf
You can u·c |hc |,pc· ·hovn ín Tabíc A-1 o| |hc appcndíx |o dc|ínc
|hc |,pc o| a bínd varíabíc.
You relerence u bínd vuríubíe ín un SQL or lL/SQL stutement usíng u coíon loííowed by the
vuríubíe nume (such us :v_product_id). lor exumpíe, the loííowíng lL/SQL bíock sets v_
product_id to l:
BEGIN
:v_product_id := 1;
END;
/
1he loííowíng query uses v_product_id to set the product_id coíumn vuíue ín the
WHERE cíuuse, becuuse v_product_id wus set to l ín the prevíous lL/SQL bíock, the query
retríeves the detuíís ol product rl:
SELECT * FROM products WHERE product_id = :v_product_id;
PRODUCT_ID PRODUCT_TYPE_ID NAME
---------- --------------- ------------------------------
DESCRIPTION PRICE
-------------------------------------------------- ----------
1 1 Modern Science
A description of modern science 19.95
1he next exumpíe sets v_product_id to 2 und repeuts the query:
BEGIN
:v_product_id := 2;
END;
/
SELECT * FROM products WHERE product_id = :v_product_id;
PRODUCT_ID PRODUCT_TYPE_ID NAME
---------- --------------- ------------------------------
DESCRIPTION PRICE
-------------------------------------------------- ----------
2 1 Chemistry
Introduction to Chemistry 30
ßecuuse the query used ín thís exumpíe ís ídentícuí to the prevíous query, the cuched query ís
reused und there's un ímprovement ín perlormunce.
TlP
You ·houíd |,pícaíí, u·c bínd varíabíc· í| ,ou'rc pcr|ormíng |hc ·amc
qucr, man, |ímc·. Aí·o, ín |hc cxampíc, |hc bínd varíabíc· arc ·c··íon
·pccí|íc and nccd |o bc rc·c| í| |hc ·c··íon í· ío·|.
S90
Crucíe Dutubuse ll SQL
listing and Printing Bind VariabIcs
You ííst bínd vuríubíes ín SQL*líus usíng the VARIABLE commund. lor exumpíe:
VARIABLE
variable v_product_id
datatype NUMBER
You díspíuy the vuíue ol u bínd vuríubíe ín SQL*líus usíng the PRINT commund. lor
exumpíe:
PRINT v_product_id
V_PRODUCT_ID
-------------
2
Using a Bind VariabIc tu Sturc a VaIuc Rcturncd
by a Pl/SQl functiun
You cun uíso use u bínd vuríubíe to store returned vuíues lrom u lL/SQL lunctíon. 1he loííowíng
exumpíe creutes u bínd vuríubíe numed v_average_product_price und stores the resuít
returned by the lunctíon average_product_price() (thís lunctíon wus descríbed ín Chupter ll
und cuícuíutes the uveruge product príce lor the suppííed product_type_id):
VARIABLE v_average_product_price NUMBER
BEGIN
:v_average_product_price := average_product_price(1);
END;
/
PRINT v_average_product_price
V_AVERAGE_PRODUCT_PRICE
------------------------
24.975
Using a Bind VariabIc tu Sturc Ruws frum a RffCURSOR
You cun uíso use u bínd vuríubíe to store returned vuíues lrom u REFCURSOR (u REFCURSOR ís u
poínter to u ííst ol rows). 1he loííowíng exumpíe creutes u bínd vuríubíe numed v_products_
refcursor und stores the resuít returned by the lunctíon product_package.get_products_
ref_cursor() (thís lunctíon wus íntroduced ín Chupter ll, ít returns u poínter to the rows ín the
products tubíe):
VARIABLE v_products_refcursor REFCURSOR
BEGIN
:v_products_refcursor := product_package.get_products_ref_cursor();
END;
/
PRINT v_products_refcursor
PRODUCT_ID NAME PRICE
---------- ------------------------------ ----------
1 Modern Science 19.95
2 Chemistry 30
Chupter l6: SQL 1uníng
S91
3 Supernova 25.99
4 Tank War 13.95
5 Z Files 49.99
6 2412: The Return 14.95
7 Space Force 9 13.49
8 From Another Planet 12.99
9 Classical Music 10.99
10 Pop 3 15.99
11 Creative Yell 14.99
PRODUCT_ID NAME PRICE
---------- ------------------------------ ----------
12 My Front Line 13.49
Cumparing thc Cust uf Pcrfurming Qucrics
1he Crucíe dutubuse soltwure uses u subsystem known us the op|ímí2cr to generute the most
ellícíent puth to uccess the dutu stored ín the tubíes. 1he puth generuted by the optímízer ís
known us un cxccu|íon pían. Crucíe Dutubuse l0g und ubove uutomutícuííy guthers stutístícs
ubout the dutu ín your tubíes und índexes ín order to generute the best executíon píun (thís ís
known us co·|-ba·cd optímízutíon).
Compuríng the executíon píuns generuted by the optímízer uííows you to ¡udge the reíutíve
cost ol one SQL stutement versus unother. You cun use the resuíts to ímprove your SQL stutements.
ln thís sectíon, you'íí íeurn how to víew und ínterpret u coupíe ol exumpíe executíon píuns.
NOTf
Da|aba·c vcr·íon· príor |o Cracíc Da|aba·c 10g don'| au|oma|ícaíí,
ga|hcr ·|a|í·|íc·, and |hc op|ímí2cr au|oma|ícaíí, dc|auí|· |o ruíe-bused
op|ímí2a|íon. Ruíc-ba·cd op|ímí2a|íon u·c· ·,n|ac|íc ruíc· |o gcncra|c
|hc cxccu|íon pían. Co·|-ba·cd op|ímí2a|íon í· |,pícaíí, bc||cr |han
ruíc-ba·cd op|ímí2a|íon bccau·c |hc |ormcr u·c· ac|uaí ín|orma|íon
ga|hcrcd |rom |hc da|a ín |hc |abíc· and índcxc·. í| ,ou'rc u·íng
Cracíc Da|aba·c 9í or bcíov, ,ou can ga|hcr ·|a|í·|íc· ,our·cí| (,ou'íí
ícarn hov |o do |ha| ía|cr ín |hc ·cc|íon ´Ca|hcríng Tabíc S|a|í·|íc·").
fxamining fxccutiun PIans
1he optímízer generutes un executíon píun lor un SQL stutement. You cun exumíne the executíon
píun usíng the SQL*líus EXPLAIN PLAN commund. 1he EXPLAIN PLAN commund popuíutes
u tubíe numed plan_table wíth the SQL stutement's executíon píun (plan_table ís olten
relerred to us the ºpíun tubíe¨). You muy then exumíne thut executíon píun by queryíng the píun
tubíe. 1he lírst thíng you must do ís check íl the píun tubíe currentíy exísts ín the dutubuse.
Chccking if thc PIan TabIc CurrcntIy fxists in thc Databasc
1o check íl the píun tubíe currentíy exísts ín the dutubuse, you shouíd connect to the dutubuse us
the store user und run the loííowíng DESCRIBE commund:
SQL> DESCRIBE plan_table
Name Null? Type
----------------------------------------- -------- --------------
STATEMENT_ID VARCHAR2(30)
S92
Crucíe Dutubuse llg SQL
PLAN_ID NUMBER
TIMESTAMP DATE
REMARKS VARCHAR2(4000)
OPERATION VARCHAR2(30)
OPTIONS VARCHAR2(255)
OBJECT_NODE VARCHAR2(128)
OBJECT_OWNER VARCHAR2(30)
OBJECT_NAME VARCHAR2(30)
OBJECT_ALIAS VARCHAR2(65)
OBJECT_INSTANCE NUMBER(38)
OBJECT_TYPE VARCHAR2(30)
OPTIMIZER VARCHAR2(255)
SEARCH_COLUMNS NUMBER
ID NUMBER(38)
PARENT_ID NUMBER(38)
DEPTH NUMBER(38)
POSITION NUMBER(38)
COST NUMBER(38)
CARDINALITY NUMBER(38)
BYTES NUMBER(38)
OTHER_TAG VARCHAR2(255)
PARTITION_START VARCHAR2(255)
PARTITION_STOP VARCHAR2(255)
PARTITION_ID NUMBER(38)
OTHER LONG
OTHER_XML CLOB
DISTRIBUTION VARCHAR2(30)
CPU_COST NUMBER(38)
IO_COST NUMBER(38)
TEMP_SPACE NUMBER(38)
ACCESS_PREDICATES VARCHAR2(4000)
FILTER_PREDICATES VARCHAR2(4000)
PROJECTION VARCHAR2(4000)
TIME NUMBER(38)
QBLOCK_NAME VARCHAR2(30)
ll you get u tubíe descríptíon símííur to these resuíts, you huve the píun tubíe uíreudy. ll you
get un error, then you need to creute the píun tubíe.
Crcating thc PIan TabIc
ll you don't huve the píun tubíe, you must creute ít. 1o do thís, you run the SQL*líus scrípt
utlxplan.sql (on my \índows computer, the scrípt ís íocuted ín the dírectory E:\oracle_
11g\product\11.1.0\db_1\RDBMS\ADMIN). 1he loííowíng exumpíe shows the commund
to run the utlxplan.sql scrípt:
SQL> @ E:\oracle_11g\product\11.1.0\db_1\RDBMS\ADMIN\utlxplan.sql
NOTf
You'íí nccd |o rcpíacc |hc dírcc|or, pa|h ví|h |hc pa|h |or ,our
cnvíronmcn|.
1he most ímportunt coíumns ín the píun tubíe ure shown ín 1ubíe l6-l.
Chupter l6: SQL 1uníng
S93
Crcating a CcntraI PIan TabIc
ll necessury, u dutubuse udmínístrutor cun creute one centruí píun tubíe. 1hut wuy,
índívíduuí users don't huve to creute theír own píun tubíes. 1o do thís, u dutubuse
udmínístrutor perlorms the loííowíng steps:
1. Creutes the píun tubíe ín u schemu ol theír choíce by runníng the utlxplan.sql
scrípt
2. Creutes u pubííc synonym lor the píun tubíe
3. Crunts uccess on the píun tubíe to the pubííc roíe
Here ís un exumpíe ol these steps:
@ E:\oracle_11g\product\11.1.0\db_1\RDBMS\ADMIN\utlxplan.sql
CREATE PUBLIC SYNONYM plan_table FOR plan_table;
GRANT SELECT, INSERT, UPDATE, DELETE ON plan_table TO PUBLIC;
CuIumn Dcscriptiun
statement_id
Nume you ussígn to the executíon píun.
operation
Dutubuse operutíon perlormed, whích cun be
Scunníng u tubíe
Scunníng un índex
Accessíng rows lrom u tubíe by usíng un índex
}oíníng two tubíes together
Sortíng u row set
lor exumpíe, the operutíon lor uccessíng u tubíe ís TABLE ACCESS.
options
Nume ol the optíon used ín the operutíon. lor exumpíe, the optíon lor u
compíete scun ís FULL.
object_name
Nume ol the dutubuse ob¡ect relerenced ín the operutíon.
object_type
Attríbute ol ob¡ect. lor exumpíe, u uníque índex hus the uttríbute ol
UNIQUE.
id
Number ussígned to thís operutíon ín the executíon píun.
parent_id
lurent number lor the current step ín the executíon píun. 1he parent_
id vuíue reíutes to un id vuíue lrom u purent step.
position
lrocessíng order lor steps thut huve the sume parent_id.
cost
Lstímute ol uníts ol work lor operutíon. Cost-bused optímízutíon uses
dísk l/C, ClL usuge, und memory usuge us uníts ol work. 1herelore, the
cost ís un estímute ol the number ol dísk l/Cs und the umount ol ClL
und memory used ín perlormíng un operutíon.
TABlf 16-1 íían Tabíc Coíumn·
S94
Crucíe Dutubuse llg SQL
Gcncrating an fxccutiun PIan
Cnce you huve u píun tubíe, you cun use the EXPLAIN PLAN commund to generute un executíon
píun lor un SQL stutement. 1he syntux lor the EXPLAIN PLAN commund ís us loííows:
EXPLAIN PLAN SET STATEMENT_ID = statement_id FOR sql_statement;
where
statement_id ís the nume you wunt to cuíí the executíon píun. 1hís cun be uny
uíphunumeríc text.
sql_statement ís the SQL stutement you wunt to generute un executíon píun lor.
1he loííowíng exumpíe generutes the executíon píun lor u query thut retríeves uíí rows lrom
the customers tubíe (notíce thut the statement_id ís set to 'CUSTOMERS'):
EXPLAIN PLAN SET STATEMENT_ID = 'CUSTOMERS' FOR
SELECT customer_id, first_name, last_name FROM customers;
Explained
Alter the commund compíetes, you muy exumíne the executíon píun stored ín the píun tubíe.
You'íí see how to do thut next.
NOTf
Thc qucr, ín |hc EXPLAIN PLAN ·|a|cmcn| doc·n'| rc|urn rov·
|rom |hc customers |abíc. Thc EXPLAIN PLAN ·|a|cmcn| ·ímpí,
gcncra|c· |hc cxccu|íon pían |ha| vouíd bc u·cd í| |hc qucr, va· run.
Qucrying thc PIan TabIc
lor queryíng the píun tubíe, l huve províded un SQL*líus scrípt numed explain_plan.sql ín
the SQL dírectory. 1he scrípt prompts you lor the statement_id und then díspíuys the executíon
píun lor thut stutement.
1he explain_plan.sql scrípt ís us loííows:
-- Displays the execution plan for the specified statement_id
UNDEFINE v_statement_id;
SELECT
id ||
DECODE(id, 0, '', LPAD(' ', 2*(level - 1))) || ' ' ||
operation || ' ' ||
options || ' ' ||
object_name || ' ' ||
object_type || ' ' ||
DECODE(cost, NULL, '', 'Cost = ' || position)
AS execution_plan
FROM plan_table
CONNECT BY PRIOR id = parent_id
AND statement_id = '&&v_statement_id'
START WITH id = 0
AND statement_id = '&v_statement_id';
Chupter l6: SQL 1uníng

An executíon píun ís orgunízed ínto u híerurchy ol dutubuse operutíons símííur to u tree, the
detuíís ol these operutíons ure stored ín the píun tubíe. 1he operutíon wíth un id ol 0 ís the root
ol the híerurchy, und uíí the other operutíons ín the píun stem lrom thís root. 1he query ín the
scrípt retríeves the detuíís ol the operutíons, sturtíng wíth the root operutíon und then nuvígutíng
the tree lrom the root.
1he loííowíng exumpíe shows how to run the explain_plan.sql scrípt to retríeve the
'CUSTOMERS' píun creuted eurííer:
SQL> @ c:\sql_book\sql\explain_plan.sql
Enter value for v_statement_id: CUSTOMERS
old 12: statement_id = '&&v_statement_id'
new 12: statement_id = 'CUSTOMERS'
old 14: statement_id = '&v_statement_id'
new 14: statement_id = 'CUSTOMERS'
EXECUTION_PLAN
----------------------------------------------
0 SELECT STATEMENT Cost = 3
1 TABLE ACCESS FULL CUSTOMERS TABLE Cost = 1
1he operutíons shown ín the EXECUTION_PLAN coíumn ure executed ín the loííowíng order:
1he ríghtmost índented operutíon ís executed lírst, loííowed by uny purent operutíons
ubove ít.
lor operutíons wíth the sume índentutíon, the topmost operutíon ís executed lírst,
loííowed by uny purent operutíons ubove ít.
Luch operutíon leeds íts resuíts buck up the chuín to íts ímmedíute purent operutíon, und the
purent operutíon ís then executed. ln the EXECUTION_PLAN coíumn, the operutíon lD ís shown
on the lur íelt. ln the exumpíe executíon píun, operutíon l ís run lírst, wíth the resuíts ol thut
operutíon beíng pussed to operutíon 0. 1he loííowíng exumpíe íííustrutes the orderíng lor u more
compíex exumpíe:
0 SELECT STATEMENT Cost = 6
1 MERGE JOIN Cost = 1
2 TABLE ACCESS BY INDEX ROWID PRODUCT_TYPES TABLE Cost = 1
3 INDEX FULL SCAN PRODUCT_TYPES_PK INDEX (UNIQUE) Cost = 1
4 SORT JOIN Cost = 2
5 TABLE ACCESS FULL PRODUCTS TABLE Cost = 1
1he order ín whích the operutíons ure executed ín thís exumpíe ís 3, 2, 5, 4, l, und 0.
Now thut you've seen the order ín whích operutíons ure executed, ít's tíme to move onto whut
the operutíons uctuuííy do. 1he executíon píun lor the 'CUSTOMERS' query wus
0 SELECT STATEMENT Cost = 3
1 TABLE ACCESS FULL CUSTOMERS TABLE Cost = 1
Cperutíon l ís run lírst, wíth the resuíts ol thut operutíon beíng pussed to operutíon 0.
Cperutíon l ínvoíves u luíí tubíe scuníndícuted by the stríng TABLE ACCESS FULLon the
customers tubíe. Here's the orígínuí commund used to generute the 'CUSTOMERS' query:
EXPLAIN PLAN SET STATEMENT_ID = 'CUSTOMERS' FOR
SELECT customer_id, first_name, last_name FROM customers;
S96
Crucíe Dutubuse llg SQL
A luíí tubíe scun ís perlormed becuuse the SELECT stutement specílíes thut uíí the rows lrom
the customers tubíe ure to be retríeved.
1he totuí cost ol the query ís three work uníts, us índícuted ín the cost purt shown to the ríght
ol operutíon 0 ín the executíon píun (0 SELECT STATEMENT Cost = 3). A work unít ís the
umount ol processíng the soltwure hus to do to perlorm u gíven operutíon. 1he hígher the cost,
the more work the dutubuse soltwure hus to do to compíete the SQL stutement.
NOTf
í| ,ou'rc u·íng a vcr·íon o| |hc da|aba·c príor |o Cracíc Da|aba·c 10g,
|hcn |hc ou|pu| |or |hc ovcraíí ·|a|cmcn| co·| ma, bc bían|. Tha|'·
bccau·c caríícr da|aba·c vcr·íon· don'| au|oma|ícaíí, coíícc| |abíc
·|a|í·|íc·. ín ordcr |o ga|hcr ·|a|í·|íc·, ,ou havc |o u·c |hc ANALYZE
command. You'íí ícarn hov |o do |ha| ía|cr ín |hc ·cc|íon ´Ca|hcríng
Tabíc S|a|í·|íc·."
fxccutiun PIans lnvuIving TabIc |uins
Lxecutíon píuns lor queríes wíth tubíe ¡oíns ure more compíex. 1he loííowíng exumpíe generutes
the executíon píun lor u query thut ¡oíns the products und product_types tubíes:
EXPLAIN PLAN SET STATEMENT_ID = 'PRODUCTS' FOR
SELECT p.name, pt.name
FROM products p, product_types pt
WHERE p.product_type_id = pt.product_type_id;
1he executíon píun lor thís query ís shown ín the loííowíng exumpíe:
@ c:\sql_book\sql\explain_plan.sql
Enter value for v_statement_id: PRODUCTS
EXECUTION_PLAN
----------------------------------------------------------------
0 SELECT STATEMENT Cost = 6
1 MERGE JOIN Cost = 1
2 TABLE ACCESS BY INDEX ROWID PRODUCT_TYPES TABLE Cost = 1
3 INDEX FULL SCAN PRODUCT_TYPES_PK INDEX (UNIQUE) Cost = 1
4 SORT JOIN Cost = 2
5 TABLE ACCESS FULL PRODUCTS TABLE Cost = 1
NOTf
í| ,ou run |hc cxampíc, ,ou ma, gc| a ·íígh|í, dí||crcn| cxccu|íon
pían dcpcndíng on |hc vcr·íon o| |hc da|aba·c ,ou arc u·íng and
on |hc ·c||íng· o| |hc paramc|cr· ín |hc da|aba·c'· init.ora
con|ígura|íon |ííc.
1he prevíous executíon píun ís more compíex, und you cun see the híerurchícuí reíutíonshíps
between the vuríous operutíons. 1he executíon order ol the operutíons ís 3, 2, 5, 4, l, und 0. 1ubíe
l6-2 descríbes euch operutíon ín the order they ure perlormed.
Chupter l6: SQL 1uníng
S97
Gathcring TabIc Statistics
ll you're usíng u versíon ol the dutubuse príor to Crucíe Dutubuse l0g (such us 9í ), then you'íí
huve to guther tubíe stutístícs yourseíl usíng the ANALYZE commund. ßy deluuít, íl no stutístícs ure
uvuííubíe then ruíe-bused optímízutíon ís used. Ruíe-bused optímízutíon ísn't usuuííy us good us
cost-bused optímízutíon.
1he loííowíng exumpíes use the ANALYZE commund to guther stutístícs lor the products
und product_types tubíes:
ANALYZE TABLE products COMPUTE STATISTICS;
ANALYZE TABLE product_types COMPUTE STATISTICS;
Cnce the stutístícs huve been guthered, cost-bused optímízutíon wííí be used ruther thun ruíe-
bused optímízutíon.
Cumparing fxccutiun PIans
ßy compuríng the totuí cost shown ín the executíon píun lor díllerent SQL stutements, you cun
determíne the vuíue ol tuníng your SQL. ln thís sectíon, you'íí see how to compure two executíon
píuns und see the benelít ol usíng EXISTS ruther thun DISTINCT (u típ l guve eurííer). 1he loííowíng
exumpíe generutes un executíon píun lor u query thut uses EXISTS:
EXPLAIN PLAN SET STATEMENT_ID = 'EXISTS_QUERY' FOR
SELECT product_id, name
FROM products outer
WHERE EXISTS
(SELECT 1
FROM purchases inner
WHERE inner.product_id = outer.product_id);
Opcratiun lD Dcscriptiun
3 luíí scun ol the índex product_types_pk (whích ís u uníque índex)
to obtuín the uddresses ol the rows ín the product_types tubíe. 1he
uddresses ure ín the lorm ol ROWID vuíues, whích ure pussed to operutíon 2.
2 Access the rows ín the product_types tubíe usíng the ííst ol ROWID
vuíues pussed lrom operutíon 3. 1he rows ure pussed to operutíon l.
5 Access the rows ín the products tubíe. 1he rows ure pussed to operutíon 4.
4 Sort the rows pussed lrom operutíon 5. 1he sorted rows ure pussed to
operutíon l.
l Merge the rows pussed lrom operutíons 2 und 5. 1he merged rows ure
pussed to operutíon 0.
0 Return the rows lrom operutíon l to the user. 1he totuí cost ol the query ís
6 work uníts.
TABlf 16-2 íxccu|íon íían Cpcra|íon·
S98
Crucíe Dutubuse ll SQL
1he executíon píun lor thís query ís shown ín the loííowíng exumpíe:
@ c:\sql_book\sql\explain_plan.sql
Enter value for v_statement_id: EXISTS_QUERY
EXECUTION_PLAN
------------------------------------------------------------
0 SELECT STATEMENT Cost = 4
1 MERGE JOIN SEMI Cost = 1
2 TABLE ACCESS BY INDEX ROWID PRODUCTS TABLE Cost = 1
3 INDEX FULL SCAN PRODUCTS_PK INDEX (UNIQUE) Cost = 1
4 SORT UNIQUE Cost = 2
5 INDEX FULL SCAN PURCHASES_PK INDEX (UNIQUE) Cost = 1
As you cun see, the totuí cost ol the query ís 4 work uníts. 1he next exumpíe generutes un
executíon píun lor u query thut uses DISTINCT:
EXPLAIN PLAN SET STATEMENT_ID = 'DISTINCT_QUERY' FOR
SELECT DISTINCT pr.product_id, pr.name
FROM products pr, purchases pu
WHERE pr.product_id = pu.product_id;
1he executíon píun lor thís query ís shown ín the loííowíng exumpíe:
@ c:\sql_book\sql\explain_plan.sql
Enter value for v_statement_id: DISTINCT_QUERY
EXECUTION_PLAN
--------------------------------------------------------------
0 SELECT STATEMENT Cost = 5
1 HASH UNIQUE Cost = 1
2 MERGE JOIN Cost = 1
3 TABLE ACCESS BY INDEX ROWID PRODUCTS TABLE Cost = 1
4 INDEX FULL SCAN PRODUCTS_PK INDEX (UNIQUE) Cost = 1
5 SORT JOIN Cost = 2
6 INDEX FULL SCAN PURCHASES_PK INDEX (UNIQUE) Cost = 1
1he cost lor the query ís 5 work uníts. 1hís query ís more costíy thun the eurííer query thut
used EXISTS (thut query hud u cost ol oníy 4 work uníts). 1hese resuíts prove ít ís better to use
EXISTS thun DISTINCT.
Passing Hints tu thc Optimizcr
You cun puss hínts to the optímízer. A hínt ís un optímízer dírectíve thut ínlíuences the optímízer's
choíce ol executíon píun. 1he correct hínt muy ímprove the perlormunce ol un SQL stutement.
You cun check the ellectíveness ol u hínt by compuríng the cost ín the executíon píun ol un SQL
stutement wíth und wíthout the hínt.
ln thís sectíon, you'íí see un exumpíe query thut uses one ol the more useluí hínts: the
FIRST_ROWS(n) hínt. 1he FIRST_ROWS(n) hínt teíís the optímízer to generute un executíon
píun thut wííí mínímíze the tíme tuken to return the lírst n rows ín u query. 1hís hínt cun be useluí
when you don't wunt to wuít uround too íong belore gettíng  rows buck lrom your query, but
you stííí wunt to see uíí the rows.
Chupter l6: SQL 1uníng
S99
1he loííowíng exumpíe generutes un executíon píun lor u query thut uses FIRST_ROWS(2),
notíce thut the hínt ís píuced wíthín the stríngs /*+ und */:
EXPLAIN PLAN SET STATEMENT_ID = 'HINT' FOR
SELECT /*+ FIRST_ROWS(2) */ p.name, pt.name
FROM products p, product_types pt
WHERE p.product_type_id = pt. product_type_id;
CAUTlON
Your hín| mu·| u·c |hc exuct ·,n|ax ·hovno|hcrví·c, |hc hín|
vííí bc ígnorcd. Thc ·,n|ax í·: /*+ |oííovcd b, onc ·pacc, |hc
hín|, |oííovcd b, onc ·pacc, and */.
1he executíon píun lor thís query ís shown ín the loííowíng exumpíe, notíce thut the cost ís
4 work uníts:
@ c:\sql_book\sql\explain_plan.sql
Enter value for v_statement_id: HINT
EXECUTION_PLAN
------------------------------------------------------------------
0 SELECT STATEMENT Cost = 4
1 NESTED LOOPS
2 NESTED LOOPS Cost = 1
3 TABLE ACCESS FULL PRODUCTS TABLE Cost = 1
4 INDEX UNIQUE SCAN PRODUCT_TYPES_PK INDEX (UNIQUE) Cost = 2
5 TABLE ACCESS BY INDEX ROWID PRODUCT_TYPES TABLE Cost = 2
1he next exumpíe generutes un executíon píun lor the sume query wíthout the hínt:
EXPLAIN PLAN SET STATEMENT_ID = 'NO_HINT' FOR
SELECT p.name, pt.name
FROM products p, product_types pt
WHERE p.product_type_id = pt. product_type_id;
1he executíon píun lor the query ís shown ín the loííowíng exumpíe, notíce the cost ís 6 work
uníts (hígher thun the query wíth the hínt):
@ c:\sql_book\sql\explain_plan.sql
Enter value for v_statement_id: NO_HINT
EXECUTION_PLAN
----------------------------------------------------------------
0 SELECT STATEMENT Cost = 6
1 MERGE JOIN Cost = 1
2 TABLE ACCESS BY INDEX ROWID PRODUCT_TYPES TABLE Cost = 1
3 INDEX FULL SCAN PRODUCT_TYPES_PK INDEX (UNIQUE) Cost = 1
4 SORT JOIN Cost = 2
5 TABLE ACCESS FULL PRODUCTS TABLE Cost = 1
1hese resuíts show thut the íncíusíon ol the hínt reduces the cost ol runníng the query by
2 work uníts.
600
Crucíe Dutubuse llg SQL
1here ure muny hínts thut you cun use, und thís sectíon hus mereíy gíven you u tuste ol the
sub¡ect.
AdditiunaI Tuning TuuIs
ln thís línuí sectíon, l'íí mentíon some other tuníng tooís. luíí coveruge ol these tooís ís beyond
the scope ol thís book. You cun reud the Cracíc Da|aba·c ícr|ormancc Tuníng Cuídc, pubííshed
by Crucíe Corporutíon, lor luíí detuíís ol the tooís mentíoned ín thís sectíon und lor u comprehensíve
ííst ol hínts.
OracIc fntcrprisc Managcr Diagnustics Pack
1he Crucíe Lnterpríse Munuger Díugnostícs luck cuptures operutíng system, míddíe tíer, und
uppíícutíon perlormunce dutu, us weíí us dutubuse perlormunce dutu. 1he Díugnostícs luck
unuíyzes thís perlormunce dutu und díspíuys the resuíts gruphícuííy. A dutubuse udmínístrutor cun
uíso conlígure the Díugnostícs luck to uíert them ímmedíuteíy ol perlormunce probíems víu e-muíí
or puge. Crucíe Lnterpríse Munuger uíso íncíudes soltwure guídes to heíp resoíve perlormunce
probíems.
Autumatic Databasc Diagnustic Munitur
1he Automutíc Dutubuse Díugnostíc Monítor (ADDM) ís u seíl-díugnostíc moduíe buíít ínto the
Crucíe dutubuse soltwure. ADDM enubíes u dutubuse udmínístrutor to monítor the dutubuse lor
perlormunce probíems by unuíyzíng system perlormunce over u íong períod ol tíme. 1he dutubuse
udmínístrutor cun víew the perlormunce ínlormutíon generuted by ADDM ín Crucíe Lnterpríse
Munuger. \hen ADDM línds perlormunce probíems, ít wííí suggest soíutíons lor correctíve
uctíon. Some exumpíe ADDM suggestíons íncíude
Hurdwure chungeslor exumpíe, uddíng ClLs to the dutubuse server
Dutubuse conlígurutíonlor exumpíe, chungíng the dutubuse ínítíuíízutíon purumeter
settíngs
Appíícutíon chungeslor exumpíe, usíng the cuche optíon lor sequences or usíng bínd
vuríubíes
Lse other udvísorslor exumpíe, runníng the SQL 1uníng Advísor und SQL Access
Advísor on SQL stutements thut ure consumíng the most dutubuse resources to execute
You'íí íeurn ubout the SQL 1uníng Advísor und SQL Access Advísor next.
SQl Tuning Advisur
1he SQL 1uníng Advísor uííows u deveíoper or dutubuse udmínístrutor to tune un SQL stutement
usíng the loííowíng ítems:
1he text ol the SQL stutement
1he SQL ídentílíer ol the stutement (obtuíned lrom the V$SQL_PLAN víew, whích ís one
ol the víews uvuííubíe to u dutubuse udmínístrutor)
1he runge ol snupshot ídentílíers
1he SQL 1uníng Set nume
Chupter l6: SQL 1uníng
601
An SQL 1uníng Set ís u set ol SQL stutements wíth theír ussocíuted executíon píun und executíon
stutístícs. SQL 1uníng Sets ure unuíyzed to generute SQL lrolííes thut heíp the optímízer to choose
the optímuí executíon píun. SQL lrolííes contuín coííectíons ol ínlormutíon thut enubíe optímízutíon
ol the executíon píun.
SQl Acccss Advisur
1he SQL Access Advísor provídes u deveíoper or dutubuse udmínístrutor wíth perlormunce udvíce
on muteríuíízed víews, índexes, und muteríuíízed víew íogs. 1he SQL Access Advísor exumínes
spuce usuge und query perlormunce und recommends the most cost-ellectíve conlígurutíon ol
new und exístíng muteríuíízed víews und índexes.
Summary
ln thís chupter, you huve íeurned the loííowíng:
1uníng ís the process ol mukíng your SQL stutements run luster.
1he optímízer ís u subsystem ol the Crucíe dutubuse soltwure thut generutes un executíon
píun, whích ís u set ol operutíons used to perlorm u purtícuíur SQL stutement.
Hínts muy be pussed to the optímízer to ínlíuence the generuted executíon píun lor un
SQL stutement.
1here ure u number ol uddítíonuí soltwure tooís u dutubuse udmínístrutor cun use to tune
the dutubuse.
ln the next chupter, you'íí íeurn ubout XML.
This page intentionally left blank
\IAI1II
17
XML und the Crucíe
Dutubuse
603
604
Crucíe Dutubuse ll SQL
n thís chupter, you wííí do the loííowíng:
ßecome íntroduced to XML
See how to generute XML lrom reíutíonuí dutu
Lxumíne how to suve XML ín the dutubuse
lntruducing XMl
1he Lxtensíbíe Murkup Lunguuge (XML) ís u generuí-purpose murkup íunguuge. XML enubíes you
to shure structured dutu ucross the lnternet, und cun be used to encode dutu und other documents.
Some udvuntuges ol XML íncíude the loííowíng:
XML cun be reud by humuns und computers, und ís stored us píuín text.
XML ís píutlorm índependent.
XML supports Lnícode, whích meuns ít cun store ínlormutíon wrítten ín muny humun
íunguuges.
XML uses u seíl-documentíng lormut thut contuíns the document structure, eíement
numes, und eíement vuíues.
ßecuuse ol these udvuntuges, XML ís wídeíy used lor document storuge und processíng, und ít
ís used by muny orgunízutíons to send dutu between theír computer systems. lor exumpíe, muny
suppííers uííow theír customers to send purchuse orders us XML lííes over the lnternet.
Crucíe Dutubuse 9 íntroduced the ubíííty to store XML ín the dutubuse, uíong wíth extensíve
lunctíonuííty lor munípuíutíng und processíng XML. Crucíe Dutubuse l0 Reíeuse 2 udded
uddítíonuí XML-generutíng lunctíons, und Crucíe Dutubuse ll udds cupubííítíes ííke }uvu und C
processíng ol bínury XML (bínury XML provídes more ellícíent storuge und munípuíutíon ol XML
ín the dutubuse). 1hís chupter locuses on u useluí subset ol the XML cupubííítíes ín the Crucíe
dutubuse.
ll you ure new to XML, you wííí línd u weuíth ol ínlormutíon ut the loííowíng websítes:
http://www.w3.org/XML
http://www.wíkípedíu.org/wíkí/XML
Gcncrating XMl frum RcIatiunaI Data
1he Crucíe dutubuse contuíns u number ol SQL lunctíons you cun use lor generutíng XML, und ín
thís sectíon you'íí see how to generute XML lrom reíutíonuí dutu usíng some ol these lunctíons.

Chupter l7: XML und the Crucíe Dutubuse
60S
XMlflfMfNT()
You use the XMLELEMENT() lunctíon to generute XML eíements lrom reíutíonuí dutu. You suppíy
u nume lor the eíement, píus the coíumn you wísh to retríeve to XMLELEMENT(), und ít returns
the eíements us XMLType ob¡ects. 1he XMLType ís u buíít-ín Crucíe dutubuse type thut ís used to
represent XML dutu. ßy deluuít, un XMLType ob¡ect stores the XML dutu us text ín u CLCß (churucter
íurge ob¡ect).
1he loííowíng exumpíe connects us the store user und gets the customer_id coíumn
vuíues us XMLType ob¡ects:
CONNECT store/store_password
SELECT XMLELEMENT("customer_id", customer_id)
AS xml_customers
FROM customers;
XML_CUSTOMERS
----------------------------
<customer_id>1</customer_id>
<customer_id>2</customer_id>
<customer_id>3</customer_id>
<customer_id>4</customer_id>
<customer_id>5</customer_id>
As you cun see lrom these resuíts, XMLELEMENT("customer_id", customer_id)
returns the customer_id vuíues wíthín u customer_id tug. You cun use whutever tug nume
you wunt, us shown ín the loííowíng exumpíe whích uses the tug "cust_id":
SELECT XMLELEMENT("cust_id", customer_id)
AS xml_customers
FROM customers;
XML_CUSTOMERS
--------------------
<cust_id>1</cust_id>
<cust_id>2</cust_id>
<cust_id>3</cust_id>
<cust_id>4</cust_id>
<cust_id>5</cust_id>
1he next exumpíe gets the first_name und dob vuíues lor customer r2:
SELECT XMLELEMENT("first_name", first_name) || XMLELEMENT("dob", dob)
AS xml_customer
FROM customers
WHERE customer_id = 2;
XML_CUSTOMER
-----------------------------------------------------
<first_name>Cynthia</first_name><dob>1968-02-05</dob>

Crucíe Dutubuse llg SQL
1he loííowíng exumpíe uses the TO_CHAR() lunctíon to chunge the dute lormut lor the dob
vuíue:
SELECT XMLELEMENT("dob", TO_CHAR(dob, 'MM/DD/YYYY'))
AS xml_dob
FROM customers
WHERE customer_id = 2;
XML_DOB
---------------------
<dob>02/05/1968</dob>
1he next exumpíe embeds two cuíís to XMLELEMENT() wíthín un outer cuíí to XMLELEMENT(),
notíce thut the returned customer_id und name eíements ure contuíned wíthín un outer
customer eíement:
SELECT XMLELEMENT(
"customer",
XMLELEMENT("customer_id", customer_id),
XMLELEMENT("name", first_name || ' ' || last_name)
)
AS xml_customers
FROM customers
WHERE customer_id IN (1, 2);
XML_CUSTOMERS
------------------------------
<customer>
<customer_id>1</customer_id>
<name>John Brown</name>
</customer>
<customer>
<customer_id>2</customer_id>
<name>Cynthia Green</name>
</customer>

í'vc addcd ·omc íínc brca|· and ·pacc· ín |hc X\í rc|urncd b, |hí·
qucr, |o ma|c |hc X\í ca·ícr |o rcad. í'vc donc |hc ·amc |híng ín
·omc o| |hc o|hcr cxampíc· ín |hí· chap|cr.
You cun retríeve reguíur reíutíonuí dutu us weíí us XML, us shown ín the loííowíng exumpíe,
whích retríeves the customer_id coíumn us u reguíur reíutíonuí resuít und the first_name
und last_name coíumns concutenuted together us XML eíements:
SELECT customer_id,
XMLELEMENT("customer", first_name || ' ' || last_name) AS xml_customer
FROM customers;
Chupter l7: XML und the Crucíe Dutubuse

CUSTOMER_ID XML_CUSTOMER
----------- ----------------------------------
1 <customer>John Brown</customer>
2 <customer>Cynthia Green</customer>
3 <customer>Steve White</customer>
4 <customer>Gail Black</customer>
5 <customer>Doreen Blue</customer>
You cun generute XML lor dutubuse ob¡ects, us shown ín the next exumpíe whích connects
us object_user und gets the id und address coíumns lor customer rl ín the object_
customers tubíe (the address coíumn stores un ob¡ect ol type t_address):
CONNECT object_user/object_password
SELECT XMLELEMENT("id", id) || XMLELEMENT("address", address)
AS xml_object_customer
FROM object_customers
WHERE id = 1;
XML_OBJECT_CUSTOMER
-----------------------------------
<id>1</id>
<address>
<T_ADDRESS>
<STREET>2 State Street</STREET>
<CITY>Beantown</CITY>
<STATE>MA</STATE>
<ZIP>12345</ZIP>
</T_ADDRESS>
</address>
You cun generute XML lor coííectíons, us shown ín the next exumpíe, whích connects us
collection_user und gets the id und addresses coíumns lor customer rl stored ín
customers_with_nested_table (the addresses coíumn stores un ob¡ect ol type t_
nested_table_address, whích ís u nested tubíe ol t_address ob¡ects):
CONNECT collection_user/collection_password
SELECT XMLELEMENT("id", id) || XMLELEMENT("addresses", addresses)
AS xml_customer
FROM customers_with_nested_table
WHERE id = 1;
XML_CUSTOMER
---------------------------------------------------------
<id>1</id>
<addresses>
<T_NESTED_TABLE_ADDRESS>
<T_ADDRESS>
<STREET>2 State Street</STREET><CITY>Beantown</CITY>
<STATE>MA</STATE><ZIP>12345</ZIP>
</T_ADDRESS>
608
Crucíe Dutubuse ll SQL
<T_ADDRESS>
<STREET>4 Hill Street</STREET>
<CITY>Lost Town</CITY>
<STATE>CA</STATE>
<ZIP>54321</ZIP>
</T_ADDRESS>
</T_NESTED_TABLE_ADDRESS>
</addresses>
XMlATTRlBUTfS()
You use XMLATTRIBUTES() ín con¡unctíon wíth XMLELEMENT() to specíly the uttríbutes lor the
XML eíements retríeved by XMLELEMENT(). 1he loííowíng exumpíe connects us the store user
und uses XMLATTRIBUTES() to set uttríbute numes lor the customer_id, first_name,
last_name, und dob eíements:
CONNECT store/store_password
SELECT XMLELEMENT(
"customer",
XMLATTRIBUTES(
customer_id AS "id",
first_name || ' ' || last_name AS "name",
TO_CHAR(dob, 'MM/DD/YYYY') AS "dob"
)
)
AS xml_customers
FROM customers
WHERE customer_id IN (1, 2);
XML_CUSTOMERS
------------------------------------------------------------------
<customer id="1" name="John Brown" dob="01/01/1965"></customer>
<customer id="2" name="Cynthia Green" dob="02/05/1968"></customer>
Notíce thut the id, name, und dob uttríbutes ure returned ínsíde customer.
XMlfORfST()
You use XMLFOREST() to generute u ºlorest¨ ol XML eíements. XMLFOREST() concutenutes
XML eíements together wíthout you huvíng to use the concutenutíon operutor || wíth muítípíe
cuíís to XMLELEMENT(). 1he loííowíng exumpíe uses XMLFOREST() to get the customer_id,
phone, und dob lor customers rl und r2:
SELECT XMLELEMENT(
"customer",
XMLFOREST(
customer_id AS "id",
phone AS "phone",
TO_CHAR(dob, 'MM/DD/YYYY') AS "dob"
)
)
AS xml_customers
Chupter l7: XML und the Crucíe Dutubuse
609
FROM customers
WHERE customer_id IN (1, 2);
XML_CUSTOMERS
-----------------------------
<customer>
<id>1</id>
<phone>800-555-1211</phone>
<dob>01/01/1965</dob>
</customer>
<customer>
<id>2</id>
<phone>800-555-1212</phone>
<dob>02/05/1968</dob>
</customer>
1he loííowíng commund sets the SQL*líus LONG purumeter to 500, so you cun see uíí the
XML returned by the subsequent queríes (LONG controís the muxímum íength ol text dutu
díspíuyed by SQL*líus):
SET LONG 500
1he loííowíng query píuces the customer nume ínsíde the customer eíement tug usíng
XMLATTRIBUTES():
SELECT XMLELEMENT(
"customer",
XMLATTRIBUTES(first_name || ' ' || last_name AS "name"),
XMLFOREST(phone AS "phone", TO_CHAR(dob, 'MM/DD/YYYY') AS "dob")
)
AS xml_customers
FROM customers
WHERE customer_id IN (1, 2);
XML_CUSTOMERS
-------------------------------
<customer name="John Brown">
<phone>800-555-1211</phone>
<dob>01/01/1965</dob>
</customer>
<customer name="Cynthia Green">
<phone>800-555-1212</phone>
<dob>02/05/1968</dob>
</customer>
XMlAGG()
You use XMLAGG() to generute u lorest ol XML eíements lrom u coííectíon ol XML eíements.
XMLAGG() ís typícuííy used lor groupíng XML together ínto u common ííst ol ítems underneuth
one purent or lor retríevíng dutu lrom coííectíons. You cun use the GROUP BY cíuuse ol u query

Crucíe Dutubuse ll SQL
to group the retuned set ol rows ínto muítípíe groups, und you cun use un ORDER BY cíuuse ol
XMLAGG() to sort the rows.
ßy deluuít, ORDER BY sorts the resuíts ín uscendíng order, but you cun udd DESC ulter the ííst
ol coíumns to sort the rows ín descendíng order. You cun udd ASC to expíícítíy índícute un uscendíng
sort. You cun uíso udd NULLS LAST to put uny nuíí vuíues ut the end ol the resuíts.
1he loííowíng exumpíe retríeves the customer first_name und last_name vuíues und returns
them ín u ííst numed customer_list, notíce thut ORDER BY ís used wíth XMLAGG() to sort the
resuíts by the first_name coíumn. l've udded ASC to expíícítíy índícute un uscendíng sort:
SELECT XMLELEMENT(
"customer_list",
XMLAGG(
XMLELEMENT("customer", first_name || ' ' || last_name)
ORDER BY first_name ASC
)
)
AS xml_customers
FROM customers
WHERE customer_id IN (1, 2);
XML_CUSTOMERS
------------------------------------
<customer_list>
<customer>Cynthia Green</customer>
<customer>John Brown</customer>
</customer_list>
1he next exumpíe retríeves the product_type_id und uveruge price lor euch group ol
products, notíce thut the products ure grouped by product_type_id usíng the GROUP BY
cíuuse ol the query, und NULLS LAST ís used ín the ORDER BY cíuuse ol XMLAGG() to píuce
the row wíth the nuíí product_type_id ut the end ol the returned resuíts:
SELECT XMLELEMENT(
"product_list",
XMLAGG(
XMLELEMENT(
"product_type_and_avg", product_type_id || ' ' || AVG(price)
)
ORDER BY product_type_id NULLS LAST
)
)
AS xml_products
FROM products
GROUP BY product_type_id;
XML_PRODUCTS
-------------------------------------------------------
<product_list>
<product_type_and_avg>1 24.975</product_type_and_avg>
<product_type_and_avg>2 26.22</product_type_and_avg>
<product_type_and_avg>3 13.24</product_type_and_avg>
Chupter l7: XML und the Crucíe Dutubuse

<product_type_and_avg>4 13.99</product_type_and_avg>
<product_type_and_avg> 13.49</product_type_and_avg>
</product_list>

You can aí·o píacc |hc nuíí rov |ír·| b, ·pccí|,íng NULLS FIRST ín
|hc ORDER BY cíau·c o| XMLAGG().
1he next exumpíe retríeves the product_type_id und name lor the products wíth
product_type_id vuíues ol l und 2, und the products ure grouped by product_type_id:
SELECT XMLELEMENT(
"products_in_group",
XMLATTRIBUTES(product_type_id AS "prd_type_id"),
XMLAGG(
XMLELEMENT("name", name)
)
)
AS xml_products
FROM products
WHERE product_type_id IN (1, 2)
GROUP BY product_type_id;
XML_PRODUCTS
-----------------------------------
<products_in_group prd_type_id="1">
<name>Modern Science</name>
<name>Chemistry</name>
</products_in_group>
<products_in_group prd_type_id="2">
<name>Supernova</name>
<name>2412: The Return</name>
</products_in_group>
1he next exumpíe connects us collection_user und retríeves the uddresses lor customer
rl lrom customers_with_nested_table:
CONNECT collection_user/collection_password
SELECT XMLELEMENT("customer",
XMLAGG(
XMLELEMENT("addresses", addresses)
)
)
AS xml_customer
FROM customers_with_nested_table
WHERE id = 1;
XML_CUSTOMER
---------------------------------------
<customer>
<addresses>
612
Crucíe Dutubuse ll SQL
<T_NESTED_TABLE_ADDRESS>
<T_ADDRESS>
<STREET>2 State Street</STREET>
<CITY>Beantown</CITY>
<STATE>MA</STATE>
<ZIP>21345</ZIP>
</T_ADDRESS>
<T_ADDRESS>
<STREET>4 Hill Street</STREET>
<CITY>Lost Town</CITY>
<STATE>CA</STATE>
<ZIP>54321</ZIP>
</T_ADDRESS>
</T_NESTED_TABLE_ADDRESS>
</addresses>
</customer>
XMlCOlATTVAl()
You use XMLCOLATTVAL() to creute un XML lrugment und then expund the resuítíng XML. Luch
XML lrugment hus the nume coíumn wíth the uttríbute nume. You cun use the AS cíuuse to chunge
the uttríbute nume.
1he loííowíng exumpíe connects us the store user retríeves the customer_id, dob, und
phone vuíues lor customers rl und r2:
CONNECT store/store_password
SELECT XMLELEMENT(
"customer",
XMLCOLATTVAL(
customer_id AS "id",
dob AS "dob",
phone AS "phone"
)
)
AS xml_customers
FROM customers
WHERE customer_id IN (1, 2);
XML_CUSTOMERS
----------------------------------------------
<customer>
<column name = "id">1</column>
<column name = "dob">1965-01-01</column>
<column name = "phone">800-555-1211</column>
</customer>
<customer>
<column name = "id">2</column>
<column name = "dob">1968-02-05</column>
<column name = "phone">800-555-1212</column>
</customer>
Chupter l7: XML und the Crucíe Dutubuse
613
XMlCONCAT()
You use XMLCONCAT() to concutenute u seríes ol eíements lor euch row. 1he loííowíng exumpíe
concutenutes the XML eíements lor first_name, last_name, und phone vuíues lor customers
rl und r2:
SELECT XMLCONCAT(
XMLELEMENT("first name", first_name),
XMLELEMENT("last name", last_name),
XMLELEMENT("phone", phone)
)
AS xml_customers
FROM customers
WHERE customer_id IN (1, 2);
XML_CUSTOMERS
--------------------------------
<first name>John</first name>
<last name>Brown</last name>
<phone>800-555-1211</phone>
<first name>Cynthia</first name>
<last name>Green</last name>
<phone>800-555-1212</phone>
XMlPARSf()
You use XMLPARSE() to purse und generute XML lrom the evuíuuted resuít ol un expressíon. 1he
expressíon must resoíve to u stríng, íl the expressíon resoíves to nuíí, then XMLPARSE() returns
nuíí. You must specíly one ol the loííowíng ítems belore the expressíon:
CONTENT, whích meuns the expressíon must resoíve to u vuííd XML vuíue
DOCUMENT, whích meuns the expressíon must resoíve to u síngíy rooted XML document
You cun uíso udd WELLFORMED ulter the expressíon, whích meuns you ure guurunteeíng thut
your expressíon resoíves to u weíí-lormed XML document. 1hís uíso meuns thut the dutubuse wííí
not perlorm vuíídíty checks on your expressíon.
1he loííowíng exumpíe purses un expressíon contuíníng the detuíís lor u customer:
SELECT XMLPARSE(
CONTENT
'<customer><customer_id>1</customer_id><name>John Brown</name></customer>'
WELLFORMED
)
AS xml_customer
FROM dual;
XML_CUSTOMER
------------------------------
<customer>
<customer_id>1</customer_id>
<name>John Brown</name>
</customer>
614
Crucíe Dutubuse llg SQL
NOTf
You can rcad morc abou| vcíí-|ormcd X\í documcn|· and vaíuc· a|
h||p://vvv.vJ.org/TR/RíC-xmí.
XMlPl()
You use XMLPI() to generute un XML processíng ínstructíon. You typícuííy use u processíng
ínstructíon to províde un uppíícutíon wíth ínlormutíon thut ís ussocíuted wíth XML dutu, the
uppíícutíon cun then use the processíng ínstructíon to determíne how to process the XML dutu.
1he loííowíng exumpíe generutes u processíng ínstructíon lor un order stutus:
SELECT XMLPI(
NAME "order_status",
'PLACED, PENDING, SHIPPED'
)
AS xml_order_status_pi
FROM dual;
XML_ORDER_STATUS_PI
-----------------------------------------
<?order_status PLACED, PENDING, SHIPPED?>
1he next exumpíe generutes u processíng ínstructíon to díspíuy un XML document usíng u
cuscudíng styíesheet lííe numed example.css:
SELECT XMLPI(
NAME "xml-stylesheet",
'type="text/css" href="example.css"'
)
AS xml_stylesheet_pi
FROM dual;
XML_STYLESHEET_PI
-----------------------------------------------------
<?xml-stylesheet type="text/css" href="example.css"?>
XMlCOMMfNT()
You use XMLCOMMENT() to generute un XML comment, whích ís u text stríng píuced wíthín <!--
und -->. lor exumpíe:
SELECT XMLCOMMENT(
'An example XML Comment'
)
AS xml_comment
FROM dual;
XML_COMMENT
-----------------------------
<!--An example XML Comment-->
Chupter l7: XML und the Crucíe Dutubuse
61S
XMlSfQUfNCf()
You use XMLSEQUENCE() to generute un XMLSequenceType ob¡ect, whích ís u vurruy ol
XMLType ob¡ects. ßecuuse XMLSEQUENCE() returns u vurruy, you cun use ít ín the FROM
cíuuse ol u query. lor exumpíe:
SELECT VALUE(list_of_values).GETSTRINGVAL() order_values
FROM TABLE(
XMLSEQUENCE(
EXTRACT(
XMLType('<A><B>PLACED</B><B>PENDING</B><B>SHIPPED</B></A>'),
'/A/B'
)
)
) list_of_values;
ORDER_VALUES
--------------
<B>PLACED</B>
<B>PENDING</B>
<B>SHIPPED</B>
Let's breuk down thís exumpíe. 1he cuíí to XMLType() ís
XMLType('<A><B>PLACED</B><B>PENDING</B><B>SHIPPED</B></A>')
1hís creutes un XMLType ob¡ect contuíníng the XML
<A><B>PLACED</B><B>PENDING</B><B>SHIPPED</B></A>.
1he cuíí to the EXTRACT() lunctíon ís
EXTRACT(
XMLType('<A><B>PLACED</B><B>PENDING</B><B>SHIPPED</B></A>'),
'/A/B'
)
EXTRACT() extructs the XML dutu lrom the XMLType ob¡ect returned by the cuíí to XMLType().
1he second purumeter to EXTRACT() ís un Xluth stríng. Xluth ís u íunguuge thut uííows you uccess
specílíc eíements ín XML dutu. lor exumpíe, ín the prevíous cuíí to EXTRACT(), '/A/B' returns uíí
the ß eíements thut ure chíídren ol the A eíements, therelore, the EXTRACT() lunctíon returns the
loííowíng:
<B>PLACED</B>
<B>PENDING</B>
<B>SHIPPED</B>
1he cuíí to XMLSEQUENCE() ín the exumpíe símpíy returns u vurruy contuíníng the eíements
returned by EXTRACT(). TABLE() converts the vurruy ínto u tubíe ol rows und uppííes the uííus
list_of_values to the tubíe. 1he SELECT stutement retríeves the stríng vuíue ol the rows ín
the tubíe usíng GETSTRINGVAL().
You'íí see more exumpíes ol EXTRACT() und Xluth íuter ín thís chupter.
616
Crucíe Dutubuse ll SQL
XMlSfRlAllZf()
You use XMLSERIALIZE() to generute u stríng or LCß (íurge ob¡ect) representutíon ol XML dutu
lrom the evuíuuted resuít ol un expressíon. You must specíly one ol the loííowíng ítems belore the
expressíon:
CONTENT, whích meuns the expressíon must resoíve to u vuííd XML vuíue
DOCUMENT, whích meuns the expressíon must resoíve to u síngíy rooted XML document
1he loííowíng exumpíe uses XMLSERIALIZE() wíth CONTENT to generute un XML vuíue:
SELECT XMLSERIALIZE(
CONTENT XMLType('<order_status>SHIPPED</order_status>')
)
AS xml_order_status
FROM DUAL;
XML_ORDER_STATUS
------------------------------------
<order_status>SHIPPED</order_status>
1he next exumpíe uses XMLSERIALIZE() wíth DOCUMENT to generute un XML document,
wíth the document returned ín u CLCß (churucter íurge ob¡ect):
SELECT XMLSERIALIZE(
DOCUMENT XMLType('<description>Description of a product</description>')
AS CLOB
)
AS xml_product_description
FROM DUAL;
XML_PRODUCT_DESCRIPTION
---------------------------------------------------
<description>Description of a product</description>
A Pl/SQl fxampIc That Writcs XMl Data tu a fiIc
ln thís sectíon, you'íí see u compíete lL/SQL exumpíe thut wrítes customer numes to un XML
lííe. lírst, you need to connect us u prívííeged user (lor exumpíe, the system user) und grunt
the CREATE ANY DIRECTORY prívííege to the store user:
CONNECT system/manager;
GRANT CREATE ANY DIRECTORY TO store;
Next, you need to connect us the store user und creute u dírectory ob¡ect:
CONNECT store/store_password;
CREATE DIRECTORY TEMP_FILES_DIR AS 'C:\temp_files';
You'íí uíso need to creute u dírectory numed temp_files ín the C purtítíon. (ll you're usíng
Línux or Lníx, you cun creute the dírectory on one ol your purtítíons und use un uppropríute
CREATE DIRECTORY commund wíth the correct puth. Aíso, muke sure you grunt wríte
permíssíons on the dírectory to the Crucíe user uccount you used to ínstuíí the dutubuse soltwure.)
Chupter l7: XML und the Crucíe Dutubuse
617
Next, you need to run the xml_examples.sql scrípt íocuted ín the SQL dírectory, us shown
here:
@ "E:\Oracle SQL book\sql_book\SQL\xml_examples.sql"
CAUTlON
Run oní, |hc xml_examples.sql ·críp| a| |hí· poín|. You ma, no|ícc
|hcrc í· a ·críp| namcd xml_schema.sql ín |hc SQL dírcc|or,. Do
no| run xml_schema.sql ,c|.
1he xml_examples.sql scrípt creutes two procedures, the one you'íí see ín thís sectíon ís
numed write_xml_data_to_file(), whích retríeves the customer numes und wrítes them to
un XML lííe. 1he write_xml_data_to_file() procedure ís delíned us loííows:
CREATE PROCEDURE write_xml_data_to_file(
p_directory VARCHAR2,
p_file_name VARCHAR2
) AS
v_file UTL_FILE.FILE_TYPE;
v_amount INTEGER := 32767;
v_xml_data XMLType;
v_char_buffer VARCHAR2(32767);
BEGIN
-- open the file for writing of text (up to v_amount
-- characters at a time)
v_file := UTL_FILE.FOPEN(p_directory, p_file_name, 'w', v_amount);
-- write the starting line to v_file
UTL_FILE.PUT_LINE(v_file, '<?xml version="1.0"?>');
-- retrieve the customers and store them in v_xml_data
SELECT
EXTRACT(
XMLELEMENT(
"customer_list",
XMLAGG(
XMLELEMENT("customer", first_name || ' ' || last_name)
ORDER BY last_name
)
),
'/customer_list'
)
AS xml_customers
INTO v_xml_data
FROM customers;
-- get the string value from v_xml_data and store it in v_char_buffer
v_char_buffer := v_xml_data.GETSTRINGVAL();
-- copy the characters from v_char_buffer to the file
UTL_FILE.PUT(v_file, v_char_buffer);
618
Crucíe Dutubuse ll SQL
-- flush any remaining data to the file
UTL_FILE.FFLUSH(v_file);
-- close the file
UTL_FILE.FCLOSE(v_file);
END write_xml_data_to_file;
/
1he loííowíng stutement cuíís write_xml_data_to_file():
CALL write_xml_data_to_file('TEMP_FILES_DIR', 'customers.xml');
Alter you run thís stutement, you'íí línd u lííe numed customers.xml ín C:\temp_files,
or whíchever dírectory you used when usíng the CREATE DIRECTORY commund eurííer. 1he
contents ol the customers.xml lííe ís us loííows:
<?xml version="1.0"?>
<customer_list><customer>Gail Black</customer><customer>Doreen Blue
</customer><customer>John Brown</customer><customer>Cynthia Green
</customer><customer>Steve White</customer></customer_list>
You cun modíly the write_xml_data_to_file() procedure to retríeve uny reíutíonuí
dutu lrom the dutubuse und wríte ít out to un XML lííe.
XMlQUfRY()
You use XMLQUERY() to construct XML or query XML. You puss un XQuery expressíon to
XMLQUERY(). XQuery ís u query íunguuge thut uííows you to construct und query XML.
XMLQUERY() returns the resuít ol evuíuutíng the XQuery expressíon.
1he loííowíng símpíe exumpíe íííustrutes the use ol XMLQUERY():
SELECT XMLQUERY(
'(1, 2 + 5, "d", 155 to 161, <A>text</A>)'
RETURNING CONTENT
)
AS xml_output
FROM DUAL;
XML_OUTPUT
--------------------------------------------
1 7 d 155 156 157 158 159 160 161<A>text</A>
Here ure some notes lor the exumpíe:
1he stríng pussed to XMLQUERY() ís the XQuery expressíon, thut ís, the XQuery
expressíon ís (1, 2 + 5, "d", 155 to 161, <A>text</A>). l ís un ínteger
ííteruí, 2 + 5 ís un uríthmetíc expressíon, d ís u stríng ííteruí, l55 to l6l ís u sequence
ol íntegers, und <A>text</A> ís un XML eíement.
Luch ol the ítems ín the XQuery ís evuíuuted ín turn. lor exumpíe, 2 + 5 ís evuíuuted, und
7 ís returned. Símííuríy, l55 to l6l ís evuíuuted und l55 l56 l57 l58 l59 l60 l6l ís
returned.
Chupter l7: XML und the Crucíe Dutubuse

RETURNING CONTENT meuns un XML lrugment ís returned. 1hís XML lrugment ís u
síngíe XML eíement wíth uny number ol ºchíídren,¨ whích cun themseíves be ol uny XML
eíement type, íncíudíng text eíements. 1he XML lrugment uíso conlorms to the extended
lnloset dutu modeí. lnloset ís u specílícutíon descríbíng un ubstruct dutu modeí ol un XML
document. You cun íeurn more ubout lnloset ut http://www.w3.org/1R/xmí-ínloset.
Let's expíore u more compíex exumpíe. 1he loííowíng stutement (contuíned ín the xml_
examples.sql scrípt) creutes u procedure numed create_xml_resources(), thís
procedure creutes XML stríngs lor products und product types. lt uses methods ín the lL/SQL
DBMS_XDB puckuge to deíete und creute XML resource lííes ín the Crucíe XML Dß Reposítory
(the XML Dß Reposítory ís u storuge ureu lor XML dutu wíthín the dutubuse):
CREATE PROCEDURE create_xml_resources AS
v_result BOOLEAN;
-- create string containing XML for products
v_products VARCHAR2(300):=
'<?xml version="1.0"?>' ||
'<products>' ||
'<product product_id="1" product_type_id="1" name="Modern Science"'
|| ' price="19.95"/>' ||
'<product product_id="2" product_type_id="1" name="Chemistry"' ||
' price="30"/>' ||
'<product product_id="3" product_type_id="2" name="Supernova"' ||
' price="25.99"/>' ||
'</products>';
-- create string containing XML for product types
v_product_types VARCHAR2(300):=
'<?xml version="1.0"?>' ||
'<product_types>' ||
'<product_type product_type_id="1" name="Book"/>' ||
'<product_type product_type_id="2" name="Video"/>' ||
'</product_types>';
BEGIN
-- delete any existing resource for products
DBMS_XDB.DELETERESOURCE('/public/products.xml',
DBMS_XDB.DELETE_RECURSIVE_FORCE);
-- create resource for products
v_result := DBMS_XDB.CREATERESOURCE('/public/products.xml',
v_products);
-- delete any existing resource for product types
DBMS_XDB.DELETERESOURCE('/public/product_types.xml',
DBMS_XDB.DELETE_RECURSIVE_FORCE);
-- create resource for product types
v_result := DBMS_XDB.CREATERESOURCE('/public/product_types.xml',
v_product_types);
END create_xml_resources;
/

Crucíe Dutubuse ll SQL
Here ure some notes lor create_xml_resources():
1he DBMS_XDB.DELETERESOURCE() procedure deíetes un XML resource lrom the
dutubuse. 1hís procedure ís cuííed by create_xml_resources() so thut you don't
huve to munuuííy remove the resources íl you run create_xml_resources() more
thun once.
1he DBMS_XDB.DELETE_RECURSIVE_FORCE constunt lorces the deíetíon ol the
resource, íncíudíng uny chííd ob¡ects.
1he DBMS_XDB.CREATERESOURCE() lunctíon creutes un XML resource ín the dutubuse
und returns u ßooíeun true/false vuíue índícutíng whether the operutíon wus successluí.
1he two cuíís to thís lunctíon creute resources lor the products und product types ín /
public, whích ís the ubsoíute puth to store the resources.
1he loííowíng stutement cuíís create_xml_resources():
CALL create_xml_resources();
1he loííowíng query uses XMLQUERY() to retríeve the products lrom the /public/
products.xml resource:
SELECT XMLQUERY(
'for $product in doc("/public/products.xml")/products/product
return <product name="{$product/@name}"/>'
RETURNING CONTENT
)
AS xml_products
FROM DUAL;
XML_PRODUCTS
-----------------------------------------
<product name="Modern Science"></product>
<product name="Chemistry"></product>
<product name="Supernova"></product>
1he XQuery expressíon ínsíde XMLQUERY() ín the prevíous exumpíe ís
for $product in doc("/public/products.xml")/products/product
return <product name="{$product/@name}"/>
Let's breuk down thís XQuery expressíon:
1he for íoop íterutes over the products ín /public/products.xml.
$product ís u bíndíng vuríubíe thut ís bound to the sequence ol products returned
by doc("/public/products.xml")/products/product, doc("/public/
products.xml") returns the products.xml document stored ín /public. \íth
euch íterutíon ol the íoop, $product ís set to euch product ín products.xml, one
ulter unother.
1he return purt ol the expressíon returns the product nume ín $product.
Chupter l7: XML und the Crucíe Dutubuse

1he next query retríeves the product types lrom the /public/product_types.xml
resource:
SELECT XMLQUERY(
'for $product_type in
doc("/public/product_types.xml")/product_types/product_type
return <product_type name="{$product_type/@name}"/>'
RETURNING CONTENT
)
AS xml_product_types
FROM DUAL;
XML_PRODUCT_TYPES
------------------------------------------
<product_type name="Book"></product_type>
<product_type name="Video"></product_type>
1he loííowíng query retríeves the products whose príce ís greuter thun 20, uíong wíth theír
product type:
SELECT XMLQUERY(
'for $product in doc("/public/products.xml")/products/product
let $product_type :=
doc("/public/product_types.xml")//product_type[@product_type_id =
$product/@product_type_id]/@name
where $product/@price > 20
order by $product/@product_id
return <product name="{$product/@name}"
product_type="{$product_type}"/>'
RETURNING CONTENT
)
AS xml_query_results
FROM DUAL;
XML_QUERY_RESULTS
---------------------------------------------------------
<product name="Chemistry" product_type="Book"></product>
<product name="Supernova" product_type="Video"></product>
Let's breuk down the XQuery expressíon ín thís exumpíe:
1wo bíndíng vuríubíes ure used: $product und $product_type. 1hese vuríubíes ure
used to store the products und product types.
1he let purt ol the expressíon sets $product_type to the product type retríeved lrom
$product. 1he expressíon on the ríght-hund síde ol the := perlorms u ¡oín usíng the
product_type_id vuíue stored ín $product_type und $product. 1he // meuns
retríeve uíí eíements.
1he where purt retríeves oníy products whose príce ís greuter thun 20.
1he order by purt orders the resuíts by the product lD (ín uscendíng order by deluuít).
622
Crucíe Dutubuse llg SQL
1he next exumpíe shows the use ol the loííowíng XQuery lunctíons:
count(), whích counts the number ol ob¡ects pussed to ít.
avg(), whích cuícuíutes the uveruge ol the numbers pussed to ít.
integer(), whích truncutes u number und returns the ínteger. 1he integer()
lunctíon ís ín the xs numespuce. (1he count() und avg() lunctíons ure ín the fn
numespuce, whích ís uutomutícuííy relerenced by the dutubuse, thereby uííowíng you
to omít thís numespuce when cuíííng these lunctíons.)
1he loííowíng exumpíe returns the product type nume, the number ol products ín euch
product type, und the uveruge príce ol the products ín euch product type (truncuted to un ínteger):
SELECT XMLQUERY(
'for $product_type in
doc("/public/product_types.xml")/product_types/product_type
let $product :=
doc("/public/products.xml")//product[@product_type_id =
$product_type/@product_type_id]
return
<product_type name="{$product_type/@name}"
num_products="{count($product)}"
average_price="{xs:integer(avg($product/@price))}"
/>'
RETURNING CONTENT
)
AS xml_query_results
FROM DUAL;
XML_QUERY_RESULTS
---------------------------------------------------------------
<product_type name="Book" num_products="2" average_price="24">
</product_type>
<product_type name="Video" num_products="1" average_price="25">
</product_type>
As you cun see lrom the resuíts, there ure two books und one vídeo.
NOTf
You can rcad morc abou| |unc|íon· a| h||p://vvv.vJ.org/TR/xqucr,-
opcra|or·. You can |índ morc ín|orma|íon on XMLQUERY() a| h||p://
vvv.·qíx.org.
Saving XMl in thc Databasc
ln thís sectíon, you'íí see how to store un XML document ín the dutubuse und retríeve ínlormutíon
lrom the stored XML.
Chupter l7: XML und the Crucíe Dutubuse
623
Thc fxampIc XMl fiIc
You'íí see the use ol u lííe numed purchase_order.xml, whích ís un XML lííe thut contuíns
u purchuse order. 1hís lííe ís contuíned ín the xml_files dírectory, whích ís creuted when you
extructed the Zíp lííe lor thís book. ll you wunt to loííow uíong wíth the exumpíes, you shouíd
copy the xml_files dírectory to the C purtítíon on your dutubuse server (íl you're usíng Línux
or Lníx, you cun copy the dírectory to one ol your purtítíons).
NOTf
í| ,ou cop, |hc xml_files dírcc|or, |o a íoca|íon dí||crcn| |rom C,
|hcn ,ou'íí nccd |o cdí| |hc xml_schema.sql ·críp| (,ou'íí ·cc |hí·
·críp| ·hor|í,).
1he contents ol the purchase_order.xml lííe ís us loííows:
<?xml version="1.0"?>
<purchase_order>
<customer_order_id>176</customer_order_id>
<order_date>2007-05-17</order_date>
<customer_name>Best Products 456 Inc.</customer_name>
<street>10 Any Street</street>
<city>Any City</city>
<state>CA</state>
<zip>94440</zip>
<phone_number>555-121-1234</phone_number>
<products>
<product>
<product_id>1</product_id>
<name>Supernova video</name>
<quantity>5</quantity>
</product>
<product>
<product_id>2</product_id>
<name>Oracle SQL book</name>
<quantity>4</quantity>
</product>
</products>
</purchase_order>
ln the loííowíng sectíons, you'íí see how to store thís XML lííe ín the dutubuse.
ln u reuí-woríd exumpíe, the purchuse order couíd be sent víu the lnternet to un onííne store,
whích wouíd then dísputch the requested ítems to the customer.
Crcating thc fxampIc XMl Schcma
l've províded un SQL*líus scrípt numed xml_schema.sql ín the SQL dírectory. 1he scrípt
creutes u user numed xml_user wíth u pussword ol xml_password, und ít creutes the ítems
used ín the rest ol thís chupter. Don't run thís scrípt yet.

Crucíe Dutubuse ll SQL
1he scrípt contuíns the loííowíng stutements thut creute un ob¡ect type numed t_product
(used to represent products), u nested tubíe type numed t_nested_table_product (used to
represent u nested tubíe ol products), und u tubíe numed purchase_order:
CREATE TYPE t_product AS OBJECT (
product_id INTEGER,
name VARCHAR2(15),
quantity INTEGER
);
/
CREATE TYPE t_nested_table_product AS TABLE OF t_product;
/
CREATE TABLE purchase_order (
purchase_order_id INTEGER CONSTRAINT purchase_order_pk PRIMARY KEY,
customer_order_id INTEGER,
order_date DATE,
customer_name VARCHAR2(25),
street VARCHAR2(15),
city VARCHAR2(15),
state VARCHAR2(2),
zip VARCHAR2(5),
phone_number VARCHAR2(12),
products t_nested_table_product,
xml_purchase_order XMLType
)
NESTED TABLE products
STORE AS nested_products;
Notíce thut the xml_purchase_order coíumn ís ol type XMLType, whích ís u buíít-ín
Crucíe dutubuse type thut uííows you to store XML dutu. ßy deluuít, un XMLType coíumn stores
the XML dutu us text ín u CLCß (churucter íurge ob¡ect).
1he xml_schema.sql scrípt uíso contuíns the loííowíng stutement thut creutes u dírectory
ob¡ect numed XML_FILES_DIR:
CREATE OR REPLACE DIRECTORY XML_FILES_DIR AS 'C:\xml_files';
You'íí need to modíly thís ííne íl you copíed the xml_files dírectory to u íocutíon díllerent
lrom C. ll you need to modíly thís ííne, go uheud und do ít now und then suve the scrípt.
1he loííowíng INSERT stutement (uíso contuíned ín the scrípt) udds u row to the purchase_
order tubíe:
INSERT INTO purchase_order (
purchase_order_id,
xml_purchase_order
) VALUES (
1,
XMLType(
BFILENAME('XML_FILES_DIR', 'purchase_order.xml'),
NLS_CHARSET_ID('AL32UTF8')
)
);
Chupter l7: XML und the Crucíe Dutubuse
62S
As you cun see, the XMLType() constructor uccepts two purumeters. 1he lírst purumeter ís
u BFILE, whích ís u poínter to un externuí lííe. 1he second purumeter ís the churucter set lor the
XML text ín the externuí lííe. ln the prevíous INSERT, the BFILE poínts to the purchase_
order.xml lííe, und the churucter set ís AL32L1l8, whích ís stundurd L1l-8 encodíng. \hen
the INSERT ís run, the XML lrom the purchase_order.xml lííe ís reud und then stored ín the
dutubuse us CLCß text ín the xml_purchase_order coíumn.
NOTf
Vhcn ,ou arc vor|íng ví|h X\í |ííc· vrí||cn ín íngíí·h, ,ou
·houíd |,pícaíí, u·c |hc AíJ2LTí8 charac|cr ·c|. You can |índ morc
ín|orma|íon abou| dí||crcn| charac|cr ·c|· ín |hc Crucíe Dutubuse
Cíobuíízutíon Support Cuíde pubíí·hcd b, Cracíc Corpora|íon.
You muy huve notíced the customer_order_id, order_date, customer_name,
street, city, state, zip, phone_number, und products coíumns ín the purchase_
order tubíe ure empty. 1he dutu lor these coíumns cun be extructed lrom the XML stored ín the
xml_purchase_order coíumn. Luter ín thís chupter, you'íí see u lL/SQL procedure thut reuds
the XML und sets the other coíumns uccordíngíy.
Co uheud und run the xml_schema.sql scrípt us u prívííeged user (such us the system
user):
CONNECT system/manager
@ "E:\Oracle SQL book\sql_book\SQL\xml_schema.sql"
Alter the scrípt compíetes, you wííí be íogged ín us xml_user.
Rctricving lnfurmatiun frum thc fxampIc XMl Schcma
ln thís sectíon, you'íí see how to retríeve ínlormutíon lrom the xml_user schemu.
1he loííowíng exumpíe retríeves the row lrom the purchase_order tubíe:
SET LONG 1000
SET PAGESIZE 500
SELECT purchase_order_id, xml_purchase_order
FROM purchase_order;
PURCHASE_ORDER_ID
-----------------
XML_PURCHASE_ORDER
-------------------------------------------------------
1
<?xml version="1.0"?>
<purchase_order>
<customer_order_id>176</customer_order_id>
<order_date>2007-05-17</order_date>
<customer_name>Best Products 456 Inc.</customer_name>
<street>10 Any Street</street>
<city>Any City</city>
<state>CA</state>
<zip>94440</zip>
<phone_number>555-121-1234</phone_number>
<products>

Crucíe Dutubuse ll SQL
<product>
<product_id>1</product_id>
<name>Supernova video</name>
<quantity>5</quantity>
</product>
<product>
<product_id>2</product_id>
<name>Oracle SQL book</name>
<quantity>4</quantity>
</product>
</products>
</purchase_order>
1he next query extructs the customer_order_id, order_date, customer_name, und
phone_number lrom the XML stored ín the xml_purchase_order coíumn usíng the
EXTRACT() lunctíon:
SELECT
EXTRACT(xml_purchase_order,
'/purchase_order/customer_order_id') cust_order_id,
EXTRACT(xml_purchase_order, '/purchase_order/order_date') order_date,
EXTRACT(xml_purchase_order, '/purchase_order/customer_name') cust_name,
EXTRACT(xml_purchase_order, '/purchase_order/phone_number') phone_number
FROM purchase_order
WHERE purchase_order_id = 1;
CUST_ORDER_ID
------------------------------------------
ORDER_DATE
-----------------------------------
CUST_NAME
-----------------------------------------------------
PHONE_NUMBER
-----------------------------------------
<customer_order_id>176</customer_order_id>
<order_date>2007-05-17</order_date>
<customer_name>Best Products 456 Inc.</customer_name>
<phone_number>555-121-1234</phone_number>
1he EXTRACT() lunctíon returns the vuíues us XMLType ob¡ects.
You cun use the EXTRACTVALUE() lunctíon to get the vuíues us stríngs. lor exumpíe, the
loííowíng query extructs the sume vuíues us stríngs usíng the EXTRACTVALUE() lunctíon:
SELECT
EXTRACTVALUE(xml_purchase_order,
'/purchase_order/customer_order_id') cust_order_id,
EXTRACTVALUE(xml_purchase_order,
'/purchase_order/order_date') order_date,
EXTRACTVALUE(xml_purchase_order,
'/purchase_order/customer_name') cust_name,
EXTRACTVALUE(xml_purchase_order,
Chupter l7: XML und the Crucíe Dutubuse

'/purchase_order/phone_number') phone_number
FROM purchase_order
WHERE purchase_order_id = 1;
CUST_ORDER_ID
----------------------
ORDER_DATE
----------------------
CUST_NAME
----------------------
PHONE_NUMBER
----------------------
176
2007-05-17
Best Products 456 Inc.
555-121-1234
1he next query extructs und converts order_date to u DATE usíng the TO_DATE()
lunctíon, notíce thut the lormut lor the dute us stored ín the XML ís suppííed usíng the second
purumeter to TO_DATE() und thut TO_DATE() returns the dute ín the deluuít dute lormut used
by the dutubuse (DD-MON-YY):
SELECT
TO_DATE(
EXTRACTVALUE(xml_purchase_order, '/purchase_order/order_date'),
'YYYY-MM-DD'
) AS ord_date
FROM purchase_order
WHERE purchase_order_id = 1;
ORD_DATE
---------
17-MAY-07
1he loííowíng query retríeves uíí the products lrom xml_purchase_order us XML usíng
EXTRACT(), notíce the use ol // to get uíí the products:
SELECT
EXTRACT(xml_purchase_order, '/purchase_order//products') xml_products
FROM purchase_order
WHERE purchase_order_id = 1;
XML_PRODUCTS
--------------------------------
<products>
<product>
<product_id>1</product_id>
<name>Supernova video</name>
<quantity>5</quantity>
</product>
<product>

Crucíe Dutubuse ll SQL
<product_id>2</product_id>
<name>Oracle SQL book</name>
<quantity>4</quantity>
</product>
</products>
1he next query retríeves product r2 lrom xml_purchase_order, notíce product[2]
returns product r2:
SELECT
EXTRACT(
xml_purchase_order,
'/purchase_order/products/product[2]'
) xml_product
FROM purchase_order
WHERE purchase_order_id = 1;
XML_PRODUCT
---------------------------------
<product>
<product_id>2</product_id>
<product>Oracle SQL book</name>
<quantity>4</quantity>
</product>
1he loííowíng query retríeves the ºSupernovu vídeo¨ product lrom xml_purchase_order,
notíce thut the nume ol the product to retríeve ís píuced ínsíde squure bruckets:
SELECT
EXTRACT(
xml_purchase_order,
'/purchase_order/products/product[name="Supernova video"]'
) xml_product
FROM purchase_order
WHERE purchase_order_id = 1;
XML_PRODUCT
------------------------------
<product>
<product_id>1</product_id>
<name>Supernova video</name>
<quantity>5</quantity>
</product>
You use the EXISTSNODE() lunctíon to check íl un XML eíement exísts. EXISTSNODE()
returns l íl the eíement exísts, otherwíse, ít returns 0. lor exumpíe, the loííowíng query returns
the stríng 'Exists' becuuse product rl exísts:
SELECT 'Exists' AS "EXISTS"
FROM purchase_order
WHERE purchase_order_id = 1
AND EXISTSNODE(
Chupter l7: XML und the Crucíe Dutubuse

xml_purchase_order,
'/purchase_order/products/product[product_id=1]'
) = 1;
EXISTS
------
Exists
1he next query returns no rows becuuse product r3 does not exíst:
SELECT 'Exists'
FROM purchase_order
WHERE purchase_order_id = 1
AND EXISTSNODE(
xml_purchase_order,
'/purchase_order/products/product[product_id=3]'
) = 1;
no rows selected
1he loííowíng query retríeves the products us u vurruy ol XMLType ob¡ects usíng the
XMLSEQUENCE() lunctíon, notíce the use ol product.* to retríeve uíí the products und
theír XML eíements:
SELECT product.*
FROM TABLE(
SELECT
XMLSEQUENCE(EXTRACT(xml_purchase_order, '/purchase_order//product'))
FROM purchase_order
WHERE purchase_order_id = 1
) product;
COLUMN_VALUE
------------------------------
<product>
<product_id>1</product_id>
<name>Supernova video</name>
<quantity>5</quantity>
</product>
<product>
<product_id>2</product_id>
<name>Oracle SQL book</name>
<quantity>4</quantity>
</product>
1he next query retríeves the product_id, name, und quantity lor the products us stríngs
usíng the EXTRACTVALUE() lunctíon:
SELECT
EXTRACTVALUE(product.COLUMN_VALUE, '/product/product_id') AS product_id,
EXTRACTVALUE(product.COLUMN_VALUE, '/product/name') AS name,
630
Crucíe Dutubuse ll SQL
EXTRACTVALUE(product.COLUMN_VALUE, '/product/quantity') AS quantity
FROM TABLE(
SELECT
XMLSEQUENCE(EXTRACT(xml_purchase_order, '/purchase_order//product'))
FROM purchase_order
WHERE purchase_order_id = 1
) product;
PRODUCT_ID
--------------
PRODUCT
---------------
QUANTITY
---------------
1
Supernova video
5
2
Oracle SQL book
4
Updating lnfurmatiun in thc fxampIc XMl Schcma
1he customer_order_id, order_date, customer_name, street, city, state, zip,
phone_number, und products coíumns ín the purchase_order tubíe ure empty. 1he dutu
lor these coíumns cun be extructed lrom the XML stored ín the xml_purchase_order coíumn.
ln thís sectíon, you'íí u lL/SQL procedure numed update_purchase_order() thut reuds the
XML und sets the other coíumns uccordíngíy.
1he most compíex uspect ol update_purchase_order() ís the process ol reudíng
the products lrom the XML und storíng them ín the products nested tubíe coíumn ol the
purchase_order tubíe. ln thís procedure, u cursor ís used to reud the products lrom the XML,
then the XML ís converted to stríngs usíng EXTRACTVALUE(), und the stríngs ure stored ín u
nested tubíe.
1he loííowíng stutement (contuíned ín the xml_schema.sql scrípt) creutes the update_
purchase_order() procedure:
CREATE PROCEDURE update_purchase_order(
p_purchase_order_id IN purchase_order.purchase_order_id%TYPE
) AS
v_count INTEGER := 1;
-- declare a nested table to store products
v_nested_table_products t_nested_table_product :=
t_nested_table_product();
-- declare a type to represent a product record
TYPE t_product_record IS RECORD (
product_id INTEGER,
name VARCHAR2(15),
quantity INTEGER
);
Chupter l7: XML und the Crucíe Dutubuse

-- declare a REF CURSOR type to point to product records
TYPE t_product_cursor IS REF CURSOR RETURN t_product_record;
-- declare a cursor
v_product_cursor t_product_cursor;
-- declare a variable to store a product record
v_product t_product_record;
BEGIN
-- open v_product_cursor to read the product_id, name, and quantity for
-- each product stored in the XML of the xml_purchase_order column
-- in the purchase_order table
OPEN v_product_cursor FOR
SELECT
EXTRACTVALUE(product.COLUMN_VALUE, '/product/product_id')
AS product_id,
EXTRACTVALUE(product.COLUMN_VALUE, '/product/name') AS name,
EXTRACTVALUE(product.COLUMN_VALUE, '/product/quantity') AS quantity
FROM TABLE(
SELECT
XMLSEQUENCE(EXTRACT(xml_purchase_order, '/purchase_order//product'))
FROM purchase_order
WHERE purchase_order_id = p_purchase_order_id
) product;
-- loop over the contents of v_product_cursor
LOOP
-- fetch the product records from v_product_cursor and exit when there
-- are no more records found
FETCH v_product_cursor INTO v_product;
EXIT WHEN v_product_cursor%NOTFOUND;
-- extend v_nested_table_products so that a product can be stored in it
v_nested_table_products.EXTEND;
-- create a new product and store it in v_nested_table_products
v_nested_table_products(v_count) :=
t_product(v_product.product_id, v_product.name, v_product.quantity);
-- display the new product stored in v_nested_table_products
DBMS_OUTPUT.PUT_LINE('product_id = ' ||
v_nested_table_products(v_count).product_id);
DBMS_OUTPUT.PUT_LINE('name = ' ||
v_nested_table_products(v_count).name);
DBMS_OUTPUT.PUT_LINE('quantity = ' ||
v_nested_table_products(v_count).quantity);
-- increment v_count ready for the next iteration of the loop
v_count := v_count + 1;
END LOOP;
-- close v_product_cursor

Crucíe Dutubuse ll SQL
CLOSE v_product_cursor;
-- update the purchase_order table using the values extracted from the
-- XML stored in the xml_purchase_order column (the products nested
-- table is set to v_nested_table_products already populated by the
-- previous loop)
UPDATE purchase_order
SET
customer_order_id =
EXTRACTVALUE(xml_purchase_order,
'/purchase_order/customer_order_id'),
order_date =
TO_DATE(EXTRACTVALUE(xml_purchase_order,
'/purchase_order/order_date'), 'YYYY-MM-DD'),
customer_name =
EXTRACTVALUE(xml_purchase_order, '/purchase_order/customer_name'),
street =
EXTRACTVALUE(xml_purchase_order, '/purchase_order/street'),
city =
EXTRACTVALUE(xml_purchase_order, '/purchase_order/city'),
state =
EXTRACTVALUE(xml_purchase_order, '/purchase_order/state'),
zip =
EXTRACTVALUE(xml_purchase_order, '/purchase_order/zip'),
phone_number =
EXTRACTVALUE(xml_purchase_order, '/purchase_order/phone_number'),
products = v_nested_table_products
WHERE purchase_order_id = p_purchase_order_id;
-- commit the transaction
COMMIT;
END update_purchase_order;
/
1he loííowíng exumpíe sets the server output on und cuíís update_purchase_order() to
updute purchuse order rl:
SET SERVEROUTPUT ON
CALL update_purchase_order(1);
product_id = 1
name = Supernova video
quantity = 5
product_id = 2
name = Oracle SQL book
quantity = 4
1he loííowíng query retríeves the coíumns lrom purchuse order rl:
SELECT purchase_order_id, customer_order_id, order_date, customer_name,
street, city, state, zip, phone_number, products
FROM purchase_order
Chupter l7: XML und the Crucíe Dutubuse

WHERE purchase_order_id = 1;
PURCHASE_ORDER_ID CUSTOMER_ORDER_ID ORDER_DAT CUSTOMER_NAME
----------------- ----------------- --------- ----------------------
STREET CITY ST ZIP PHONE_NUMBER
--------------- --------------- -- ----- ------------
PRODUCTS(PRODUCT_ID, NAME, QUANTITY)
------------------------------------
1 176 17-MAY-07 Best Products 456 Inc.
10 Any Street Any City CA 94440 555-121-1234
T_NESTED_TABLE_PRODUCT(
T_PRODUCT(1, 'Supernova video', 5),
T_PRODUCT(2, 'Oracle SQL book', 4)
)
1he products nested tubíe contuíns the sume dutu us stored ín the XML product eíements ín
the xml_purchase_order coíumn. l've udded some ííne breuks to sepurute the products ín the
exumpíe's resuíts to muke them eusíer to see.

ln thís chupter, you huve íeurned
How to generute XML lrom reíutíonuí dutu.
How to suve XML ín the dutubuse und subsequentíy reud thut XML to updute reíutíonuí
coíumns.
1hís short chupter hus bureíy scrutched the surluce ol the rích XML lunctíonuííty uvuííubíe ín
the Crucíe dutubuse. You cun línd more ínlormutíon ín the Cracíc X\í Dcvcíopcr'· Kí| und the
Cracíc X\í Dß Dcvcíopcr'· Cuídc, both pubííshed by Crucíe Corporutíon.
Apurt lrom the línuí uppendíx, thís ís the end ol thís book. l hope you've lound the book
ínlormutíve und useluí, und thut l've heíd your ínterest!
This page intentionally left blank

Crucíe Dutu 1ypes
635
636
Crucíe Dutubuse llg SQL
hís uppendíx contuíns two tubíes documentíng the dutu types thut ure uvuííubíe ín
Crucíe SQL und thut muy be used to delíne coíumns ín u tubíe, uíong wíth the
uddítíonuí types supported by Crucíe lL/SQL.
OracIc SQl Typcs
1ubíe A-l shows the Crucíe SQL types.

Typc Dcscriptiun
CHAR[(length [BYTE | CHAR])]
l
líxed-íength churucter dutu ol length bytes or churucters und pudded wíth truíííng
spuces. Muxímum íength ís 2,000 bytes.
VARCHAR2(length [BYTE | CHAR])
l
Vuríubíe-íength churucter dutu ol up to length bytes or churucters. Muxímum
íength ís 4,000 bytes.
NCHAR[(length)] líxed-íength Lnícode churucter dutu ol length churucters. Number ol bytes stored
ís 2 muítípííed by length lor ALl6L1ll6 encodíng und 3 muítípííed by length
lor L1l8 encodíng. Muxímum íength ís 2,000 bytes.
NVARCHAR2(length) Vuríubíe-íength Lnícode churucter dutu ol length churucters. Number ol bytes
stored ís 2 muítípííed by length lor ALl6L1ll6 encodíng und 3 muítípííed by
length lor L1l8 encodíng. Muxímum íength ís 4,000 bytes.
BINARY_FLOAT lntroduced ín Crucíe Dutubuse l0g, stores u síngíe-precísíon 32-bít líoutíng-poínt
number. Cperutíons ínvoívíng BINARY_FLOAT ure typícuííy perlormed luster
thun operutíons usíng NUMBER vuíues. BINARY_FLOAT requíres 5 bytes ol
storuge spuce.
BINARY_DOUBLE lntroduced ín Crucíe Dutubuse l0g, stores u doubíe-precísíon 64-bít líoutíng-poínt
number. Cperutíons ínvoívíng BINARY_DOUBLE ure typícuííy perlormed luster
thun operutíons usíng NUMBER vuíues. BINARY_DOUBLE requíres 9 bytes ol
storuge spuce.
NUMBER(precision, scale) und
NUMERIC(precision, scale)
Vuríubíe-íength number, precision ís the muxímum number ol dígíts (íelt und
ríght ol u decímuí poínt, íl used) thut muy be used lor the number. 1he muxímum
precísíon supported ís 38, scale ís the muxímum number ol dígíts to the ríght
ol u decímuí poínt (íl used). ll neíther precision nor scale ís specílíed, then u
number wíth up to u precísíon und scuíe ol 38 dígíts muy be suppííed (meuníng you
cun suppíy u number wíth up to 38 dígíts, und uny ol those 38 dígíts muy be ríght
or íelt ol the decímuí poínt).
DEC und DECIMAL Subtype ol NUMBER. A líxed-poínt decímuí number wíth up to 38 dígíts ol decímuí
precísíon.
DOUBLE PRECISION und FLOAT Subtype ol NUMBER. A líoutíng-poínt number wíth up to 38 dígíts ol precísíon.
REAL
Subtype ol NUMBER. A líoutíng-poínt number wíth up to l8 dígíts ol precísíon.
INT, INTEGER, und SMALLINT Subtype ol NUMBER. An ínteger wíth up to 38 dígíts ol decímuí precísíon.
DATE
Dute und tíme wíth the century, uíí lour dígíts ol yeur, month, duy, hour (ín 24-
hour lormut), mínute, und second. Muy be used to store u dute und tíme between
}unuury l, 47l2 ß.C. und December 3l, 47l2 A.D. Deluuít lormut ís specílíed by
the NLS_DATE_FORMAT dutubuse purumeter (lor exumpíe: DD-MON-RR).
INTERVAL YEAR[(years_precision)]
TO MONTH
1íme íntervuí meusured ín yeurs und months, years_precision specílíes the
precísíon lor the yeurs, whích muy be un ínteger lrom 0 to 9 (deluuít ís 2). Cun be
used to represent u posítíve or negutíve tíme íntervuí.
TABlf A-1 Cracíc SÇí T,pc·
Appendíx: Crucíe Dutu 1ypes
637
Typc Dcscriptiun
INTERVAL DAY[(days_precision)] TO
SECOND[(seconds_precision)]
1íme íntervuí meusured ín duys und seconds, days_precision specílíes the
precísíon lor the duys, whích ís un ínteger lrom 0 to 9 (deluuít ís 2), seconds_
precision specílíes the precísíon lor the lructíonuí purt ol the seconds, whích ís
un ínteger lrom 0 to 9 (deluuít ís 6). Cun be used to represent u posítíve or negutíve
tíme íntervuí.
TIMESTAMP[(seconds_precision)] Dute und tíme wíth the century, uíí lour dígíts ol yeur, month, duy, hour (ín 24-hour
lormut), mínute, und second, seconds_precision specílíes the number ol dígíts
lor the lructíonuí purt ol the seconds, whích cun be un ínteger lrom 0 to 9 (deluuít
ís 6). Deluuít lormut ís specílíed by the NLS_TIMESTAMP_FORMAT dutubuse
purumeter.
TIMESTAMP[(seconds_precision)] WITH
TIME ZONE
Lxtends TIMESTAMP to store u tíme zone. 1he tíme zone cun be un ollset lrom
L1C, such us -8:0, or u regíon nume, such us US/Pacific or PST. Deluuít
lormut ís specílíed by the NLS_TIMESTAMP_TZ_FORMAT dutubuse purumeter.
TIMESTAMP[(seconds_precision)] WITH
LOCAL TIME ZONE
Lxtends TIMESTAMP to convert u suppííed dutetíme to the íocuí tíme zone set lor
the dutubuse. 1he process ol conversíon ís known us normaíí2íng the dutetíme.
Deluuít lormut ís specílíed by the NLS_TIMESTAMP_FORMAT dutubuse purumeter.
CLOB Vuríubíe-íength síngíe-byte churucter dutu ol up to l28 terubytes.
NCLOB Vuríubíe-íength Lnícode nutíonuí churucter set dutu ol up to l28 terubytes.
BLOB Vuríubíe-íength bínury dutu ol up to l28 terubytes.
BFILE loínter to un externuí lííe. 1he externuí lííe ís not stored ín the dutubuse.
LONG Vuríubíe-íength churucter dutu ol up to 2 gígubytes. Superseded by the CLOB und
NCLOB types, but supported lor buckwurds computíbíííty.
RAW(length) Vuríubíe-íength bínury dutu ol up to length bytes. Muxímum íength ís 2,000
bytes. Superseded by the BLOB type, but supported lor buckwurds computíbíííty.
LONG RAW Vuríubíe-íength bínury dutu ol up to 2 gígubytes. Superseded by the BLOB type but
supported lor buckwurds computíbíííty.
ROWID Hexudecímuí stríng used to represent u row uddress.
UROWID[(length)] Hexudecímuí stríng representíng the íogícuí uddress ol u row ol un índex-orgunízed
tubíe, length specílíes the number ol bytes. Muxímum íength ís 4,000 bytes (uíso
the deluuít íength íl none ís specílíed).
REF object_type Relerence to un ob¡ect type. Símííur to u poínter ín the C++ progrummíng íunguuge.
VARRAY Vuríubíe-íength urruy. 1hís ís u composíte type und stores un ordered set ol
eíements.
NESTED TABLE Nested tubíe. 1hís ís u composíte type und stores un unordered set ol eíements.
XMLType Stores XML dutu.
User defined object type You cun delíne your own ob¡ect type und creute ob¡ects ol thut type. See Chupter
l2 lor detuíís.
l
1he BYTE und CHAR keywords work oníy wíth Crucíe Dutubuse 9í und ubove. ll neíther BYTE nor CHAR ís specílíed, the
deluuít ís BYTE.
TABlf A-1 Cracíc SÇí T,pc· (contínued)
638
Crucíe Dutubuse llg SQL
Typc Dcscriptiun
BOOLEAN
ßooíeun vuíue (TRUE, FALSE, or NULL).
BINARY_INTEGER
lnteger between 2
3l
(2,l47,483,648) und 2
3l
(2,l47,483,648).
NATURAL
Subtype ol BINARY_INTEGER. A non-negutíve ínteger.
NATURALN
Subtype ol BINARY_INTEGER. A non-negutíve ínteger (cunnot
be NULL).
POSITIVE
Subtype ol BINARY_INTEGER. A posítíve ínteger.
POSITIVEN
Subtype ol BINARY_INTEGER. A posítíve ínteger (cunnot be NULL).
SIGNTYPE
Subtype ol BINARY_INTEGER. An ínteger set to l, 0, or l.
PLS_INTEGER
lnteger between 2
3l
(2,l47,483,648) und 2
3l
(2,l47,483,648).
ldentícuí to BINARY_INTEGER.
SIMPLE_INTEGER
New lor Crucíe Dutubuse llg, SIMPLE_INTEGER ís u subtype ol
BINARY_INTEGER. SIMPLE_INTEGER cun store the sume runge ol
vuíues us BINARY_INTEGER, except lor NULL vuíues, whích cunnot
be stored ín u SIMPLE_INTEGER. Aíso, uríthmetíc overlíow does not
cuuse un error when usíng SIMPLE_INTEGER vuíues, ínsteud, the
resuít ís símpíy truncuted.
STRING
Sume us VARCHAR2.
RECORD
Composíte ol u group ol other types. Símííur to u structure ín the C++
progrummíng íunguuge.
REF CURSOR
loínter to u set ol rows.
TABlf A-2 Cracíc íí/SÇí T,pc·
OracIc Pl/SQl Typcs
Crucíe lL/SQL supports uíí the types prevíousíy shown ín 1ubíe A-l, píus the loííowíng uddítíonuí
Crucíe lL/SQL specílíc types shown ín 1ubíe A-2.
SymbuIs
(mínus), 3l
r (pound), l07
% (percent), 404l
%1YlL, 342, 346
( ) (purentheses), 34, l68
* (usterísk)
ín uríthmetíc, 3l
coíumn retríevuí, 29
customers tubíe, l5
metuchuructers, ll0
 (lorwurd síush)
ín uríthmetíc, 3l
edítíng SQL stutements, 6566
lL/SQL stutements, 34l
SQL dírectory puths, l0
\ (buckwurd síush), l0
:new uttríbute, 524525
, (semícoíon), 6, 34l
: (questíon murk), 564
!= (not equuí), 3839
@ filename, 67
_ (underscore), 404l
]] (concutenutíon operutor), 34
+ (píus)
ín uríthmetíc, 3l
outer ¡oíns, 5l55
< (íess thun)
compuríng ob¡ect vuíues, 393
non-equí¡oíns, 50
vuíue compuríson, 3839
<= (íess thun or equuí)
compuríng ob¡ect vuíues, 393
non-equí¡oíns, 50
vuíue compuríson, 3839
<> (not equuí)
ANSl nested tubíe support,
464465
compuríng ob¡ect vuíues,
392394
vuíue compuríson, 3839
= (equuí)
ANSl nested tubíe support,
464465
compuríng ob¡ect vuíues,
392393
equí¡oíns, 50
vuíue compuríson, 3839
> (greuter thun)
compuríng ob¡ect vuíues,
393394
non-equí¡oíns, 50
vuíue compuríson, 3839
>= (greuter thun or equuí)
compuríng ob¡ect vuíues, 393
non-equí¡oíns, 50
vuíue compuríson, 3839
" (quotes), 34, 254
A
AßS( ), 98, l00
ACCLl1, 7879, 808l
ACCLSS_lN1C_NLLL, 354
AClD (utomíc, consístent, ísoíuted
und durubíe) trunsuctíon
propertíes, 265266
ACCS( ), 98
ADDM (Automutíc Dutubuse
Díugnostíc Monítor), 60060l
lndcx
ADD_MCN1HS( ), l42l43
udvunced queríes.  queríes,
udvunced
uggregute lunctíons
delíned, 90
groupíng rows, l20l27
muítípíe ín llVC1, 247248
RL1LRNlNC, 255256
wíth RCLLLl, 207
types ol, ll7l20
uígoríthms, LCß dutu encryptíon, 526
uííuses
coíumns, 3435
tubíe, 4748
ALL, 3839, l75
AL1LR
delíned, 3
lNDLX, 324
SLQLLNCL, 320
1AßLL, 302306
Amerícun Nutíonuí Stundurds
lnstítute (ANSl), 464472
unuíytíc lunctíons
delíned, 2l62l7
llRS1 und LAS1 lunctíons, 233
hypothetícuí runk und
dístríbutíon lunctíons, 235
ínverse percentííe lunctíons,
224225
LAC( ) und LLAD( ), 232233
ííneur regressíon lunctíons,
233235
runkíng lunctíons, 2l7224
reportíng lunctíons, 230232
wíndow lunctíons, 225230
639

Crucíe Dutubuse ll SQL
AND, 43, 238
ANSl (Amerícun Nutíonuí Stundurds
lnstítute), 47, 464472
ANY
uccessíng uíí ceíís usíng,
238239
muítípíe-row subqueríes, l74
vuíue compuríson, 3839
A¦llLND¦, 6566
AllLND( )
dutu to CLCßs, 506507
delíned, 483, 485
uríthmetíc, 3l34
urruys, ussocíutíve, 428
ussocíutíve, 462
urruys, vurruy.  vurruys
ASCll( ), 9l92
ASlN( ), 98
ussocíutíve urruys, 428, 462
usterísk (*).  * (usterísk)
A1AN( ), 98
A1AN2( ), 99
utomíc trunsuctíons, 265
uttríbutes
:new, 524525
OracleDataSource,
540542
XMLA11RlßL1LS( ), 608
uudítíng
overvíew, 295297
usíng tríggers, 369374
uuto-commít mode, 552553
Automutíc Dutubuse Díugnostíc
Monítor (ADDM), 60060l
uutomutícuííy generuted SQL
stutements, 86
uveruges
centered, 228229
movíng, 227228
AVC( ), ll7ll8

ß-tree índexes, 32l322
buckwurd síush (\), l0
buse tubíes, 325
BasicExample1.java, 556562
BasicExample2.java, 565567
BasicExample3.java, 575577
ßL1\LLN
ceíí runge uccess usíng, 238
compuríng ob¡ect vuíues, 393
delíned, 39
non-equí¡oíns, 505l
overvíew, 4243
ßllLLs (bínury llLL types)
copyíng dutu lrom ínto CLCßs
und ßLCßs, 5l7520
delíned, 477478
llLLCLCSL( ) und
llLLCLCSLALL( ), 489
llLLLXlS1S( ), 490
llLLCL1NAML( ), 490
llLLlSClLN( ), 49049l
llLLClLN( ), 49l
LCADßLCßlRCMllLL( ), 497
LCADCLCßlRCMllLL( ),
497498
LCADlRCMllLL( ), 496
usíng ín SQL, 48l482
bínury LCßs (ßLCßs).  ßLCßs
(bínury LCßs)
ßlNARY_DCLßLL, l3, 2325
ßlNARY_lLCA1, l3, 2325
bínd vuríubíes, 58859l
bínds, 539
bít vectors, 2l2
ßl1AND( ), 99
bítmup índexes, 32l, 324325
ßLCßs (bínury LCßs)
compressíon, 529
copyíng dutu lrom ßllLL ínto,
5l7520
copyíng dutu lrom lííe ínto,
5l25l5
copyíng dutu lrom ínto lííes,
5l55l7
delíned, 477478
encryptíon, 526528
LCADßLCßlRCMllLL( ), 497
reudíng dutu lrom, 504506
usíng ín SQL, 47848l
bíock structure, 340342
body, ob¡ect type, 38l382
body, puckuge, 365367
brunch eíímínutíon, 20l202
ßRLAK CN, 8385
ß1l1LL, 8283
buckets, 223

CACHL ín sequences, 3l9
cuchíng LCß dutu, 526
cuícuíutíons, numeríc, 98l02
cuícuíutíons wíth MCDLL. 
MCDLL
cuíííng lL/SQL lunctíons, 364,
367368
cuíííng lL/SQL procedures, 360
36l, 367368
CARDlNALl1Y( ), 469
Curtesíun products, 4849
CASL expressíons
udvunced queríes, l93l96
vs. muítípíe queríes, 583
usíng wíth CRCLllNC( ),
2092l0
CASL_NC1_lCLND, 354
CAS1( ), l08l09, 443444
CLlL( ), 99, l00
ceíís
uccessíng uíí usíng ANY und lS
ANY, 238239
lCR íoops, 24024l
posítíonuí und symboííc
notutíon, 237238
runge uccess usíng ßL1\LLN
und AND, 238
updutíng exístíng, 243244
centered uveruge, 228229
centruí píun tubíes, 593
century lormuttíng, l33
C¦HANCL¦, 6566
chungíng tubíe contents.  tubíe
contents, chungíng
CHAR( ), l3
churucter lunctíons
delíned, 90
types ol, 9098
churucter LCßs (CLCßs).  CLCßs
(churucter LCßs)
churucters
vuríubíe delínítíon, 76
XML lííes wrítten ín Lngíísh, 625
CHLCK, 306, 307
CHLCK Cl1lCN, 306, 329
chííd nodes, l97
chííd tubíes, 257258
CHR( ), 9l92
lndex

chunks ol dutu, 492
cíusses
computíbíe Crucíe dutubuse
types, 568
ob¡ect types us, 380
orucíe.¡dbc puckuge, 573
CLASSlA1H envíronment vuríubíe,
534535
CLL¦AR¦, 707l
CLLAR, 73
CLCßs (churucter LCßs)
uppendíng dutu to, 506507
compuríng dutu, 507508
compressíon, 529
copyíng dutu lrom, 508509
copyíng dutu lrom ßllLL ínto,
5l7520
copyíng dutu lrom lííe ínto,
5l25l5
copyíng dutu lrom ínto lííes,
5l55l7
delíned, 477478
encryptíon, 526528
erusíng dutu lrom, 5l0
ímpíícít conversíon, 523524
LCADCLCßlRCMllLL( ),
497498
reudíng dutu lrom, 504506
seurchíng dutu, 5l05ll
temporury, 5095l0
usíng ín SQL, 47848l
wrítíng to, 506
CLCSL( ), 483, 485
cíosed operutíons, 23
cíosíng
cursors, 347
}DßC ob¡ects, 554556
ResultSet ob¡ect, 546547
Codd, L. l., 2, 3
CCLLLC1( ), 47l472
CCLLLC1lCN_lS_NLLL, 354
coííectíons, 427473
ANSl nested tubíe support,
464472
ussocíutíve urruys, 462
compuríng nested tubíe contents
wíth mup method, 440442
convertíng types wíth CAS1( ),
443444
CCLN1( ), 44845l
delíníng coíumn wíth type, 430
DLLL1L( ), 45l452
eíement type sízíng, 463
LXlS1S( ), 452453
LX1LND( ), 453
llRS1( ), 454
generutíng XML lor, 607608
íncreusíng eíements ín
vurruy, 463
ínlormutíon retríevuí, 43l433
íntroductíon, 428429
LAS1( ), 454455
modílyíng eíements, 438440
muítííeveí, 45846l
nested tubíe's storuge tubíe
tubíespuce, 463464
NLX1( ), 455456
Crucíe dutubuse l0g
enhuncements, 46l462
ín lL/SQL, 444448
popuíutíng wíth eíements,
434435
lRlCR( ), 456457
retríevíng eíements lrom,
435436
summury, 473
1AßLL( ), 436438
1RlM( ), 457458
types, 429430
vurruys ín temporury tubíes, 463
XMLACC( ), 6096l2
coíumns
uccessíng usíng MCDLL cíuuse,
236237
uddíng/modílyíng/removíng,
303306
uííuses, 3435
ín uríthmetíc, 3234
chungíng tubíe contents. Scc
tubíe contents, chungíng
combíníng output, 35
comments, 3l33l4
construínt ínlormutíon retríevuí,
3ll3l2
decíuríng vuríubíes to store
vuíues, 346
delíned, 2
delíníng wíth coííectíon type, 430
encryptíng LCß dutu, 528
CRCLllNC( ), 2092ll
ínlormutíon retríevuí on índexes,
323324
¡oíns wíth luííy quuíílíed
relerences, 582
LCNC und LCNC RA\ types,
52l522
muítípíe-coíumn
subqueríes, l75
ob¡ects, 383386
pívotíng on muítípíe, 246247
píun tubíe, 593
reudíng vuíues lrom
ResultSet ob¡ect, 544546
retríevíng uíí, 29
ín RCLLLl cíuuse, 205207
SQL*líus, cíeuríng lormuts, 73
SQL*líus, lormuttíng, 7072
substítutíng numes usíng
vuríubíes, 7677
LNllVC1, 248249
usíng muítípíe ín group, l22
combíníng lunctíons, 98
commund ííne SQL*líus sturtup, 6
communds
coíumn lormuttíng, 7072
delíned vuríubíes, 7779
edítíng SQL stutements, 6566
HLLl, 8586
suvíng/retríevíng/runníng lííes,
6670
SL1 LlNLSlZL, 73
SL1 lACLSlZL, 7273
símpíe reportíng, 7985
comments
ín tubíes, 3l33l4
XML, 6l4
CCMMl1
uuto-commít mode, 552553
delíned, 4
trunsuctíons, 262263
Communíca|íon· o| |hc AC\, 2
CCMlARL( )
dutu ín two CLCßs, 507508
delíned, 483, 486487
compuríng vuíues
delíned, 3739
tubíe ob¡ects, 392394
compíex víews, 332333
compressíon, LCß, 529
CCMlL1L, 8385

Crucíe Dutubuse ll SQL
computer conlígurutíon lor runníng
SQL usíng }uvu, 533535
computíng subtotuís, 8385
concutenutíon
combíníng coíumn output, 35
CCNCA1( ), 9l92
XMLCCNCA1( ), 6l3
concutenutíon operutor (]]), 34
concurrent trunsuctíons, 266
condítíonuí íogíc, 342343
condítíons ín híerurchícuí queríes,
202203
condítíons, trígger, 369
conlíguríng computer lor runníng
SQL usíng }uvu, 533535
CCNNLC1 ßY, l98
connectívíty, dutubuse, 537542
consístent trunsuctíons, 265
construíned cursors, 34535l
construínts
creutíng víews wíth, 329330
enlorcíng, 257258
gettíng ínlormutíon on víew,
33l332
tubíe, 3063l2
constructors
coíumn ob¡ects, 384
ob¡ect tubíes, 386
user-delíned, 4l8422
CCN1LN1
pursíng XML expressíons, 6l3
XMLSLRlALlZL( ), 6l6
contents, chungíng tubíe.  tubíe
contents, chungíng
conversíon lunctíons, 90, l02l09
convertíng dutetíme, l3ll39, l50
CCNVLR11CßLCß( ), 483
CCNVLR11CCLCß( ), 483
Coordínuted Lníversuí 1íme (L1C),
l46l47
CClY( )
copyíng dutu lrom CLCßs,
508509
delíned, 483
LCß methods, 487
copyíng LCß dutu
uppendíng dutu to CLCßs,
506507
lrom ßllLL ínto CLCßs und
ßLCßs, 5l7520
lrom CLCßs und ßLCßs ínto
lííes, 5l55l7
lrom lííe ínto CLCßs und
ßLCßs, 5l25l5
copyíng rows, 254
correíuted subqueríes, l68,
l75l79
CCS( ), 99
CCSH( ), 99
cost-bused optímízutíon, 59l598
CCLN1( ), ll7ll9, 44845l
CRLA1L, 3, lll2
CRLA1L lRCCLDLRL, 2526
CRLA1L SYNCNNYM, 287288
CRLA1L LSLR, 276277
CRLA1L1LMlCRARY( ), 483, 488
cross ¡oíns, 6l
CLßL
delíned, 207208
vs. CRCLllNC SL1S, 2l2, 588
CRCLllNC( ) wíth, 2l02ll
usíng wíth unuíytíc lunctíons,
22l223
CLML_DlS1( ), 2l8, 223
cumuíutíve sums, 225227
CLRRLN1_DA1L( ), l49
CLRRLN1_1lMLS1AMl, l55l56
CLRRLN1V( ), 239240
currval, 3l7, 376
CLRSCR_ALRLADY_ClLN, 354
cursors
lCR íoops und, 349350
ClLN-lCR stutement, 35035l
overvíew, 345346
product_cursor.sqí exumpíe,
348349
progrummíng steps, 346348
unconstruíned, 352353
customer_id, l4, l7l8
customers tubíe, l4l5

Dutu Controí Lunguuge (DCL)
stutements, 4
Dutu Delínítíon Lunguuge (DDL)
stutements
delíned, 3, ll20
runníng SQL usíng }uvu, 553
dutu, LCß
uppendíng to CLCß, 506507
CLCßs und ßLCßs ín SQL,
47848l
compuríng ín CLCßs, 507508
compressíon, 529
copyíng.  copyíng LCß dutu
delíned, 478
encryptíon, 525528
erusíng lrom CLCß, 5l0
reudíng lrom CLCßs und
ßLCßs, 504506
removíng dupíícute, 529
seurchíng ín CLCß, 5l05ll
Dutu Munípuíutíon Lunguuge (DML)
stutements.  DML (Dutu
Munípuíutíon Lunguuge)
stutements
dutu sources, 539542
dutu types.  types
dutubuse munugement systems, 23
dutubuse ob¡ects, 379426
coíumn, 383386
compuríng vuíues, 392394
creutíng types, 38l382
delete_product(), 40040l
display_product(),
396397
generuíízed ínvocutíon,
423425
generutíng XML lor, 607
get_product(), 398399
get_product_ref(), 400
get_products(), 395396
insert_product(), 397
íntroductíon, 380
lS Cl( ), 4084l2
}DßC Statement, 542543
íurge.  LCßs (íurge ob¡ects)
NC1 lNS1AN1lAßLL types,
4l64l8
ClDs und relerences, 390392
OracleDataSource, 540542
overrídíng methods, 422423
ín lL/SQL, 394395
product_lifecycle(),
40l402
product_lifecycle2(),
402403
ResultSet, 543547
subtype ín píuce ol supertype,
405408
summury, 425426
SYS_1YlLlD( ), 4l6
tubíes, 386389
1RLA1( ), 4l24l6
lndex

type ínherítunce, 403405
update_product(), 399
update_product_
price(), 398
user-delíned constructors,
4l8422
usíng DLSCRlßL to get type
ínlormutíon, 382383
wruppers, 55l552
dutubuse tubíe ínlormutíon retríevuí,
276l
uíí coíumns, 29
uríthmetíc, 3l34
Curtesíun products, 4849
coíumn uííuses, 3435
concutenutíon, 35
dístínct row díspíuy, 37
¡oín condítíons und types, 50
¡oíns usíng SQL/92 syntux,
566l
non-equí¡oíns, 505l
nuíí vuíues, 3537
operutor precedence, 44
outer ¡oíns, 5l55
row ídentílíers, 30
row numbers, 303l
SLLLC1 stutements usíng
muítípíe tubíes, 4950
SLLLC1 stutements usíng síngíe
tubíe, 2829
SLLLC1 stutements usíng two
tubíes, 4547
seíl ¡oíns, 5556
sortíng rows, 4445
SQL operutors, 3943
summury, 6l
tubíe uííuses, 4748
tubíes und coíumns ín tubíes,
302303
vuíue compuríson, 3739
\HLRL, 29
dutubuses
common types, l2l3
creutíng users, lll2
íntegríty, 256258
openíng connectíon, 537542
tubíes.  tubíes
tíme zones, l47l49
trunsuctíons, 262269, 552553
DA1L, l3
dute uríthmetíc, 3l32
dute ol bírth (dob), l5
dutetíme, l30l66
convertíng, l3ll39
deluuít lormut, l39l40
lunctíons, l42l46
storíng/retríevíng, l30l3l
summury, l66
tíme íntervuís, l59l65
tíme zones, l46l50
tímestump lunctíons, l54l59
tímestumps, l50l54
two-dígít yeurs, l40l42
duys
dutetíme lunctíons, l43l45
deluuít lormut, l30
lormut purumeters, l34
lN1LRVAL DAY 1C SLCCND,
l62l64
DCL (Dutu Controí Lunguuge)
stutements, 4
DD, l30
DDL (Dutu Delínítíon Lunguuge)
stutements
delíned, 3, ll20
runníng SQL usíng }uvu, 553
decíurutíons, cursor, 346
DLCCDL( ), l9ll93
deluuít dutetíme lormut, l39l40
deluuít edítors, 69
deluuít íockíng, 266267
deluuít roíes, 294
deluuít vuíues, 258259, 306
delerred construínts, 3l0
DLllNL, 7778
delíned vuríubíes
delíned, 74, 7779
ín scrípts, 8l
delínítíon churucters, 76
delínítíons, víew, 33033l
DLL, 6566
DLLL1L( ), 449, 45l452
DLLL1L
delíned, 3
}DßC, 548
removíng rows, 2223, 256
stutements contuíníng
subqueríes, l80l8l
delete_product(), 395,
40040l
DLNSL RANK( ), 2l7223
DLRLl( ), 39l392
DLSCRlßL
uddíng rows, 20
coííectíon ínlormutíon retríevuí,
43l433
ob¡ect type ínlormutíon,
382383
row ídentílíers, 30
tubíe ínlormutíon retríevuí, 302
víewíng tubíe structure, 6465
description, l7
dímensíons, current vuíues, 239240
dírectory ob¡ects
usíng ßllLLs, 48l
wuííets, 525526
dírectory puths, l0
dírty reuds, 268
dísubííng construínts, 309
dísubííng tríggers, 374
díspíuyíng dístínct rows, 37
display_product(), 394,
396397
DlS1lNC1
delíned, 37
vs. LXlS1S, 587
dístríbutíon, 235
DML (Dutu Munípuíutíon Lunguuge)
stutements
chungíng tubíe contents. 
tubíe contents, chungíng
delíned, 3
perlormíng wíth víews, 328329
tríggers, 369374
dob (dute ol bírth), l5
DCCLMLN1, 6l3, 6l6
drívers, }DßC
regísteríng, 537
types ol, 535536
DRCl, 3
DRCl 1AßLL, 86
DRCl LSLR, 278
droppíng
coíumns, 306
construínts, 309
índexes, 324
puckuges, 368
lL/SQL lunctíons, 365
procedures, 362
roíes, 295
sequences, 320
tubíes, 3l4
tríggers, 374
víews, 334
dual tubíe, 32
dupíícute LCß dutu, 529

Crucíe Dutubuse ll SQL
dupíícute rows, 2l52l6
dupíícute vuíues, 356
DLl_VAL_CN_lNDLX, 354, 356
durubíe trunsuctíons, 265

LD¦l1¦, 67
edítíng SQL stutements, 7, 6566
eíements
uddíng to coííectíon, 453
countíng, 44845l
deíetíng, 45l452
exístíng, 452453
gettíng lírst, 454
gettíng íust, 454455
íncreusíng ín vurruy, 463
modílyíng ín coííectíons,
438440
popuíutíng coííectíons,
434435
removíng lrom coííectíon,
457458
retríevíng lrom coííectíons,
435436
returníng next, 455456
returníng príor, 456457
type sízíng, 463
XML, 605608
LLSL, 342343
LLSll, 342343
employees tubíe, l8l9
enubííng construínts, 3093l0
enubííng tríggers, 374
encryptíon, LCß, 525528
LND ll, 342343
endíng trunsuctíons, 263
envíronment vuríubíes, 533535
equuí (=).  = (equuí)
equí¡oíns
delíned, 46
SLLLC1 stutements usíng
muítípíe tubíes, 4950
SQL/92 syntux, 5758
eru lormuttíng purumeters, l35
LRASL( )
dutu lrom CLCß, 5l0
delíned, 483
LCß methods, 488489
errors
exceptíons.  exceptíons
síngíe-row subqueríes, l72l73
víewíng ín procedures, 362
exceptíons
DLl_VAL_CN_lNDLX, 356
lNVALlD_NLMßLR, 356357
C1HLRS, 357
lL/SQL, 353355
runníng SQL usíng }uvu,
553554
thrown by methods. 
methods
ZLRC_DlVlDL, 355356
executíon píuns, 562, 59l598
LXlS1S( ), 449, 452453
LXlS1S
vs. lN, 586587
correíuted subqueríes, l76l79
vs. DlS1lNC1, 587
LXl1, 25, 86
LXl( ), 99
LXlLAlN lLAN, 594
expressíons
uríthmetíc, 3l34
CASL.  CASL expressíons
reguíur expressíon lunctíons,
l09ll6
usíng wíth lunctíons, 98
XMLlARSL( ), 6l3
LX1LND( ), 449, 453
Lxtensíbíe Murkup Lunguuge (XML).
 XML (Lxtensíbíe Murkup
Lunguuge)
LX1RAC1( ), l55l57

lL1CH, 347
llLLCLCSL( ), 483, 489
llLLCLCSLALL( ), 483, 489
llLLLXlS1S( ), 483, 490
llLLCL1NAML( ), 483, 490
llLLlSClLN( ), 483, 49049l
llLLClLN( ), 483, 49l
lííes
ßllLLs.  ßllLLs (bínury
llLL types)
copyíng dutu lrom CLCßs und
ßLCßs ínto, 5l55l7
copyíng dutu lrom ínto CLCßs
und ßLCßs, 5l25l5
suvíng/retríevíng/runníng, 6670
lííteríng rows
wíth HAVlNC, l25l26
wíth \HLRL, 58058l
\HLRL vs. HAVlNC,
584585
líndíng tríggers, 37l372
llRS1, 2l6, 233
llRS1( ), 449, 454
first_name, l4
llRS1_VALLL( ), 229230
líushbuck dutu urchíves, 334337
líushbucks, query, 270273
lLCCR( ), 99, l00l0l
looters, 8283
lCR íoops
ceíí uccess usíng, 24024l
cursors und, 349350
delíned, 343, 344345
loreígn keys
uddíng, 308309
construínts enlorcement,
257258
delíned, 306
lorests
XMLACC( ), 6096l2
XMLlCRLS1( ), 608609
lCR¦MA1¦ format, 707l
lormuts, dutetíme
conversíon, l3ll39
dute, l30
deluuít, l39l40
two-dígít yeur ínterpretutíon,
l40l42
lormuttíng híerurchícuí query resuíts,
l99200
lorwurd síush ().   (lorwurd
síush)
lrugments, XML, 6l2
lRLL1LMlCRARY( ), 484, 492
lRCM, l7ll72
lRCM_1Z( ), l55, l57
luíí outer ¡oíns, 60
luííy quuíílíed coíumn relerences, 582
lunctíon-bused índexes, 322323
lunctíons, 89l27
uggregute, ll7l20
unuíytíc.  unuíytíc lunctíons
ANSl nested tubíe support,
469472
cuíííng ín puckuges, 367368
wíth CAS1( ), 443444
churucter, 9098
lndex

conversíon, l02l09
CLRRLN1V( ), 239240
dutetíme, l42l46
dutetíme conversíon,
l3ll39
DLCCDL( ), l9ll93
DLRLl( ), 39l392
get_product(), 398399
get_product_ref(), 400
get_products(), 395396
CRCLl_lD( ), 2l52l6
CRCLllNC( ), 2092ll
groupíng rows, l20l27
CRCLllNC_lD( ), 2l22l4
lS Cl( ), 4084l2
numeríc, 98l02
lL/SQL, 363365
RLl( ), 390392
reguíur expressíon, l09ll6
síngíe-row, 90
storíng returned vuíues wíth
bínd vuríubíes, 590
summury, l27
SYS_1YlLlD( ), 4l6
1AßLL( ), 436438
tímestump, l54l59
1RANSLA1L( ), l90l9l
1RLA1( ), 4l24l6
usíng ob¡ects ín lL/SQL,
394395
XMLACC( ), 6096l2
XMLA11RlßL1LS( ), 608
XMLCCLA11VAL( ), 6l2
XMLCCMMLN1( ), 6l4
XMLCCNCA1( ), 6l3
XMLLLLMLN1( ), 605608
XMLlCRLS1( ), 608609
XMLlARSL( ), 6l3
XMLll( ), 6l4
XMLQLLRY( ), 6l8622
XMLSLQLLNCL( ), 6l5
XMLSLRlALlZL( ), 6l6

generuíízed ínvocutíon, 423425
CL1 filename, 67
get methods, 540542, 545546
CL1CHLNKSlZL( ), 484, 492
getConnection(), 537538
CL1LLNC1H( ), 484, 493
get_product(), 394, 398399
get_product_ref(), 395, 400
get_products(), 394,
395396
CL1_S1CRACL_LlMl1( ),
484, 492
CM1 (Creenwích Meun 1íme),
l46l47
CRAN1, 4
gruntíng prívííeges
ob¡ect, 282
roíes, 290
to users, 278279
usíng wíth roíes, 293
gruntíng roíes, 29029l
greuter thun (>).  > (greuter thun)
greuter thun or equuí (>=).  >=
(greuter thun or equuí)
Creenwích Meun 1íme (CM1),
l46l47
CRCLl ßY, l20l27
CRCLl ßY, extended cíuuses
CLßL, 207208
delíned, 203204
CRCLl ßY coíumn use, 2l4
CRCLl_lD( ), 2l52l6
CRCLllNC( ), 2092ll
CRCLllNC SL1S, 2ll2l2
CRCLllNC_lD( ), 2l22l4
muítípíe coíumn use, 2l4
RCLLLl, 205207
CRCLl_lD( ), 2l52l6
CRCLllNC( ), 2092ll
groupíng lunctíons
groupíng rows, l20l27
types ol, ll7l20
CRCLllNC SL1S
vs. CLßL, 588
delíned, 2ll2l2
usíng wíth unuíytíc lunctíons,
22l223
CRCLllNC_lD( ), 2l22l4

hundííng dutubuse nuíí vuíues,
550552
hundííng exceptíons.  exceptíons
hundííng nuíí und míssíng vuíues,
24l243
hundííng numbers, 549550
HAVlNC
groupíng rows, l25l27
subqueríes ín, l70l7l
vs. \HLRL, 584585
heuders, 8283
HLA¦DlNC¦ heading, 707l
heíp, SQL*líus, 8586
híerurchícuí queríes
delíned, l96l99
eíímínutíng nodes und brunches,
20l202
lormuttíng resuíts, l99200
íncíudíng other condítíons,
202203
S1AR1 \l1H subquery,
20020l
sturtíng ut node other thun
root, 200
truversíng upwurd through
tree, 20l
híerurchíes ol ob¡ect types,
403405
hínts, pussíng to optímízer,
598600
hour lormuttíng purumeters, l34
hypothetícuí lunctíons, 2l6, 235

lD
CRCLl_lD( ), 2l52l6
CRCLllNC_lD( ), 2l22l4
SYS_1YlLlD( ), 4l6
ídentícuí SQL stutements, 588589
ídentílíers, row, 30
ll, 342343
lCNCRL NAV, 243
ímpíícít conversíon, 523524
ímportíng }DßC puckuges, 536537
lN
ANSl nested tubíe support,
465466
compuríng ob¡ect vuíues,
392394
delíned, 39
vs. LXlS1S, 586587
vs. LXlS1S ín correíuted
subqueríes, l78
muítípíe-row subqueríes,
l73l74
outer ¡oín íímítutíons, 54

Crucíe Dutubuse llg SQL
procedure purumeters, 358
usíng, 4l42
lN CL1, 358
íncíusíve runge, 42
índexes
uddíng to tubíes, 584
DLl_VAL_CN_lNDLX
exceptíons, 356
overvíew, 320325
summury, 337
INF (ínlíníty), 24
ínlormutíon retríevuí
lrom CLCßs, 479480
coííectíons, 43l433
coíumn comments,
3l33l4
construínts, 3l03l2
índexes, 323324
puckuges, 368
lL/SQL lunctíons, 365
procedures, 36l362
sequences, 3l63l7
tubíe comments, 3l3
tubíes. Scc dutubuse tubíe
ínlormutíon retríevuí
tríggers, 372374
usíng DLSCRlßL to get ob¡ect
type ínlormutíon, 382383
víews, 330332
XML schemu, 625630
ínherítunce, type, 403405
lNl1CAl( ), 9l93
ínííne víews, l7ll72
ínner ¡oíns, 50, 5660
lNSLR1
uddíng rows, 202l,
252254
delíned, 3
usíng }DßC, 547548
usíng víew, 328329
insert_product(), 394, 397
lNS1R( ), 9l, 93, 484
LCß methods, 493494
seurchíng dutu ín CLCß,
5l05ll
ínstructíons, processíng, 6l4
lN1LCLR, l3
íntegríty, dutubuse, 256258
ínterluces, 573
ínterrow cuícuíutíons wíth MCDLL.
Scc MCDLL
lN1LRSLC1, l84, l88l89
lN1LRVAL DAY 1C SLCCND,
l62l64
lN1LRVAL YLAR 1C MCN1H,
l59l62
íntervuís, tíme, l59l65
lNVALlD_CLRSCR, 354
lNVALlD_NLMßLR, 354,
356357
ínverse percentííe lunctíons, 2l6,
224225
ínvocutíon, generuíízed, 423425
lS A SL1, 47047l
lS ANY, 238239
lS LMl1Y, 47l
lS lNllNl1L, 39
lS NAN, 39
lS NLLL, 39
lS Cl( ), 4084l2
lS lRLSLN1, 24l242
ísoíuted trunsuctíons, 265
ísoíutíon íeveís, trunsuctíon,
267269
lSClLN( ), 484, 494495
lS1LMlCRARY( ), 484, 495496

}uvu
runníng SQL usíng. Scc SQL
(Structured Query Lunguuge),
runníng usíng }uvu
SQL Deveíoper computíbíííty, 8
types, 544545
}AVA_HCML envíronment
vuríubíe, 534
}DßC. Scc aí·o SQL (Structured
Query Lunguuge), runníng usíng
}uvu
cíosíng ob¡ects, 554556
ímportíng puckuges, 536537
Crucíe drívers, 535536
Crucíe extensíons, 567568
regísteríng drívers, 537
Statement ob¡ect, 542543
¡oíns
condítíons und types, 50
lN (con|ínucd) executíon píuns ínvoívíng tubíe,
596597
MLRCL, 26l
non-equí¡oíns, 505l
outer ¡oíns, 5l55
quuíílíed coíumn
relerences, 582
SLLLC1 stutements usíng
muítípíe tubíes, 4950
SLLLC1 stutements usíng two
tubíes, 4547
seíl ¡oíns, 5556
tubíe ¡oíns vs. muítípíe queríes,
58l582
usíng SQL/92 syntux, 566l
}LS¦1llY¦, 707l

KLLl NAV, 243
keys
ussocíutíve urruys, 462
prímury und loreígn, 257258

LAC( ), 2l6, 232233
íurge ob¡ects (LCßs). Scc LCßs (íurge
ob¡ects)
LAS1, 2l6, 233
LAS1( ), 449, 454455
LAS1_DAY( ), l43l44
last_name, l5
LAS1_VALLL( ), 229230
LD_LlßRARY_lA1H envíronment
vuríubíe, 535
LLAD( ), 2l6, 232233
íeul nodes, l97
íelt outer ¡oíns, 5253, 59
íength, l3
LLNC1H( ), 9l, 94
íess thun (<). Scc < (íess thun)
íess thun or equuí (<=). Scc <= (íess
thun or equuí)
LLVLL pseudo coíumn, l98l99
LlKL
compuríng ob¡ect vuíues, 393
delíned, 39, 404l
lndex

LlMl1( ), 449
ííne síze settíng, 73
ííneur regressíon lunctíons, 2l6,
233235
Línux, CRACLL_HCML
envíronment vuríubíe, 533534
L¦lS1¦, 6566
íístíng bínd vuríubíes, 590
LN( ), 99
LCADßLCßlRCMllLL( ),
484, 497
LCADCLCßlRCMllLL( ), 484,
497498
LCADlRCMllLL( ), 484, 496
LCßMAXSlZL, 484
LCßs (íurge ob¡ects)
AllLND( ), 485
uppendíng dutu to CLCß,
506507
CLCSL( ), 485
CCMlARL( ), 486487
compuríng dutu ín CLCßs,
507508
CClY( ), 487
copyíng dutu lrom ßllLL ínto
CLCßs und ßLCßs, 5l7520
copyíng dutu lrom CLCßs,
508509
copyíng dutu lrom CLCßs und
ßLCßs ínto lííes, 5l55l7
copyíng dutu lrom lííe ínto
CLCßs und ßLCßs, 5l25l5
CRLA1L1LMlCRARY( ), 488
LRASL( ), 488489
erusíng CLCß dutu, 5l0
exumpíe lííes, 476477
llLLCLCSL( ) und
llLLCLCSLALL( ), 489
llLLLXlS1S( ), 490
llLLCL1NAML( ), 490
llLLlSClLN( ), 49049l
llLLClLN( ), 49l
lRLL1LMlCRARY( ), 492
CL1CHLNKSlZL( ), 492
CL1LLNC1H( ), 493
CL1_S1CRACL_LlMl1( ), 492
lNS1R( ), 493494
íntroductíon, 476
lSClLN( ), 494495
lS1LMlCRARY( ), 495496
LCADßLCßlRCMllLL( ), 497
LCADCLCßlRCMllLL( ),
497498
LCADlRCMllLL( ), 496
LCNC und LCNC RA\ types,
52l522
ClLN( ), 498499
Crucíe dutubuse l0g
enhuncements, 523525
Crucíe dutubuse llg
enhuncements, 525529
ín lL/SQL, 482484
RLAD( ), 499500
reudíng dutu lrom CLCßs und
ßLCßs, 504506
retríevíng íocutor,
503504
seurchíng CLCß dutu,
5l05ll
ín SQL, 478482
SLßS1R( ), 50050l
summury, 529530
tubíes contuíníng, 478
temporury CLCßs, 5095l0
1RlM( ), 50l502
types, 477478
\Rl1L( ), 502
\Rl1LAllLND( ), 503
wrítíng to CLCß, 506
XMLSLRlALlZL( ), 6l6
íocuí tíme zones, l53l54, l59
LCCAL1lMLS1AMl, l55l56
íocutors, LCß, 478, 503504
íocks, trunsuctíon, 266267
LCC( ), 99
íogíc, condítíonuí, 342343
íogícuí operutors, 43
íogícuí unít ol work, 262
LCClN_DLNlLD, 354
LCNC RA\ types, 52l522
LCNC types, 52l522
íookíng up, 539
íoops
ceíí uccess usíng lCR,
24024l
cursors und, 349350
lL/SQL, 343345
LC\LR( ), 9l, 9495
íower bounds, lCR íoops,
344345
LlAD( ), 9l, 95
L1RlM( ), 9l, 95

\acbc|h (Shukespeure), 477
mup method, 440442
MAX( ), ll7, ll9
MLMßLR Cl, 469470
MLRCL, 259262
metuchuructers
lerí-ínlíuenced, ll2
reguíur expressíons, l09ll2
method overíoudíng, 420
method overrídíng, 422423
methods
AllLND( ), 485
CLCSL( ), 485
CCMlARL( ), 486487
CClY( ), 487
CCLN1( ), 44845l
CRLA1L1LMlCRARY( ), 488
DLLL1L( ), 45l452
LRASL( ), 488489
LXlS1S( ), 452453
LX1LND( ), 453
llLLCLCSL( ) und
llLLCLCSLALL( ), 489
llLLLXlS1S( ), 490
llLLCL1NAML( ), 490
llLLlSClLN( ), 49049l
llLLClLN( ), 49l
llRS1( ), 454
lRLL1LMlCRARY( ), 492
generuíízed ínvocutíon,
423425
CL1CHLNKSlZL( ), 492
getConnection(), 537538
CL1LLNC1H( ), 493
CL1_S1CRACL_LlMl1( ), 492
lNS1R( ), 493494
lSClLN( ), 494495
lS1LMlCRARY( ), 495496
LAS1( ), 454455
LCADßLCßlRCMllLL( ), 497
LCADCLCßlRCMllLL( ),
497498
LCADlRCMllLL( ), 496
NLX1( ), 455456
ClLN( ), 498499
lRlCR( ), 456457
RLAD( ), 499500
SLßS1R( ), 50050l
1RlM( ), 457458, 50l502

Crucíe Dutubuse llg SQL
\Rl1L( ), 502
\Rl1LAllLND( ), 503
MlN( ), ll7, ll9
mínus (), 3l
MlNLS, l84, l88
mínute lormuttíng purumeters, l34
míssíng vuíues, hundííng, 24l243
míxed notutíon, 36l
MCD( ), 99, l0l
MCDLL
uíí ceíís uccess usíng ANY und
lS ANY, 238239
ceíí uccess usíng lCR íoop,
24024l
ceíí runge uccess usíng
ßL1\LLN und AND, 238
current dímensíon vuíues usíng
CLRRLN1V( ), 239240
delíned, 236237
nuíí und míssíng vuíues
hundííng, 24l243
posítíonuí und symboííc
notutíon, 237238
updutíng exístíng ceíís, 243244
modes, 358
modílyíng eíements, 438440
MCN, l30
months
dutetíme lunctíons, l42l44
deluuít lormut, l30
lormuttíng purumeters, l33l34
lN1LRVAL YLAR 1C MCN1H,
l59l62
MCN1HS_ßL1\LLN( ), l43l44
movíng uveruge, 227228
muítííeveí coííectíons, 45846l
muítípíe uggregute lunctíons,
247248
muítípíe-coíumn subqueríes, l68, l75
muítípíe queríes
vs. CASL expressíons, 583
vs. tubíe ¡oíns, 58l582
muítípíe-row subqueríes, l68,
l73l75
muítípíe set operutors, l88l89
MLL1lSL1, 467469

name, l5, l7
numed notutíon, 36l
numes, tíme zone, l49
NAN (not u number), 24
nutíve muchíne code generutíon, 377
NCLCßs (Nutíonuí Churucter
Set LCßs)
compressíon, 529
delíned, 477478
encryptíon, 526528
ímpíícít conversíon, 523524
LCADCLCßlRCMllLL( ),
497498
nested subqueríes, l68, l79l80
nested tubíes
ANSl support, 464472
compuríng contents wíth mup
method, 440442
convertíng wíth CAS1( ),
443444
delíned, 428
ínlormutíon retríevuí, 432433
munípuíutíng, 446448
modílyíng eíements, 439440
muítííeveí coííectíons, 45846l
popuíutíng wíth eíements,
434435
retríevíng eíements lrom, 436
storuge tubíe tubíespuce,
463464
types, 429430
usíng 1AßLL( ) wíth, 438
NLX1( ), 449, 455456
NLX1_DAY( ), l43l45
nextval, 3l73l9, 376
NLS_DA1L_lCRMA1, l39l40
NCCACHL, 3l9
NC_DA1A_lCLND, 354
nodes
delíned, l97
eíímínutíng, 20l202
other thun root, 200
non-equí¡oíns, 505l
non-ídentícuí SQL stutements, 588
nonrepeutubíe reuds, 268
normuíízed tíme zones, l53l54
NC1
delíned, 40, 43
vs. NC1 LXlS1S ín correíuted
subqueríes, l78
not u number (NAN), 24
not equuí (!=), 3839
not equuí (<>). Scc <> (not equuí)
NC1 LXlS1S, l76l79
NC1 lN, 465466
NC1 lNS1AN1lAßLL types,
4l64l8
NC1 NLLL, 306, 307308
notutíon
cuíííng procedures, 36036l
posítíonuí und symboííc,
237238
NC1_LCCCLD_CN, 354
N1lLL( ), 2l8, 223224
nuíí vuíues
controíííng runkíng, 2l9
dutubuse tubíe ínlormutíon
retríevuí, 3537
hundííng, 24l243,
550552
NC1 lN und, 42
specílyíng lor coíumns, 253
NLLLS llRS1, 2l9
NLLLS LAS1, 2l9
NLMßLR( ), l3
NLMßLR, 23
numbers
hundííng, 549550
rows, 303l
numeríc coíumns, 305
numeríc lunctíons, 90, 98l02
NLM1CDSlN1LRVAL( ), l64l65
NLM1CYMlN1LRVAL( ), l65
NVL( ), 36, 9l, 96
NVL2( ), 9l, 96

ob¡ect ídentílíers (ClDs), 390392
ob¡ect prívííeges
delíned, 28l287
gruntíng to roíes, 292293
revokíng, 288
synonyms, 287288
ob¡ects, dutubuse. Scc dutubuse
ob¡ects
CCl (Crucíe Cuíí lnterluce)
drívers, 536
ollsets, tíme zone, l49
ClDs (ob¡ect ídentílíers),
390392
CN, 5657
CNLY, 4l04ll
ClLN( ), 484, 498499
ClLN-lCR, 35035l
openíng cursors, 346
operunds, 3l
methods (con|ínucd)
lndex

operutors
ANSl nested tubíe support,
46447l
uríthmetíc, 3l34
combíníng set operutors,
l88l90
compuríng ob¡ect vuíues,
392394
correíuted subqueríes, l76
¡oíns.  ¡oíns
íogícuí, 43
muítípíe-row subqueríes, l73
precedence, 44
set operutors, l84l88
síngíe-row subqueríes, l69l70
SQL, 3943
vuíue compuríson, 3739
optímízers
hínts, 598600
query costs compuríson,
59l598
CR, 43, 55, 6566
Crucíe
connectíng to dutubuse wíth
dutu source, 539542
}DßC.  }DßC
two-dígít yeur ínterpretutíon,
l40l42
types, 544545, 635638
XML und.  XML (Lxtensíbíe
Murkup Lunguuge)
Crucíe Cuíí lnterluce (CCl)
drívers, 536
Crucíe dutubuse l0
ANSl nested tubíe support,
464472
ussocíutíve urruys, 462
coííectíons enhuncements,
46l462
cost-bused optímízutíon, 59l
eíement type sízíng, 463
íncreusíng eíements ín
vurruy, 463
LCß enhuncements, 523525
nested tubíe's storuge tubíe
tubíespuce, 463464
vurruys ín temporury tubíes, 463
Crucíe dutubuse ll
generuíízed ínvocutíon leuture,
423425
LCß enhuncements, 525529
new lL/SQL leutures, 374377
Crucíe Lnterpríse Munuger
Díugnostícs luck, 600
Crucíe íntroductíon, l26
ßlNARY_lLCA1 und ßlNARY_
DCLßLL types, 2325
DDL stutements used to creute
store schemu, ll20
lL/SQL, 2526
quíttíng SQL*líus, 25
reíutíonuí dutubuses, 23
rows, uddíng/modílyíng/
removíng, 2023
SQL, 34
SQL Deveíoper, 7l0
SQL*líus, 47
store schemu, l0ll
summury, 26
CRACLL_HCML envíronment
vuríubíe, 533534
oracle.jdbc puckuge, 57l575
oracle.sql puckuge, 56857l
CRDLR ßY, 4445, l72l73
C1HLRS exceptíons, 357
CL1, 358
outer ¡oíns
delíned, 50, 5l55
SQL/92 syntux, 5960
output, combíníng coíumn, 35
output íínes, 7576
overíoudíng methods, 420
overrídíng methods, 422423

puckuges
delíned, 365368
ímportíng }DßC, 536537
puge síze, settíng, 7273
purumeters
convertíng dutetíme usíng 1C_
CHAR( ), l33l35
procedures, 358359
1C_CHAR( ), l05l06
user-delíned constructors,
4l8422
purent nodes, l97
purent tubíes, 257258
purentheses ( ), 34, l68
pursíng
delíned, 562
XMLlARSL( ), 6l3
lAR1l1lCN ßY, 22022l
pusswords, lll2, 277278
lA1H envíronment vuríubíe, 534
percent (%), 404l
lLRCLN1_RANK( ), 2l8, 223
perlormunce speed, 23
lerí-ínlíuenced metuchuructers, ll2
phuntom reuds, 267268
phone, l5
llVC1
delíned, 244
exumpíe, 244246
muítípíe uggregute lunctíons ín,
247248
on muítípíe coíumns, 246247
lL/SQL (lroceduruí Lunguuge/SQL),
339377
bíock structure, 340342
ín coííectíons, 444448
condítíonuí íogíc, 342343
CCLN1( ), 44845l
cursor steps, 346348
cursors, 345346
cursors und lCR íoops,
349350
dutubuse ob¡ects ín, 394395
DLLL1L( ), 45l452
delete_product(), 40040l
display_product(),
396397
DLl_VAL_CN_lNDLX
exceptíons, 356
exceptíons, 353355
LXlS1S( ), 452453
LX1LND( ), 453
llRS1( ), 454
lunctíons, 363365
get_product(), 398399
get_product_ref(), 400
get_products(), 395396
insert_product(), 397
íntroductíon, 2526
lNVALlD_NLMßLR exceptíons,
356357
LAS1( ), 454455
LCßs ín, 482484. 
LCßs (íurge ob¡ects)
íoops, 343345
new Crucíe Dutubuse ll
leutures, 374377
NLX1( ), 455456
ClLN-lCR stutement, 35035l
Crucíe dutu types, 638

Crucíe Dutubuse llg SQL
C1HLRS exceptíons, 357
puckuges, 365368
lRlCR( ), 456457
procedures, 358362
product_cursor.sqí exumpíe,
348349
product_lifecycle(),
40l402
product_lifecycle2(),
402403
storíng returned vuíues
lrom lunctíon wíth bínd
vuríubíe, 590
subtype ín píuce ol supertype,
406407
summury, 377
1RLA1( ) ín, 4l44l6
tríggers, 369374
1RlM( ), 457458
unconstruíned cursors,
352353
update_product(), 399
update_product_
price(), 398
user-delíned constructors,
4l8422
vuríubíes und types, 342
wrítíng XML dutu to lííe,
6l66l8
ZLRC_DlVlDL exceptíons,
355356
píun tubíes, 592593
píuns, executíon, 562, 59l598
píus (+). Scc + (píus)
poínters, 482
popuíutíng coííectíons, 434435
popuíutíng LCßs
ßllLLs, 482
CLCßs und ßLCßs, 479
popuíutíng prímury keys, 3l9
popuíutíng ResultSet ob¡ect,
543544
posítíonuí notutíon
udvunced queríes, 237238
cuíííng procedures, 36036l
pound (r), l07
lC\LR( ), 99, l0l
lC\LRMLL1lSL1( ), 472
lC\LRMLL1lSL1_ßY_
CARDlNALl1Y( ), 472
precísíon, l3
predelíned exceptíons, 354355
prepured SQL stutements, 562564
lRLSLN1NNV( ), 242243
lRLSLN1V( ), 242
price, l7
prímury keys
construínts enlorcement, 257
delíned, 306
popuíutíng wíth sequences, 3l9
príntíng bínd vuríubíes, 590
lRlCR( ), 449, 456457
prívute ítems, 365
prívííeges
uudítíng, 295
checkíng roíe, 29l292
gruntíng ob¡ect to roíes,
292293
ob¡ect, 28l287
query líushbucks, 270
revokíng ob¡ect, 288
summury, 297298
synonyms, 287288
user, 27828l
víews, 327
lroceduruí Lunguuge/SQL (lL/SQL).
Scc lL/SQL (lroceduruí
Lunguuge/SQL)
procedures
uppendíng dutu to CLCß,
506507
cuíííng ín puckuges, 367368
compuríng dutu ín CLCßs,
507508
copyíng dutu lrom CLCßs,
508509
copyíng LCß dutu. Scc copyíng
LCß dutu
delíned, 358362
delete_product(), 40040l
display_product(),
396397
erusíng CLCß dutu, 5l0
insert_product(), 397
product_lifecycle(),
40l402
product_lifecycle2(),
402403
reudíng dutu lrom CLCßs und
ßLCßs, 504506
retríevíng LCß íocutors, 503504
seurchíng CLCß dutu, 5l05ll
temporury CLCßs, 5095l0
tríggers, 369374
update_product(), 399
update_product_
price(), 398
usíng ob¡ects ín lL/SQL,
394395
wrítíng to CLCß, 506
processíng dutetíme. Scc dutetíme
processíng ínstructíons, 6l4
product_cursor.sqí exumpíe,
348349
product_id, l6, l7l8
product_lifecycle(),
40l402
product_lifecycle2(),
402403
products tubíe, l5l6
product_type_id, l5l7
product_types tubíe, l5l6
lRCCRAM_LRRCR, 354
progrummíng íunguuges
lL/SQL. Scc lL/SQL (lroceduruí
Lunguuge/SQL)
SQL*líus. Scc SQL*líus
XML. Scc XML (Lxtensíbíe
Murkup Lunguuge)
pseudo coíumns
delíned, 30
LLVLL, l98l99
sequences, 3l73l9
pubííc synonyms, 287288
purchases tubíe, l7l8

quantity, l8
quurter lormuttíng purumeters, l33
queríes
costs compuríson, 59l598
delíned, 28
líushbucks, 270273
subqueríes. Scc subqueríes
tuníng SQL. Scc SQL (Structured
Query Lunguuge) tuníng
usíng }DßC, 543547
XMLQLLRY( ), 6l8622
queríes, udvunced, l83250
uíí ceíís uccess usíng ANY und
lS ANY, 238239
lL/SQL (con|ínucd)
lndex

unuíytíc lunctíons, 2l62l7
CASL expressíons, l93l96
ceíí uccess usíng lCR íoop,
24024l
ceíí runge uccess usíng
ßL1\LLN und AND, 238
CLßL, 207208
current dímensíon vuíues usíng
CLRRLN1V( ), 239240
DLCCDL( ), l9ll93
eíímínutíng nodes und brunches,
20l202
llRS1 und LAS1 lunctíons, 233
lormuttíng híerurchícuí resuíts,
l99200
CRCLl ßY, 203204
CRCLl ßY coíumn use, 2l4
CRCLl_lD( ), 2l52l6
CRCLllNC( ), 2092ll
CRCLllNC SL1S, 2ll2l2
CRCLllNC_lD( ), 2l22l4
híerurchícuí, l96l99
híerurchícuí, íncíudíng other
condítíons, 202203
hypothetícuí runk und
dístríbutíon lunctíons, 235
ínverse percentííe lunctíons,
224225
LAC( ) und LLAD( ), 232233
ííneur regressíon lunctíons,
233235
MCDLL, 236237
muítípíe uggregute lunctíons ín
pívot, 247248
nuíí und míssíng vuíues
hundííng, 24l243
llVC1 und LNllVC1, 244
llVC1 exumpíe, 244246
pívotíng on muítípíe coíumns,
246247
posítíonuí und symboííc
notutíon, 237238
runkíng lunctíons, 2l7224
reportíng lunctíons, 230232
RCLLLl, 205207
set operutors, l84l88
set operutors, combíníng,
l88l90
S1AR1 \l1H subquery, 20020l
sturtíng ut node other thun
root, 200
summury, 249250
1RANSLA1L( ), l90l9l
truversíng upwurd through
tree, 20l
LNllVC1, 248249
updutíng exístíng ceíís,
243244
wíndow lunctíons, 225230
query stutements, SQL, 3
questíon murk (:), 564
quíttíng SQL *líus, 25
quotes ("), 34, 254

runge, 23
runk, hypothetícuí lunctíons, 235
runkíng lunctíons, 2l6, 2l7224
RA1lC_1C_RLlCR1( ), 23l232
RA\ types, 52l
RLAD( ), 484, 499500,
504506
RLAD CCMMl11LD, 268
RLAD CNLY, 306, 330
RLAD LNCCMMl11LD, 268
RLl( ), 390392
RLl CLRSCR, 35l, 59059l
relerences, ob¡ect, 383,
390392
RLCLXl_CCLN1( ), ll4, ll6
RLCLXl_lNS1R( ), ll3, ll5
RLCLXl_LlKL( ), ll3, ll4ll5
RLCLXl_RLlLACL( ), ll4, ll6
RLCLXl_SLßS1R( ), ll4, ll6
reguíur expressíon lunctíons, 90,
l09ll6
reguíur expressíons
lunctíons, ll3ll6
metuchuructers, l09ll2
reíutíonuí dutu, generutíng XML. Scc
XML (Lxtensíbíe Murkup
Lunguuge)
reíutíonuí dutubuses, 23
removíng rows, 256
RLNAML, 3
renumíng tubíes, 3l3
RLlLA1AßLL RLAD, 268
RLlLACL( ), 9l, 9697
reportíng lunctíons, 2l6,
230232
reports, 7985
resuít set
delíned, 28
retríevíng rows usíng }DßC,
543547
resuíts, híerurchícuí query, l99200
retríevíng ínlormutíon. Scc
ínlormutíon retríevuí
RL1LRNlNC, 255256
RLVCKL, 4
revokíng prívííeges
ob¡ect, 288
lrom users, 28l
revokíng roíes, 294
ríght outer ¡oíns, 5254, 5960
roíes
checkíng prívííeges,
29l292
creutíng, 289
deluuít, 294
droppíng, 295
grunted prívííege use, 293
grunted to users, 29029l
gruntíng ob¡ect prívííeges,
292293
gruntíng prívííeges, 290
revokíng, 294
summury, 297298
RCLLßACK
delíned, 4
row removuí, 2223
trunsuctíons, 262263
RCLLLl
delíned, 205207
CRCLllNC( ), 2092l0
usíng wíth unuíytíc lunctíons,
22l223
Romco and }uííc|
(Shukespeure), ll0
root nodes
delíned, l97
sturtíng ut node other thun, 200
rotutíng. Scc llVC1
RCLND( )
dutetíme lunctíons,
l43, l45
delíned, 99, l0l
row-íeveí tríggers, 369
RC\lD, 30
RC\NLM, 303l
RC\_NLMßLR( ), 2l8, 224

Crucíe Dutubuse ll SQL
rows
uddíng/modílyíng/removíng,
2023
uddíng usíng }DßC, 547548
chungíng tubíe contents. 
tubíe contents, chungíng
delíned, 2
deíetíng usíng }DßC, 548
díspíuyíng dístínct, 37
lííteríng wíth \HLRL, 58058l
gettíng lírst und íust, 229230
groupíng, l20l27
ídentílíers, 30
modílyíng usíng }DßC, 548
muítípíe-row subqueríes,
l73l75
numbers, 303l
pívotíng.  llVC1
removíng dupíícute wíth
CRCLl_lD( ), 2l52l6
retríevíng specílíc usíng
\HLRL, 29
retríevíng usíng }DßC, 543547
retríevíng wíth cursors. 
cursors
síngíe-row subqueríes, l68l73
sortíng, 4445
storíng wíth bínd vuríubíe,
59059l
usíng 1AßLL( ) to treut coííectíon
us seríes ol, 436438
RC\1YlL_MlSMA1CH, 354
RlAD( ), 9l, 95
RR lormut, l40l42
R1RlM( ), 9l, 95
ruíe-bused optímízutíon, 59l
RLLLS LlDA1L, 243244
R¦LN¦, 65
run-tíme checks, 4l24l6
run-tíme errors hundííng. 
exceptíons

salary_grades tubíe, l920
SAVLlClN1, 4
suvepoínts, 264265
suvíng SQL*líus lííes, 6670
suvíng XML
ín dutubuse, 622
exumpíe lííe, 623
exumpíe schemu, 623625
exumpíe schemu ínlormutíon
retríevuí, 625630
exumpíe schemu ínlormutíon
updutíng, 630633
scuíur subqueríes, l70
scuíe, l3
schemus, 2
schemus, store
DDL stutements, ll20
íntroductíon, l0ll
schemus, XML
creutíng, 623625
ínlormutíon retríevuí, 625630
ínlormutíon updutíng, 630633
SCNs (system chunge numbers),
272273
scrípts, 7985
seurched CASL expressíons,
l94l96
seurchíng CLCß dutu, 5l05ll
seconds
lormuttíng purumeters, l34
lN1LRVAL DAY 1C SLCCND,
l62l64
SLLLC1
uddíng rows, 2l
perlormíng usíng SQL*líus, 67
síngíe tubíe ínlormutíon
retríevuí, 2829
usíng muítípíe tubíes, 4950
usíng two tubíes, 4547
SLLl, 4l9
seíl ¡oíns, 50, 5556, 60
SLLl_lS_NLLL, 355
semícoíon (,), 6, 34l
sepurutors, l34
sequences, 3l4320
creutíng, 3l43l6
droppíng, 320
modílyíng, 320
new Crucíe Dutubuse ll
leutures, 375377
popuíutíng prímury keys, 3l9
retríevíng ínlormutíon, 3l63l7
summury, 337
usíng, 3l73l9
XMLSLQLLNCL( ), 6l5
SLRlALlZAßLL trunsuctíons,
268269
server-síde ínternuí dríver, 536
server-síde 1hín dríver, 536
sessíons
delíned, l39
tíme zones, l47l49
SL1( ), 470
SL1 LlNLSlZL, 73
set methods, 540542
set operutors, l84l90
SL1 lACLSlZL, 7273
SL1S, CRCLllNC, 2ll2l2
Shukespeure, \ííííum, ll0, 477
SlCN( ), 99, l02
símpíe CASL expressíons,
l93l94
símpíe íoops, 343344
símpíe víews, 327
SlMlLL_lN1LCLR type, 375
SlN( ), 99
síngíe-row lunctíons
churucter, 9098
conversíon, l02l09
numeríc, 98l02
reguíur expressíon, l09ll6
types ol, 90
síngíe-row subqueríes, l68l73
SlNH( ), 99
sízíng coíumns, 305
sízíng eíement types, 463
SCML, 3839
sortíng rows, 4445
SCLNDLX( ), 9l, 97
specíuí vuíues, 2425
specílícutíons, puckuge,
365366, 395
SlC¦CL¦, 67
SQL/92
CASL expressíons, l93
delíned, 47
¡oíns usíng, 566l
SQL Access Advísor, 60l
SQL Deveíoper, 7l0
SQL (Structured Query Lunguuge)
íntroductíon, 34
LCßs ín, 478482
operutor precedence, 44
operutors, 3943
Crucíe dutu types, 636637
lroceduruí Lunguuge. 
lL/SQL (lroceduruí
Lunguuge/SQL)
lndex

subtype ín píuce ol supertype,
405406
SQL (Structured Query Lunguuge),
runníng usíng }uvu, 53l578
uddíng rows, 547548
BasicExample1.java,
556562
BasicExample2.java,
565567
BasicExample3.java,
575577
cíosíng }DßC ob¡ects, 554556
conlíguríng computer, 533535
dutubuse connectíon, 537542
dutubuse trunsuctíon controí,
552553
DDL stutements, 553
deíetíng rows, 548
gettíng sturted, 532
hundííng dutubuse nuíí vuíues,
550552
hundííng exceptíons, 553554
hundííng numbers, 549550
ímportíng }DßC puckuges,
536537
}DßC Statement ob¡ect,
542543
modílyíng rows, 548
Crucíe }DßC drívers, 535536
Crucíe }DßC extensíons,
567568
oracle.jdbc puckuge,
57l575
oracle.sql puckuge,
56857l
prepured stutements, 562564
regísteríng Crucíe }DßC
drívers, 537
retríevíng rows, 543547
summury, 578
SQL (Structured Query Lunguuge)
tuníng, 57960l
uddíng índexes to tubíes, 584
uddítíonuí tooís, 60060l
bínd vuríubíes, 58859l
CASL expressíons vs. muítípíe
queríes, 583
LXlS1S vs. DlS1lNC1, 587
LXlS1S vs. lN, 586587
lííteríng rows wíth \HLRL,
58058l
CRCLllNC SL1S vs.
CLßL, 588
íntroductíon, 580
¡oíns wíth quuíílíed coíumn
relerences, 582
pussíng hínts to optímízer,
598600
query costs compuríson,
59l598
summury, 60l
tubíe ¡oíns vs. muítípíe queríes,
58l582
LNlCN ALL vs. LNlCN,
585586
\HLRL vs. HAVlNC,
584585
SQL 1uníng Advísor, 60060l
SQL*líus, 6387
uutomutícuííy generuted
stutements, 86
ßlNARY_lLCA1 und ßlNARY_
DCLßLL types, 2325
coíumn lormut cíeuríng, 73
coíumn lormuttíng, 7072
DDL stutements used to creute
store schemu, ll20
dísconnectíng/exítíng, 86
edítíng SQL stutements,
6566
lííes, suvíng/retríevíng/runníng,
6670
gettíng heíp, 8586
ínlormutíon retríevuí. 
dutubuse tubíe ínlormutíon
retríevuí
íntroductíon, 47
ííne síze, settíng, 73
puge síze, settíng, 7273
quíttíng, 25
rows, uddíng/modílyíng/
removíng, 2023
símpíe reportíng, 7985
store schemu, l0ll
summury, 87
tubíe structure, 6465
vuríubíes, 7479
SQR1( ), 99, l02
S1AR1 \l1H, l98, 20020l
sturtíng trunsuctíons, 263
stutement-íeveí trígger, 369
Statement ob¡ect, 542543
stutístícs ín cost-bused
optímízutíon, 597
S1DDLV( ), ll7, l20
storuge
dutetíme.  dutetíme
delíned, 23
numbers ín }uvu,
549550
returned vuíues wíth bínd
vuríubíe, 590
rows wíth bínd vuríubíe,
59059l
tubíes, 463464
S1CRACL_LRRCR, 355
store schemus
DDL stutements, ll20
íntroductíon, l0ll
stored subprogrums, 363
stríngs
convertíng dutetíme usíng
1C_CHAR( ), l32l36
convertíng dutetíme usíng
1C_DA1L( ), l36l39
convertíng to 1lMLS1AMl
\l1H LCCAL 1lML
ZCNL, l59
XMLSLRlALlZL( ), 6l6
structure, bíock, 340342
Structured Query Lunguuge (SQL).
 SQL (Structured Query
Lunguuge)
SLßMLL1lSL1, 442, 466467
subqueríes, l67l8l
correíuted, l75l79
muítípíe-coíumn, l75
muítípíe-row, l73l75
nested, l79l80
síngíe-row, l68l73
S1AR1 \l1H, 20020l
summury, l8l
types ol, l68
LlDA1L, 255
LlDA1L und DLLL1L stutements
contuíníng, l80l8l
SLßSCRll1_ßLYCND_
CCLN1, 355
SLßSCRll1_CL1SlDL_LlMl1, 355
substítutíon vuríubíes, 7479
SLßS1R( ), 9l, 9798, 484,
50050l
subtotuí computíng, 8385

Crucíe Dutubuse ll SQL
subtypes
delíned, 404
generuíízed ínvocutíon,
423425
lS Cl( ), 4084l2
overrídíng methods, 422423
usíng ín píuce ol supertype,
405408
SLM( ), ll7, l20
sums, cumuíutíve, 225227
sums, reportíng on, 23023l
supertypes
delíned, 404
generuíízed ínvocutíon,
423425
NC1 lNS1AN1lAßLL ob¡ect
types, 4l64l8
overrídíng methods, 422423
subtype, usíng ín píuce ol,
405408
symboííc notutíon, 237238
synonyms, prívííeges, 287288
SYSDA1L, 67, l43, l45
SYS_LX1RAC1_L1C( ), l55,
l57l58
SYS_lNVALlD_RC\lD, 355
system chunge numbers (SCNs),
272273
system prívííeges.  prívííeges
SYS1lMLS1AMl, l55l56
SYS_1YlLlD( ), 408, 4l6

1AßLL( ), 436438
tubíe uííuses
delíned, 4748
seíl ¡oíns, 55
tubíe contents, chungíng, 25l273
uddíng rows, 252254
dutubuse íntegríty, 256258
dutubuse trunsuctíons,
262269
deluuít vuíues, 258259
mergíng rows, 259262
modílyíng rows, 254255
query líushbucks, 270273
removíng rows, 256
RL1LRNlNC, 255256
summury, 273
tubíe ¡oíns.  ¡oíns
delíned, 46
executíon píuns ínvoívíng,
596597
vs. muítípíe queríes,
58l582
tubíes, 3003l4
uddíng comments, 3l33l4
uddíng índexes to, 584
uíteríng, 302306
ßlNARY_lLCA1 und ßlNARY_
DCLßLL, 2425
coíumn ob¡ects, 383386
compuríng ob¡ect vuíues,
392394
construínts, 3063l2
contuíníng LCßs, 478
creutíng, 300302
delíníng coíumn wíth coííectíon
type, 430
droppíng, 3l4
exumíníng, l220
gettíng ínlormutíon on,
302303
ínlormutíon retríevuí. 
dutubuse tubíe ínlormutíon
retríevuí
nested.  nested tubíes
ob¡ect tubíes, 386389
ClDs und ob¡ect relerences,
390392
píun tubíe, 592593
renumíng, 3l3
SQL*líus structure, 6465
storuge tubíe tubíespuce,
463464
substítutíng numes usíng
vuríubíes, 7677
summury, 337
truncutíng, 3l4
vurruys ín temporury, 463
tubíespuces, 276, 463464
1AN( ), 99
1ANH( ), 99
1C (1runsuctíon Controí)
stutements, 4
temporury LCßs
CRLA1L1LMlCRARY( ), 488
lRLL1LMlCRARY( ), 492
usíng temporury CLCßs,
5095l0
temporury tubíes, 463
temporury vuríubíes, 7477, 80
1HLN, 342343
1hín dríver, 535536
tíme.  dutetíme
tíme query líushbucks, 270272
tíme zones, l35, l46l50,
l52l54
1lMLCL1_CN_RLSCLRCL, 355
tímestumps
líushbuck dutu urchíves,
334337
lunctíons, l54l59
usíng, l50l54
1C_CHAR( )
combíníng wíth 1C_DA1L( ),
l38l39
convertíng dutetíme, l3ll36
delíned, l04l07
1C_DA1L( ), 32, l3ll32, l36l39
1C_NLMßLR( ), l07l08
tooís, SQL tuníng.  SQL
(Structured Query Lunguuge)
tuníng
1CC_MANY_RC\S, 355
1C_1lMLS1AMl( ), l55, l58
1C_1lMLS1AMl_1Z( ), l55, l58
truíí víews, uudítíng, 296
1runsuctíon Controí (1C)
stutements, 4
trunsuctíon ísoíutíon íeveí,
267269
trunsuctíon íockíng, 266267
trunsuctíons, dutubuse, 262269,
552553
1RANSLA1L( ), l90l9l
trunspurent roundíng, 23
1RLA1( ), 408, 4l24l6
tree queríes.  híerurchícuí
queríes
delíned, l97
eíímínutíng nodes und brunches,
20l202
truversíng upwurd through, 20l
tríggers
:new uttríbute, 524525
delíned, 369374
1RlM( )
delíned, 9l, 95, 449,
457458, 484
LCß methods, 50l502
lndex

1RLNC( )
dutetíme lunctíons,
l43, l46
delíned, 99, l02
1RLNCA1L, 3, 3l4
try/cutch stutements, 553554
11l1LL, 8283
tuníng, SQL.  SQL (Structured
Query Lunguuge) tuníng
two-dígít yeur ínterpretutíon,
l40l42
types
chungíng coíumn, 305
cíusses und computíbíe Crucíe
dutubuse types, 568
hundííng numbers wíth }uvu,
549550
Crucíe, 635638
Crucíe und }uvu, 544545
lL/SQL, 342
SlMlLL_lN1LCLR, 375
types, coííectíon
convertíng wíth CAS1( ),
443444
delíned, 429430
delíníng coíumns wíth, 430
eíement type sízíng, 463
types, LCß
ßllLLs.  ßllLLs (bínury
llLL types)
ßLCßs (bínury LCßs). 
ßLCßs (bínury LCßs)
CLCßs.  CLCßs
(churucter LCßs)
creutíng, 477478
LCNC und LCNC RA\ types,
52l522
NCLCßs.  NCLCßs
(Nutíonuí Churucter Set LCßs)
types, ob¡ect
creutíng, 38l382
generuíízed ínvocutíon,
423425
ínherítunce, 403405
lS Cl( ), 4084l2
NC1 lNS1AN1lAßLL,
4l64l8
overrídíng methods,
422423
subtype ín píuce ol supertype,
405408
SYS_1YlLlD( ), 4l6
usíng DLSCRlßL to get
ínlormutíon, 382383

unconstruíned cursors, 352353
LNDLllNL, 7879
underscore (_), 404l
LNlCN
combíníng set operutors,
l88l89
delíned, l84
vs. LNlCN ALL, 585586
usíng, l87
LNlCN ALL
delíned, l84
vs. LNlCN, 585586
usíng, l86l87
LNlQLL, 306, 309
Lníx, CRACLL_HCML envíronment
vuríubíe, 533534
LNllVC1, 244, 248249
LlDA1L
delíned, 3
modílyíng rows, 22, 254255
stutements contuíníng
subqueríes, l80l8l
usíng }DßC, 548
update_product(),
394, 399
update_product_price(),
394, 398
updutíng
RLLLS LlDA1L, 243244
XML schemu, 630633
LllLR( ), 9l, 9495
upper bounds, 344345
LRL, dutubuse connectíon,
538539
user-delíned constructors, 4l8422
user víews
nested tubíes, 433
vurruys, 43l432
users
uudítíng, 295296
creutíng, lll2
grunted roíes to, 29029l
gruntíng ob¡ect prívííeges, 282
overvíew, 276278
prívííeges, 27828l
summury, 297298
LSlNC, 5758, 26l
L1C (Coordínuted Lníversuí 1íme),
l46l47

VACHAR( ), l3
VALLL( ), 387
VALLL_LRRCR, 355
vuíues
ussocíutíve urruys, 462
compuríson, 3739
convertíng wíth CRCLllNC,
2092l0
dutubuse ob¡ects compuríson,
392394
decíuríng vuríubíes to store
coíumn, 346
gettíng current, 239240
gettíng lírst und íust rows usíng,
229230
hundííng nuíí und míssíng,
24l243
nuíí.  nuíí vuíues
reudíng coíumn lrom
ResultSet ob¡ect, 544545
storíng returned wíth bínd
vuríubíe, 590
usíng deluuít, 258259
vuríubíes
bínd, 58859l
cursors, 346
CRACLL_HCML envíronment,
533534
lL/SQL, 342
ín scrípts, 8082
SQL*líus, 7479
VARlANCL, ll7, l20
vurruys
convertíng wíth CAS1( ),
443444
delíned, 428
íncreusíng eíements ín, 463
ínlormutíon retríevuí, 43l432
munípuíutíng, 444446
modílyíng eíements, 438439
muítííeveí coííectíons, 45846l
popuíutíng wíth eíements, 434

Crucíe Dutubuse llg SQL
retríevíng eíements lrom, 435
ín temporury tubíes, 463
types, 429430
usíng 1AßLL( ) wíth, 437438
víews, 325334
creutíng/usíng, 326333
delíned, 325326
droppíng, 334
errors ín procedures, 362
modílyíng, 333334
nested tubíe ínlormutíon
retríevuí, 433
summury, 337
tubíe structure, 6465
vurruy ínlormutíon retríevuí,
43l432
vírtuuí coíumns, 304305

wuííets, 525526
week lormuttíng purumeters, l34
\HLN NC1 MA1CHLD, 26l
\HLRL
lííteríng rows wíth, 58058l
groupíng rows, l26l27
vs. HAVlNC, 584585
híerurchícuí queríes, 202203
retríevíng specílíc rows, 29
row modílícutíon, 22
subqueríes ín, l68l69
usíng SQL operutors, 3943
\HlLL íoops, 343, 344
wíndow lunctíons, 2l6, 225230
\índows Xl, CRACLL_HCML
envíronment vuríubíe, 533
\CR¦D_\RAllLD¦, 707l
\RA¦llLD¦, 707l
wrupper cíusses, 55l552
\Rl1L( ), 484, 502, 506
\Rl1LAllLND( ), 484, 503

x, 6566
XML (Lxtensíbíe Murkup Lunguuge),
603633
exumpíe lííe, 623
exumpíe schemu, 623625
exumpíe schemu ínlormutíon
retríevuí, 625630
exumpíe schemu ínlormutíon
updutíng, 630633
generutíng lrom reíutíonuí
dutu, 604
íntroductíon, 604
lL/SQL exumpíe, 6l66l8
suvíng ín dutubuse, 622
summury, 633
XMLACC( ), 6096l2
XMLA11RlßL1LS( ), 608
XMLCCLA11VAL( ), 6l2
XMLCCMMLN1( ), 6l4
XMLCCNCA1( ), 6l3
XMLLLLMLN1( ), 605608
XMLlCRLS1( ), 608609
XMLlARSL( ), 6l3
XMLll( ), 6l4
XMLQLLRY( ), 6l8622
XMLSLQLLNCL( ), 6l5
XMLSLRlALlZL( ), 6l6
XQuery expressíon, 6l8622

yeurs
dutetíme deluuít lormut, l30
dutetíme lormuttíng
purumeters, l33
lN1LRVAL YLAR 1C MCN1H,
l59l62
two-dígít yeur ínterpretutíon,
l40l42
YY lormut, l40
YYYY, l30

ZLRC_DlVlDL exceptíons, 355356
vurruys (con|ínucd)
F8EE 8üß868I FII üN
YOU MUST ANSWER ALL TEN OUESTIONS BELOW.

Yes, pIease send me a FREE subscription to OracIe magazine. NO
To receive a Iree subscripIioh Io Oracíe Nagaz¡ne, you musI Iill ouI Ihe ehIire card, sigh iI, ahd daIe iI
(ihcompleIe cards cahhoI be processed or ackhowledged). You cah also Ia× your applicaIioh Io +1.847.763.9638.
Or subscribe at our Web site at otn.oracIe.com/oracIemagazine
h a m e I i I l e
c o m p a h y e - m a i l a d d r e s s
s I r e e I / p . o . b o ×
c i I y / s I a I e / z i p o r p o s I a l c o d e I e l e p h o h e
c o u h I r y I a ×
s i g h a I u r e ( r e q u i r e d ) d a I e
x
From Iime Io Iime, Oracle Publishihg allows
our parIhers e×clusive access Io our e-mail
addresses Ior special promoIiohs ahd
ahhouhcemehIs. To be ihcluded ih Ihis pro-
gram, please check Ihis circle.
Oracle Publishihg allows sharihg oI our
mailihg lisI wiIh selecIed Ihird parIies. ÌI you
preIer your mailihg address hoI Io be
ihcluded ih Ihis program, please check here.
ÌI aI ahy Iime you would like Io be removed
Irom Ihis mailihg lisI, please cohIacI
CusIomer Service aI +1.847.647.9630 or sehd
ah e-mail Io oracle@halldaIa.com.
RäAI | º Iä | º1| ¥A1 \ JJ º| 4| ºº
A| I| \ | I \ J | \J J1 | | 1¥ AI I ä| º
| J| AI | J4! (:|-:| ta- ta|¡j
1I A-|tsj±:- ±a1 J-|-as- ¥±aa|±:|a||a¡
1l Ajj||:±||ta º-|t|:- º|tt|1-|
11 Aa|tmt||t- ¥±aa|±:|a||a¡
11 ||-m|:±|s, J|| ±a1 ä±s
1a |tmmaa|:±||tas ±a1 ¥-1|±
1ä |tas||a:||ta/|a¡|a--||a¡
1I |tasam-| º-:|t|/|tasam-| º±:|±¡-1 ätt1s
1º |1a:±||ta
11 ||a±a:|±| º-|t|:-s/|asa|±a:-
I1 ätt-|am-a| (:|t||j
II ätt-|am-a| (m||||±|¡j
Il ä-±|||:±|-
I1 ä|¡| I-:|at|t¡¡ ¥±aa|±:|a||a¡, J|¥
I1 |a|-¡|±|-1 ºt||w±|- \-a1t|
Ia |||- º:|-a:-s (J|t|-:|, º|±|m±:-a||:±|sj
Iä ¥|a|a¡
II 1-|±||/R|t|-s±|-/J|s||||a||ta
Iº º¡s|-ms |a|-¡|±|t|, \A1/\AJ
I1 I-|-:tmmaa|:±||tas
l1 I|±t-| ±a1 I|±asjt||±||ta
lI J||||||-s (-|-:|||:, ¡±s, s±a||±||ta, w±|-|j
1º J||-| Jas|a-ss ±a1 º-|t|:-s
Rä| | ä J | I ä | | J || J R| 4 ä J| ºI
J |º |1| J| º \J J1 º 1| ¥A1\ J JJ
| J4| I | J 4! (:|-:| ta- ta|¡j
| t | j t | ± | - ¥± a ± ¡ - m- a | / º| ± | |
1I |t-:a||t- ¥±a±¡-m-a| (º|-s|1-a|, ||±||,
||J, ||J, Jwa-|, º±||a-|, º||a:|j±|j
1l ||a±a:-/A1m|a|s||±||t- ¥±a±¡-m-a|
(\º/J||-:|t|/ ¥±a±¡-|/|ta||t||-|,
ºa|:|±s|a¡, A1m|a|s||±||taj
11 º±|-s/¥±||-||a¡ ¥±a±¡-m-a|
(\º/J||-:|t|/¥±a±¡-|j
11 |tmja|-| º¡s|-ms/Jj-|±||tas ¥±a±¡-m-a|
(||J/\º/J||-:|t|/ ¥±a±¡-| ¥|º, Jj-|±||tasj
| º/ | I º | ± | |
1a º¡s|-ms J-t-|tjm-a|/
º|t¡|±mm|a¡ ¥±a±¡-m-a|
1ä º¡s|-ms J-t-|tjm-a|/ º|t¡|±mm|a¡ º|±||
1I |tasa|||a¡
1º JJA/º¡s|-ms A1m|a|s||±|t|
11 |1a:±||ta/I|±|a|a¡
I1 I-:|a|:±| ºajjt|| J||-:|t|/¥±a±¡-|
II J||-| I-:|a|:±| ¥±a±¡-m-a|/º|±||
1º J||-|
RäAI | º \J J1 |J 11| 4I º1| ¥A1\
J º|1AI | 4ä º|AI | J1¥! (s-|-:| ±|| ||±| ±jj|¡j
1I J|¡||±| |¡a|jm-a| J4|K
1l J|¡||±| |¡a|jm-a| \AK \¥º
11 äº J4|K
11 |J¥ A|K
1a |J¥ J4|K
1ä J±t±
1I ||aat
1º ¥±:|a|ts|
11 ¥º-JJº
I1 ¥\º
II 4-|R±|-
Il 4-|wt|| |tmja||a¡
I1 Jj-a\¥º
I1 º|J J4|K
Ia º-¡a-a| J\4|K/j|t
Iä ºaa ºt|±||s/ºaaJº
II º\11
Iº Ja|tR±|-
I1 R|a1tws
l1 R|a1tws 4I
lI J||-| J4|K
1º J||-|
11 4ta- t| ||- ±|tt-
J J \ JJ | \A|J AI |, ºº| | | |\ ,
1| |J ¥¥| 4J, J 1 AJ I äJ 1| l | Iä |
ºJ 1|ä Aº| J | A4\ J | I ä | | J || J R| 4 ä!
(:|-:| ±|| ||±| ±jj|¡j
1I ä±|1w±|-
1l ºt||w±|-
11 Ajj||:±||ta J-t-|tjm-a| Itt|s
11 J±|±|±s- º|t1a:|s
1a |a|-|a-| t| |a||±a-| º|t1a:|s
11 4ta- t| ||- ±|tt-
| 4 \ JJ 1 J JJ, J J \ JJ J º| J1 º|A4 I J
ºJ 1|ä Aº| A4\ J| I ä| | J| | JR| 4ä
º1J JJ | Iº ! (:|-:| ±|| ||±| ±jj|¡j
ºt | | w± | -
1I Jas|a-ss ä|±j||:s
1l |AJ/|A|/|A¥
11 |Aº|
11 |tmmaa|:±||tas
1a J±|±|±s- ¥±a±¡-m-a|
1ä |||- ¥±a±¡-m-a|
1I ||a±a:-
1º J±t±
11 ¥±|-||±|s 1-sta|:- º|±aa|a¡
I1 ¥a|||m-1|± Aa||t||a¡
II 4-|wt|||a¡
Il J|||:- Aa|tm±||ta
I1 J|1-| |a||¡/|at-a|t|¡ |ta||t|
I1 º|t¡|±mm|a¡
Ia º|tj-:| ¥±a±¡-m-a|
Iä º:|-a||||: ±a1 |a¡|a--||a¡
II ºj|-±1s|--|s
Iº º¡s|-ms ¥±a±¡-m-a|
I1 Rt||||tw
ä ± | 1 w± | -
l1 ¥±:|a|ts|
lI ¥±|a||±m-
ll ¥±ss|t-|¡ º±|±||-| º|t:-ss|a¡
l1 ¥|a|:tmja|-|
l1 º|
la 4-|wt|| |tmja|-|
lä º¡mm-|||: ¥a|||j|t:-ss|a¡
lI Rt||s|±||ta
º- | | j | - | ± | s
lº J||1¡-s/1ta|-|s/äa|s/ä±|-w±¡s
l1 |J-1J¥ J||t-s
11 J|s| J||t-s/ºa|s¡s|-ms
1I ¥t1-ms
1l I±j- J||t-s/ºa|s¡s|-ms
11 \|1-t Jt±|1s/¥a|||m-1|±
º- | t | : - s
11 Ajj||:±||ta º-|t|:- º|tt|1-|
1a |tasa|||a¡
1ä |1a:±||ta/I|±|a|a¡
1I ¥±|a|-a±a:-
1º Ja||a- J±|±|±s- º-|t|:-s
11 ºajjt||
11 I-:|at|t¡¡-J±s-1 I|±|a|a¡
1º J||-|
11 4ta- t| ||- ±|tt-
RäAI J 1A|| | º1JJ J |I º A1| | 4 Jº |
AI \J J1 º| I |! (:|-:| ±|| ||±| ±jj|¡j
J | ± : | - | - Ja s | a - s s ºa | | -
1I J|±:|- ¥±||-||a¡
1l J|±:|- º±|-s
11 J|±:|- J|1-| |a|||||m-a|
11 J|±:|- ºajj|¡ ||±|a ¥±a±¡-m-a|
1a J|±:|- º|t:a|-m-a|
1ä J|±:|- ¥±aa|±:|a||a¡
1I J|±:|- ¥±|a|-a±a:- ¥±a±¡-m-a|
1º J|±:|- º-|t|:-
11 J|±:|- |ta||±:|s
I1 J|±:|- º|tj-:|s
II J|±:|- ||a±a:|±|s
Il J|±:|- äam±a 1-sta|:-s
I1 J|±:|- |a|-|±:||ta |-a|-|
I1 J|±:|- |tmmaa|:±||tas/J||||||-s (mt1a|-sj
Ia J|±:|- ºa|||: º-:|t|/Ja|t-|s||¡ (mt1a|-sj
Iä J|±:|- ||a±a:|±| º-|t|:-s (mt1a|-sj
º- | t - | / º t | | w± | -
II J|±:|-1
Iº J|±:|-1 |||-
I1 J|±:|-º
l1 J||-| J|±:|- 1±|±|±s-
lI J|±:|-1 Ajj||:±||ta º-|t-|
ll J|±:|-1 Ajj||:±||ta º-|t-| R||-|-ss
l1 J|±:|- ºm±|| Jas|a-ss ºa||-
I t t | s
l1 J|±:|- J-t-|tj-| ºa||-
la J|±:|- J|s:tt-|-|
lä J|±:|- JJ-t-|tj-|
lI J|±:|- ¥|¡|±||ta Rt|||-a:|
lº J|±:|-1 Aº ºt||±|
l1 J|±:|- R±|-|tas- Ja||1-|
J | ± : | - º - | t | : - s
11 J|±:|- Ja|sta|:|a¡
1I J|±:|- |tasa|||a¡
1l J|±:|- |1a:±||ta
11 J|±:|- ºajjt||
1º J||-|
11 4ta- t| ||- ±|tt-
RäAI J I ä| 1 J AI AJAº| º1JJ J |I º A1|
| 4 J º| AI \J J1 º| I |! (:|-:| ±|| ||±| ±jj|¡j
1I A::-ss 1º ¥|:|tst|| A::-ss
1l J±±a 11 ¥|:|tst|| ºJ| º-|t-|
11 1|±s- I1 º-tj|-ºt||
11 äaj|± II º|t¡|-ss
1a |J¥ JJl Il ºAº
1ä |a|t|m|t I1 º¡|±s-
1I |a¡|-s I1 \ºA¥
1º J||-|
11 4ta- t| ||- ±|tt-
RäAI J I ä| 1 Aºº|| | AI | J4 º| 1\| 1
º1J JJ | Iº A1| | 4 Jº | AI \ JJ 1 º| I | !
(:|-:| ±|| ||±| ±jj|¡j
1I J|A
1l |J¥
11 º¡|±s-
11 ºaa
1a J||-|
J J1| 4ä I ä| 4| KI I l ¥J 4I äº , ä J R
¥J |ä J J \ J J A4I | | | ºAI | \ JJ 1
J 1äA4| l AI | J 4 R| | | ºº| 4J J4
| J¥ºJ I |1 äA1JRA1| , º J| I RA1|,
º| 1| ºä| 1A|º , A4J º| 1\| | | º
| J1 \ J J1 | J| AI | J4 ! (:|-:| ta|¡ ta-j
1I |-ss ||±a ºI1,111
1l ºI1,111 |t º11,111
11 ºa1,111 |t º11,111
11 ºI11,111 |t º111,111
1a ºa11,111 |t º111,111
1ä ºI,111,111 ±a1 tt-|
RäAI | º \J J1 |J ¥ºA4\' º \ | A1| \
ºA| |º 1| \|4 J| ! (j|-±s- :|tts- ta-j
1I ºa11, 111, 111 ±a1 ±|tt-
1l ºI11, 111, 111 |t ºa11, 111, 111
11 ºa1, 111, 111 |t ºI11, 111, 111
11 ºa, 111, 111 |t ºa1, 111, 111
1a ºI, 111, 111 |t ºa, 111, 111
1
2
3
4
8
9
10
6
5
7