You are on page 1of 200

Chupter 6: Subqueres

171
1hs vuue ol 26.22 s used n the HAVING cuuse ol the outer query to lter the group's rows
to those huvng un uveruge prce ess thun 26.22. 1he loowng query shows u verson ol the
outer query thut retreves the product_type_id und uveruge prce ol the products grouped
by product_type_id:
SELECT product_type_id, AVG(price)
FROM products
GROUP BY product_type_id
ORDER BY product_type_id;
PRODUCT_TYPE_ID AVG(PRICE)
--------------- ----------
1 24.975
2 26.22
3 13.24
4 13.99
13.49
1he groups wth u product_type_id ol l, 3, 4, und nu huve un uveruge prce ess thun
26.22. As expected, these ure the sume groups returned by the query ut the sturt ol ths secton.
Subqucrics in a fROM CIausc (lnIinc Vicws)
You muy puce u subquery n the FROM cuuse ol un outer query. 1hese types ol subqueres ure
uso known us , becuuse the subquery provdes dutu n ne wth the FROM cuuse.
1he loowng smpe exumpe retreves the products whose product_id s ess thun 3:
SELECT product_id
FROM
(SELECT product_id
FROM products
WHERE product_id < 3);
PRODUCT_ID
----------
1
2
Notce thut the subquery returns the rows lrom the products tube whose product_id s
ess thun 3 to the outer query, whch then retreves und dspuys those product_id vuues. As lur
us the FROM cuuse ol the outer query s concerned, the output lrom the subquery s ust unother
source ol dutu.
1he next exumpe s more uselu und retreves the product_id und price lrom the
products tube n the outer query, und the subquery retreves the number ol tmes u product
hus been purchused:
SELECT prds.product_id, price, purchases_data.product_count
FROM products prds,
(SELECT product_id, COUNT(product_id) product_count
172
Cruce Dutubuse ll SQL
FROM purchases
GROUP BY product_id) purchases_data
WHERE prds.product_id = purchases_data.product_id;
PRODUCT_ID PRICE PRODUCT_COUNT
---------- ---------- -------------
1 19.95 4
2 30 4
3 25.99 1
Notce thut the subquery retreves the product_id und COUNT(product_id) lrom the
purchases tube und returns them to the outer query. As you cun see, the output lrom subquery
s ust unother source ol dutu to the FROM cuuse ol the outer query.
frrurs Yuu Might fncuuntcr
ln ths secton, you' see some errors you mght encounter. Speclcuy, you' see thut u snge-
row subquery muy return u muxmum ol one row und thut u subquery muy not contun un ORDER
BY cuuse.
SingIc-Ruw Subqucrics May Rcturn a Maximum uf Onc Ruw
ll your subquery returns more thun one row, you' get the loowng error:
ORA-01427: single-row subquery returns more than one row.
lor exumpe, the subquery n the loowng stutement uttempts to puss mutpe rows to the
equuty operutor (=) n the outer query:
SQL> SELECT product_id, name
2 FROM products
3 WHERE product_id =
4 (SELECT product_id
5 FROM products
6 WHERE name LIKE '%e%');
(SELECT product_id
*
ERROR at line 4:
ORA-01427: single-row subquery returns more than one row
1here ure nne rows n the products tube whose numes contun the etter e, und the
subquery uttempts to puss these rows to the equuty operutor n the outer query. ecuuse the
equuty operutor cun hunde ony u snge row, the query s nvud und un error s returned.
You' eurn how to return mutpe rows lrom u subquery uter n the secton \rtng
Mutpe-Row Subqueres.
Subqucrics May Nut Cuntain an ORDfR BY CIausc
A subquery muy not contun un ORDER BY cuuse. lnsteud, uny orderng must be done n the
outer query. lor exumpe, the loowng outer query hus un ORDER BY cuuse ut the end thut sorts
the product_id vuues n descendng order:
Chupter 6: Subqueres
173
SELECT product_id, name, price
FROM products
WHERE price >
(SELECT AVG(price)
FROM products)
ORDER BY product_id DESC;
PRODUCT_ID NAME PRICE
---------- ------------------------------ ----------
5 Z Files 49.99
3 Supernova 25.99
2 Chemistry 30
1 Modern Science 19.95
Writing MuItipIc-Ruw Subqucrics
You use u mutpe-row subquery to return one or more rows to un outer SQL stutement. 1o
hunde u subquery thut returns mutpe rows, your outer query muy use the IN, ANY, or ALL
operutor. As you suw n Chupter 2, you cun use these operutors to see l u coumn vuue s
contuned n u st ol vuues, lor exumpe:
SELECT product_id, name
FROM products
WHERE product_id IN (1, 2, 3);
PRODUCT_ID NAME
---------- -------------------
1 Modern Science
2 Chemistry
3 Supernova
As you' see n ths secton, the st ol vuues cun come lrom u subquery.
NOTf
You can ao uc |hc EXISTS opcra|or |o chcc| | a vauc n a |
rc|urncd b, a corrca|cd ubqucr,. You' carn abou| |h a|cr, n |hc
cc|on Vr|ng Corrca|cd Subqucrc."
Using lN with a MuItipIc-Ruw Subqucry
As you suw n Chupter 2, you use IN to check l u vuue s n u specled st ol vuues. 1he st ol
vuues muy come lrom the resuts returned by u subquery. You cun uso use NOT IN to perlorm
the ogcu opposte ol IN: to check l u vuue s not n u specled st ol vuues.
1he loowng smpe exumpe uses IN to check l u product_id s n the st ol vuues
returned by the subquery, the subquery returns the product_id lor products whose nume
contuns the etter e:
SELECT product_id, name
FROM products
WHERE product_id IN
174
Cruce Dutubuse ll SQL
(SELECT product_id
FROM products
WHERE name LIKE '%e%');
PRODUCT_ID NAME
---------- -------------------
1 Modern Science
2 Chemistry
3 Supernova
5 Z Files
6 2412: The Return
7 Space Force 9
8 From Another Planet
11 Creative Yell
12 My Front Line
1he next exumpe uses NOT IN to get the products thut ure not n the purchases tube:
SELECT product_id, name
FROM products
WHERE product_id NOT IN
(SELECT product_id
FROM purchases);
PRODUCT_ID NAME
---------- -------------------
4 Tank War
5 Z Files
6 2412: The Return
7 Space Force 9
8 From Another Planet
9 Classical Music
10 Pop 3
11 Creative Yell
12 My Front Line
Using ANY with a MuItipIc-Ruw Subqucry
You use the ANY operutor to compure u vuue wth uny vuue n u st. You must puce un =, <>,
<, >, <=, or >= operutor belore ANY n your query. 1he loowng exumpe uses ANY to get the
empoyees whose suury s ess thun uny ol the owest suures n the salary_grades tube:
SELECT employee_id, last_name
FROM employees
WHERE salary < ANY
(SELECT low_salary
FROM salary_grades);
EMPLOYEE_ID LAST_NAME
----------- ----------
2 Johnson
3 Hobbs
4 Jones
Chupter 6: Subqueres
17S
Using All with a MuItipIc-Ruw Subqucry
You use the ALL operutor to compure u vuue wth uny vuue n u st. You must puce un =, <>,
<, >, <=, or >= operutor belore ALL n your query. 1he loowng exumpe uses ALL to get the
empoyees whose suury s greuter thun u ol the hghest suures n the salary_grades tube:
SELECT employee_id, last_name
FROM employees
WHERE salary > ALL
(SELECT high_salary
FROM salary_grades);
no rows selected
As you cun see, no empoyee hus u suury greuter thun the hghest suury.
Writing MuItipIc-CuIumn Subqucrics
1he subqueres you've seen so lur huve returned rows contunng one coumn. You're not mted
to one coumn: you cun wrte subqueres thut return mutpe coumns. 1he loowng exumpe
retreves the products wth the owest prce lor euch product type group:
SELECT product_id, product_type_id, name, price
FROM products
WHERE (product_type_id, price) IN
(SELECT product_type_id, MIN(price)
FROM products
GROUP BY product_type_id);
PRODUCT_ID PRODUCT_TYPE_ID NAME PRICE
---------- --------------- ------------------------------ ----------
1 1 Modern Science 19.95
4 2 Tank War 13.95
8 3 From Another Planet 12.99
9 4 Classical Music 10.99
Notce thut the subquery returns the product_type_id und the mnmum price lor euch
group ol products, und these ure compured n the outer query's WHERE cuuse wth the product_
type_id und price lor euch product.
Writing CurrcIatcd Subqucrics
A correuted subquery relerences one or more coumns n the outer SQL stutement. 1hese ure
cued corrca|cd subqueres, becuuse they ure reuted to the outer SQL stutement through the
sume coumns.
You typcuy use u correuted subquery when you need un unswer to u queston thut depends on
u vuue n euch row contuned n un outer query. lor exumpe, you mght wunt to see whether there
s u reutonshp between the dutu, but you don't cure how muny rows ure returned by the subquery,
thut s, you ust wunt to check whether an, rows ure returned, but you don't cure how muny.
A correuted subquery s run once lor euch row n the outer query, ths s dllerent lrom u non-
correuted subquery, whch s run once pror to runnng the outer query. ln uddton, u correuted
176
Cruce Dutubuse ll SQL
subquery cun resove nu vuues. You' see exumpes n the loowng sectons thut ustrute
these concepts.
A CurrcIatcd Subqucry fxampIc
1he loowng correuted subquery retreves the products thut huve u prce greuter thun the
uveruge lor ther product type:
SELECT product_id, product_type_id, name, price
FROM products outer
WHERE price >
(SELECT AVG(price)
FROM products inner
WHERE inner.product_type_id = outer.product_type_id);
PRODUCT_ID PRODUCT_TYPE_ID NAME PRICE
---------- --------------- ------------------------------ ----------
2 1 Chemistry 30
5 2 Z Files 49.99
7 3 Space Force 9 13.49
10 4 Pop 3 15.99
11 4 Creative Yell 14.99
Notce thut l've used the uus outer to ube the outer query und the uus inner lor the
nner subquery. 1he relerence to the product_type_id coumn n both the nner und outer
purts s whut mukes the nner subquery correuted wth the outer query. Aso, the subquery returns
u snge row contunng the uveruge prce lor the product.
ln u correuted subquery, euch row n the outer query s pussed one ut u tme to the subquery.
1he subquery reuds euch row n turn lrom the outer query und uppes t to the subquery unt u
the rows lrom the outer query huve been processed. 1he resuts lrom the entre query ure then
returned.
ln the prevous exumpe, the outer query retreves euch row lrom the products tube
und pusses them to the nner query. Luch row s reud by the nner query, whch cucuutes the
uveruge prce lor euch product where the product_type_id n the nner query s equu to
the product_type_id n the outer query.
Using fXlSTS and NOT fXlSTS with a CurrcIatcd Subqucry
You use the EXISTS operutor to check lor the exstence ol rows returned by u subquery. Athough
you cun use EXISTS wth non-correuted subqueres, you' typcuy use t wth correuted
subqueres. 1he NOT EXISTS operutor does the ogcu opposte ol EXISTS: t checks l rows
do not exst n the resuts returned by u subquery.
Using fXlSTS with a CurrcIatcd Subqucry
1he loowng exumpe uses EXISTS to retreve empoyees who munuge other empoyees, notce
thut l don't cure how muny rows ure returned by the subquery, l ony cure whether uny rows ure
returned ut u:
SELECT employee_id, last_name
FROM employees outer
WHERE EXISTS
(SELECT employee_id
Chupter 6: Subqueres
177
FROM employees inner
WHERE inner.manager_id = outer.employee_id);
EMPLOYEE_ID LAST_NAME
----------- ----------
1 Smith
2 Johnson
ecuuse EXISTS ust checks lor the exstence ol rows returned by the subquery, u subquery
doesn't huve to return u coumnt cun ust return u teru vuue. 1hs leuture cun mprove the
perlormunce ol your query. lor exumpe, the loowng query rewrtes the prevous exumpe wth
the subquery returnng the teru vuue l:
SELECT employee_id, last_name
FROM employees outer
WHERE EXISTS
(SELECT 1
FROM employees inner
WHERE inner.manager_id = outer.employee_id);
EMPLOYEE_ID LAST_NAME
----------- ----------
1 Smith
2 Johnson
As ong us the subquery returns one or more rows, EXISTS returns true, l the subquery returns
no rows, EXISTS returns luse. ln the exumpes, l ddn't cure how muny rows ure returned by the
subquery: A l cured ubout wus whether uny rows (or no rows) ure returned, so thut EXISTS returns
true (or luse). ecuuse the outer query requres ut eust one coumn, the teru vuue l s returned
by the subquery n the prevous exumpe.
Using NOT fXlSTS with a CurrcIatcd Subqucry
1he loowng exumpe uses NOT EXISTS to retreve products thut huven't been purchused:
SELECT product_id, name
FROM products outer
WHERE NOT EXISTS
(SELECT 1
FROM purchases inner
WHERE inner.product_id = outer.product_id);
PRODUCT_ID NAME
---------- -------------------
4 Tank War
5 Z Files
6 2412: The Return
7 Space Force 9
8 From Another Planet
9 Classical Music
10 Pop 3
11 Creative Yell
12 My Front Line
178
Cruce Dutubuse llg SQL
fXlSTS and NOT fXlSTS Vcrsus lN and NOT lN
Lurer n the secton Lsng lN wth u Mutpe-Row Subquery, you suw how the IN operutor s
used to check l u vuue s contuned n u st. EXISTS s dllerent lrom IN: EXISTS checks ust
lor the exstence ol rows, whereus IN checks lor uctuu vuues.
TlP
EXISTS |,pca, o||cr bc||cr pcr|ormancc |han IN v|h ubqucrc.
Thcrc|orc, ,ou houd uc EXISTS ra|hcr |han IN vhcrcvcr pobc.
You shoud be curelu when wrtng queres thut use NOT EXISTS or NOT IN. \hen u st
ol vuues contuns u nu vuue, NOT EXISTS returns true, but NOT IN returns luse. Consder the
loowng exumpe thut uses NOT EXISTS und retreves the product types thut don't huve uny
products ol thut type n the products tube:
SELECT product_type_id, name
FROM product_types outer
WHERE NOT EXISTS
(SELECT 1
FROM products inner
WHERE inner.product_type_id = outer.product_type_id);
PRODUCT_TYPE_ID NAME
--------------- ----------
5 Magazine
Notce one row s returned by ths exumpe. 1he next exumpe rewrtes the prevous query to
use NOT IN, notce thut no rows ure returned:
SELECT product_type_id, name
FROM product_types
WHERE product_type_id NOT IN
(SELECT product_type_id
FROM products);
no rows selected
No rows ure returned becuuse the subquery returns u st ol product_id vuues, one ol
whch s nu (the product_type_id lor product rl2 s nu). ecuuse ol ths, NOT IN n the
outer query returns luse, und therelore no rows ure returned. You cun get uround ths by usng the
NVL() luncton to convert nus to u vuue. ln the loowng exumpe, NVL() s used to convert
nu product_type_id vuues to 0:
SELECT product_type_id, name
FROM product_types
WHERE product_type_id NOT IN
(SELECT NVL(product_type_id, 0)
FROM products);
PRODUCT_TYPE_ID NAME
--------------- ----------
5 Magazine
1hs tme the row uppeurs.
Chupter 6: Subqueres
179
1hese exumpes ustrute unother dllerence between correuted und non-correuted
subqueres: u correuted query cun resove nu vuues.
Writing Ncstcd Subqucrics
You cun nest subqueres nsde other subqueres to u depth ol 255. You shoud use ths technque
spurngyyou muy lnd your query perlorms better usng tube ons. 1he loowng exumpe
contuns u nested subquery, notce thut t s contuned wthn u subquery, whch s tsel contuned
n un outer query:
SELECT product_type_id, AVG(price)
FROM products
GROUP BY product_type_id
HAVING AVG(price) <
(SELECT MAX(AVG(price))
FROM products
WHERE product_type_id IN
(SELECT product_id
FROM purchases
WHERE quantity > 1)
GROUP BY product_type_id)
ORDER BY product_type_id;
PRODUCT_TYPE_ID AVG(PRICE)
--------------- ----------
1 24.975
3 13.24
4 13.99
13.49
As you cun see, ths exumpe s qute compex und contuns three queres: u nested subquery,
u subquery, und the outer query. 1hese query purts ure run n thut order. Let's breuk the exumpe
down nto the three purts und exumne the resuts returned. 1he nested subquery s
SELECT product_id
FROM purchases
WHERE quantity > 1
1hs subquery returns the product_id lor the products thut huve been purchused more thun
once. 1he rows returned by ths subquery ure
PRODUCT_ID
----------
2
1
1he subquery thut receves ths output s
SELECT MAX(AVG(price))
FROM products
WHERE product_type_id IN
(... output from the nested subquery ...)
GROUP BY product_type_id
180
Cruce Dutubuse ll SQL
1hs subquery returns the muxmum uveruge prce lor the products returned by the nested
subquery. 1he row returned s
MAX(AVG(PRICE))
---------------
26.22
1hs row s returned to the loowng outer query:
SELECT product_type_id, AVG(price)
FROM products
GROUP BY product_type_id
HAVING AVG(price) <
(... output from the subquery ...)
ORDER BY product_type_id;
1hs query returns the product_type_id und uveruge prce ol products thut ure ess thun
uveruge returned by the subquery. 1he rows returned ure
PRODUCT_TYPE_ID AVG(PRICE)
--------------- ----------
1 24.975
3 13.24
4 13.99
13.49
1hese ure the rows returned by the compete query shown ut the sturt ol ths secton.
Writing UPDATf and DflfTf Statcmcnts
Cuntaining Subqucrics
So lur, you've ony seen subqueres contuned n u SELECT stutement. As you' see n ths
secton, you cun uso put subqueres nsde UPDATE und DELETE stutements.
Writing an UPDATf Statcmcnt Cuntaining a Subqucry
ln un UPDATE stutement, you cun set u coumn to the resut returned by u snge-row subquery.
lor exumpe, the loowng UPDATE stutement sets empoyee r4's suury to the uveruge ol the hgh
suury grudes returned by u subquery:
UPDATE employees
SET salary =
(SELECT AVG(high_salary)
FROM salary_grades)
WHERE employee_id = 4;
1 row updated.
Dong ths ncreuses empoyee r4's suury lrom S500,000 to S625,000 (ths s the uveruge ol
the hgh suures lrom the salary_grades tube).
Chupter 6: Subqueres
181
NOTf
| ,ou cxccu|c |hc UPDATE |a|cmcn|, rcmcmbcr |o cxccu|c a
ROLLBACK |o undo |hc changc. Tha| va,, ,our rcu| v ma|ch
|hoc hovn a|cr n |h boo|.
Writing a DflfTf Statcmcnt Cuntaining a Subqucry
You cun use the rows returned by u subquery n the WHERE cuuse ol u DELETE stutement. lor
exumpe, the loowng DELETE stutement removes the empoyee whose suury s greuter thun
the uveruge ol the hgh suury grudes returned by u subquery:
DELETE FROM employees
WHERE salary >
(SELECT AVG(high_salary)
FROM salary_grades);
1 row deleted.
1hs DELETE stutement removes empoyee rl.
NOTf
| ,ou cxccu|c |hc DELETE |a|cmcn|, rcmcmbcr |o cxccu|c a
ROLLBACK |o undo |hc rcmova o| |hc rov.
Summary
ln ths chupter, you eurned the loowng:
A subquery s u query puced wthn u SELECT, UPDATE, or DELETE stutement.
Snge-row subqueres return zero or one row.
Mutpe-row subqueres return one or more rows.
Mutpe-coumn subqueres return more thun one coumn.
Correuted subqueres relerence one or more coumns n the outer SQL stutement.
Nested subqueres ure subqueres puced wthn unother subquery.
ln the next chupter, you' eurn ubout udvunced queres.
This page intentionally left blank

Advunced Queres
l83
184
Cruce Dutubuse llg SQL
n ths chupter, you w see how to
Lse the set operutors, whch uow you to combne rows returned by two or more queres.
Lse the TRANSLATE() luncton to trunsute churucters n one strng to churucters n
unother strng.
Lse the DECODE() luncton to seurch lor u certun vuue n u set ol vuues.
Lse the CASE expresson to perlorm l-then-ese ogc n SQL.
lerlorm queres on herurchcu dutu.
Lse the ROLLUP und CUBE cuuses to get subtotus und totus lor groups ol rows.
1uke udvuntuge ol the unuytc lunctons, whch perlorm compex cucuutons, such us
lndng the top-seng product type lor euch month, the top suespersons, und so on.
lerlorm nter-row cucuutons wth the MODEL cuuse.
Lse the new Cruce Dutubuse llg PIVOT und UNPIVOT cuuses, whch ure uselu lor
seeng overu trends n urge umounts ol dutu.
Let's punge n und exumne the set operutors.
Using thc Sct Opcraturs
1he set operutors uow you to combne rows returned by two or more queres. 1ube 7-l shows
the lour set operutors.
You must keep n mnd the loowng restrcton when usng u set operutor: Thc numbcr o|
coumn and |hc coumn |,pc rc|urncd b, |hc qucrc mu| ma|ch, a|hough |hc coumn namc
ma, bc d||crcn|.
You' eurn how to use euch ol the set operutors shown n 1ube 7-l shorty, but lrst et's ook
ut the exumpe tubes used n ths secton.

Opcratur Dcscriptiun
UNION ALL
Returns u the rows retreved by the queres, ncudng dupcute rows.
UNION
Returns u non-dupcute rows retreved by the queres.
INTERSECT
Returns rows thut ure retreved by both queres.
MINUS
Returns the remunng rows when the rows retreved by the second
query ure subtructed lrom the rows retreved by the lrst query.
TABlf 7-1 Sc| Cpcra|or
Chupter 7: Advunced Queres
18S
Thc fxampIc TabIcs
1he products und more_products tubes ure creuted by the store_schema.sql scrpt
usng the loowng stutements:
CREATE TABLE products (
product_id INTEGER
CONSTRAINT products_pk PRIMARY KEY,
product_type_id INTEGER
CONSTRAINT products_fk_product_types
REFERENCES product_types(product_type_id),
name VARCHAR2(30) NOT NULL,
description VARCHAR2(50),
price NUMBER(5, 2)
);
CREATE TABLE more_products (
prd_id INTEGER
CONSTRAINT more_products_pk PRIMARY KEY,
prd_type_id INTEGER
CONSTRAINT more_products_fk_product_types
REFERENCES product_types(product_type_id),
name VARCHAR2(30) NOT NULL,
available CHAR(1)
);
1he loowng query retreves the product_id, product_type_id, und name coumns
lrom the products tube:
SELECT product_id, product_type_id, name
FROM 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
1he next query retreves the prd_id, prd_type_id, und name coumns lrom the more_
products tube:
SELECT prd_id, prd_type_id, name
FROM more_products;
186
Cruce Dutubuse ll SQL
PRD_ID PRD_TYPE_ID NAME
---------- ----------- --------------
1 1 Modern Science
2 1 Chemistry
3 Supernova
4 2 Lunar Landing
5 2 Submarine
Using thc UNlON All Opcratur
1he UNION ALL operutor returns u the rows retreved by the queres, ncudng dupcute rows.
1he loowng query uses UNION ALL, notce thut u the rows lrom products und more_
products ure retreved, ncudng dupcutes:
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
17 rows selected.
You cun sort the rows usng the ORDER BY cuuse loowed by the poston ol the coumn.
1he loowng exumpe uses ORDER BY 1 to sort the rows by the lrst coumn retreved by the
two queres (product_id und prd_id):
SELECT product_id, product_type_id, name
FROM products
UNION ALL
SELECT prd_id, prd_type_id, name
FROM more_products
ORDER BY 1;
Chupter 7: Advunced Queres
187
PRODUCT_ID PRODUCT_TYPE_ID NAME
---------- --------------- -------------------
1 1 Modern Science
1 1 Modern Science
2 1 Chemistry
2 1 Chemistry
3 2 Supernova
3 Supernova
4 2 Tank War
4 2 Lunar Landing
5 2 Z Files
5 2 Submarine
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
17 rows selected.
Using thc UNlON Opcratur
1he UNION operutor returns ony the non-dupcute rows retreved by the queres. 1he loowng
exumpe uses UNION, notce the dupcute Modern Scence und Chemstry rows ure not
retreved, und so ony l5 rows ure returned:
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
15 rows selected.
188
Cruce Dutubuse ll SQL
Using thc lNTfRSfCT Opcratur
1he INTERSECT operutor returns ony rows thut ure retreved by both queres. 1he loowng
exumpe uses INTERSECT, notce thut the Modern Scence und Chemstry rows ure returned:
SELECT product_id, product_type_id, name
FROM products
INTERSECT
SELECT prd_id, prd_type_id, name
FROM more_products;
PRODUCT_ID PRODUCT_TYPE_ID NAME
---------- --------------- --------------
1 1 Modern Science
2 1 Chemistry
Using thc MlNUS Opcratur
1he MINUS operutor returns the remunng rows when the rows retreved by the second query ure
subtructed lrom the rows retreved by the lrst query. 1he loowng exumpe uses MINUS, notce
thut the rows lrom more_products ure subtructed lrom products und the remunng rows ure
returned:
SELECT product_id, product_type_id, name
FROM products
MINUS
SELECT prd_id, prd_type_id, name
FROM more_products;
PRODUCT_ID PRODUCT_TYPE_ID NAME
---------- --------------- -------------------
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
10 rows selected.
Cumbining Sct Opcraturs
You cun combne more thun two queres wth mutpe set operutors, wth the returned resuts
lrom one operutor leedng nto the next operutor. y deluut, set operutors ure evuuuted lrom
top to bottom, but you shoud ndcute the order usng purentheses n cuse Cruce Corporuton
chunges ths deluut behuvor n luture soltwure reeuses.
ln the exumpes n ths secton, l' use the loowng product_changes tube (creuted by
the store_schema.sql scrpt):
Chupter 7: Advunced Queres

CREATE TABLE product_changes (


product_id INTEGER
CONSTRAINT prod_changes_pk PRIMARY KEY,
product_type_id INTEGER
CONSTRAINT prod_changes_fk_product_types
REFERENCES product_types(product_type_id),
name VARCHAR2(30) NOT NULL,
description VARCHAR2(50),
price NUMBER(5, 2)
);
1he loowng query returns the product_id, product_type_id, und name coumns lrom
the product_changes tube:
SELECT product_id, product_type_id, name
FROM product_changes;
PRODUCT_ID PRODUCT_TYPE_ID NAME
---------- --------------- --------------
1 1 Modern Science
2 1 New Chemistry
3 1 Supernova
13 2 Lunar Landing
14 2 Submarine
15 2 Airplane
1he next query does the loowng:
Lses the UNION operutor to combne the resuts lrom the products und more_products
tubes. (1he UNION operutor returns ony the non-dupcute rows retreved by the queres.)
Lses the INTERSECT operutor to combne the resuts lrom the prevous UNION operutor
wth the resuts lrom the product_changes tube. (1he INTERSECT operutor ony returns
rows thut ure retreved by both queres.)
Lses purentheses to ndcute the order ol evuuuton, whch s: (l) the UNION between
the products und more_products tubes, (2) the INTERSECT.
(SELECT product_id, product_type_id, name
FROM products
UNION
SELECT prd_id, prd_type_id, name
FROM more_products)
INTERSECT
SELECT product_id, product_type_id, name
FROM product_changes;
PRODUCT_ID PRODUCT_TYPE_ID NAME
---------- --------------- --------------
1 1 Modern Science
190
Cruce Dutubuse ll SQL
1he loowng query hus the purentheses set so thut the INTERSECT s perlormed lrst, notce
the dllerent resuts returned by the query compured wth the prevous exumpe:
SELECT product_id, product_type_id, name
FROM products
UNION
(SELECT prd_id, prd_type_id, name
FROM more_products
INTERSECT
SELECT product_id, product_type_id, name
FROM product_changes);
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
1hs concudes the dscusson ol the set operutors.
Using thc TRANSlATf() functiun
TRANSLATE(x, from_string, to_string) converts the occurrences ol churucters n from_
string lound n x to correspondng churucters n to_string. 1he eusest wuy to understund
how TRANSLATE() works s to see some exumpes.
1he loowng exumpe uses TRANSLATE() to shlt euch churucter n the strng SECRET
MESSAGE: MEET ME IN THE PARK by lour puces to the rght: A becomes L, becomes l,
und so on:
SELECT TRANSLATE('SECRET MESSAGE: MEET ME IN THE PARK',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'EFGHIJKLMNOPQRSTUVWXYZABCD')
FROM dual;
TRANSLATE('SECRETMESSAGE:MEETMEINTH
-----------------------------------
WIGVIX QIWWEKI: QIIX QI MR XLI TEVO
1he next exumpe tukes the output ol the prevous exumpe und shlts the churucters lour
puces to the elt: L becomes A, l becomes , und so on:
SELECT TRANSLATE('WIGVIX QIWWEKI: QIIX QI MR XLI TEVO',
'EFGHIJKLMNOPQRSTUVWXYZABCD',
Chupter 7: Advunced Queres
191
'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
FROM dual;
TRANSLATE('WIGVIXQIWWEKI:QIIXQIMRXL
-----------------------------------
SECRET MESSAGE: MEET ME IN THE PARK
You cun ol course puss coumn vuues to TRANSLATE(). 1he loowng exumpe pusses the
name coumn lrom the products tube to TRANSLATE(), whch shlts the etters n the product
nume lour puces to the rght:
SELECT product_id, TRANSLATE(name,
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
'EFGHIJKLMNOPQRSTUVWXYZABCDefghijklmnopqrstuvwxyzabcd')
FROM products;
PRODUCT_ID TRANSLATE(NAME,'ABCDEFGHIJKLMN
---------- ------------------------------
1 Qshivr Wgmirgi
2 Gliqmwxvc
3 Wytivrsze
4 Xero Aev
5 D Jmpiw
6 2412: Xli Vixyvr
7 Wtegi Jsvgi 9
8 Jvsq Ersxliv Tperix
9 Gpewwmgep Qywmg
10 Tst 3
11 Gviexmzi Cipp
12 Qc Jvsrx Pmri
You cun uso use TRANSLATE() to convert numbers. 1he loowng exumpe tukes the
number l2345 und converts 5 to 6, 4 to 7, 3 to 8, 2 to 9, und l to 0:
SELECT TRANSLATE(12345,
54321,
67890)
FROM dual;
TRANS
-----
09876
Using thc DfCODf() functiun
DECODE(value, search_value, result, default_value) compures value wth
search_value. ll the vuues ure equu, DECODE() returns result, otherwse, default_
value s returned. DECODE() uows you to perlorm l-then-ese ogc n SQL wthout huvng
to use lL/SQL. Luch ol the purumeters to DECODE() cun be u coumn, u teru vuue, u luncton,
or u subquery.

Cruce Dutubuse llg SQL

DECODE() an od Cracc proprc|ar, |unc|on, and |hcrc|orc ,ou


houd uc CASE cxprcon n|cad | ,ou arc ung Cracc Da|abac
9 and abovc (,ou v carn abou| CASE n |hc ncx| cc|on). Thc
DECODE() |unc|on mcn|oncd hcrc bccauc ,ou ma, cncoun|cr
| vhcn ung odcr Cracc da|abac.
1he loowng exumpe ustrutes the use ol DECODE() wth teru vuues, DECODE() returns
2 (l s compured wth l, und becuuse they ure equu 2 s returned):
SELECT DECODE(1, 1, 2, 3)
FROM dual;
DECODE(1,1,2,3)
---------------
2
1he next exumpe uses DECODE() to compure l to 2, und becuuse they ure not equu 3 s
returned:
SELECT DECODE(1, 2, 1, 3)
FROM dual;
DECODE(1,2,1,3)
---------------
3
1he next exumpe compures the available coumn n the more_products tube, l
available equus Y, the strng 'Product is available' s returned, otherwse, 'Product
is not available' s returned:
SELECT prd_id, available,
DECODE(available, 'Y', 'Product is available',
'Product is not available')
FROM more_products;
PRD_ID A DECODE(AVAILABLE,'Y','PR
---------- - ------------------------
1 Y Product is available
2 Y Product is available
3 N Product is not available
4 N Product is not available
5 Y Product is available
You cun puss mutpe seurch und resut purumeters to DECODE(), us shown n the loowng
exumpe, whch returns the product_type_id coumn us the nume ol the product type:
SELECT product_id, product_type_id,
DECODE(product_type_id,
1, 'Book',
2, 'Video',
3, 'DVD',
4, 'CD',
'Magazine')
Chupter 7: Advunced Queres
193
FROM products;
PRODUCT_ID PRODUCT_TYPE_ID DECODE(P
---------- --------------- --------
1 1 Book
2 1 Book
3 2 Video
4 2 Video
5 2 Video
6 2 Video
7 3 DVD
8 3 DVD
9 4 CD
10 4 CD
11 4 CD
12 Magazine
Notce thut
ll product_type_id s l, Book s returned.
ll product_type_id s 2, Video s returned.
ll product_type_id s 3, DVD s returned.
ll product_type_id s 4, CD s returned.
ll product_type_id s uny other vuue, Magazine s returned.
Using thc CASf fxprcssiun
1he CASE expresson perlorms l-then-ese ogc n SQL und s supported n Cruce Dutubuse 9
und ubove. 1he CASE expresson works n u smur munner to DECODE(), but you shoud use
CASE becuuse t s ANSl-compunt und lorms purt ol the SQL/92 stundurd. ln uddton, the CASE
expresson s euser to reud.
1here ure two types ol CASE expressons:
Smpe cuse expressons, whch use expressons to determne the returned vuue
Seurched cuse expressons, whch use condtons to determne the returned vuue
You' eurn ubout both ol these types ol CASE expressons next.
Using SimpIc CASf fxprcssiuns
Smpe CASE expressons use embedded expressons to determne the vuue to return. Smpe
CASE expressons huve the loowng syntux:
CASE search_expression
WHEN expression1 THEN result1
WHEN expression2 THEN result2
...
WHEN expressionN THEN resultN
ELSE default_result
END
194
Cruce Dutubuse ll SQL
where
search_expression s the expresson to be evuuuted.
expression1, expression2, ..., expressionN ure the expressons to be
evuuuted ugunst search_expression.
result1, result2, ..., resultN ure the returned resuts (one lor euch possbe
expresson). ll expression1 evuuutes to search_expression, result1 s
returned, und smury lor the other expressons.
default_result s returned when no mutchng expresson s lound.
1he loowng exumpe shows u smpe CASE expresson thut returns the product types us
numes:
SELECT product_id, product_type_id,
CASE product_type_id
WHEN 1 THEN 'Book'
WHEN 2 THEN 'Video'
WHEN 3 THEN 'DVD'
WHEN 4 THEN 'CD'
ELSE 'Magazine'
END
FROM products;
PRODUCT_ID PRODUCT_TYPE_ID CASEPROD
---------- --------------- --------
1 1 Book
2 1 Book
3 2 Video
4 2 Video
5 2 Video
6 2 Video
7 3 DVD
8 3 DVD
9 4 CD
10 4 CD
11 4 CD
12 Magazine
Using Scarchcd CASf fxprcssiuns
Seurched CASE expressons use condtons to determne the returned vuue. Seurched CASE
expressons huve the loowng syntux:
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
...
WHEN conditionN THEN resultN
ELSE default_result
END
Chupter 7: Advunced Queres

where
condition1, condition2, ..., conditionN ure the expressons to be evuuuted.
result1, result2, ..., resultN ure the returned resuts (one lor euch possbe
condton). ll condition1 s true, result1 s returned, und smury lor the other
expressons.
default_result s returned when there s no condton thut returns true.
1he loowng exumpe ustrutes the use ol u seurched CASE expresson:
SELECT product_id, product_type_id,
CASE
WHEN product_type_id = 1 THEN 'Book'
WHEN product_type_id = 2 THEN 'Video'
WHEN product_type_id = 3 THEN 'DVD'
WHEN product_type_id = 4 THEN 'CD'
ELSE 'Magazine'
END
FROM products;
PRODUCT_ID PRODUCT_TYPE_ID CASEPROD
---------- --------------- --------
1 1 Book
2 1 Book
3 2 Video
4 2 Video
5 2 Video
6 2 Video
7 3 DVD
8 3 DVD
9 4 CD
10 4 CD
11 4 CD
12 Magazine
You cun use operutors n u seurched CASE expresson, us shown n the loowng exumpe:
SELECT product_id, price,
CASE
WHEN price > 15 THEN 'Expensive'
ELSE 'Cheap'
END
FROM products;
PRODUCT_ID PRICE CASEWHENP
---------- ---------- ---------
1 19.95 Expensive
2 30 Expensive
3 25.99 Expensive
4 13.95 Cheap
5 49.99 Expensive
196
Cruce Dutubuse ll SQL
6 14.95 Cheap
7 13.49 Cheap
8 12.99 Cheap
9 10.99 Cheap
10 15.99 Expensive
11 14.99 Cheap
12 13.49 Cheap
You w see more udvunced exumpes ol CASE expressons uter n ths chupter und n
Chupter l6.
HicrarchicaI Qucrics
You' qute olten encounter dutu thut s orgunzed n u herurchcu munner. Lxumpes ncude
the peope who work n u compuny, u lumy tree, und the purts thut muke up un engne. ln ths
secton, you' see queres thut uccess u herurchy ol empoyees who work lor our mugnury store.
Thc fxampIc Data
You' see the use ol u tube numed more_employees, whch s creuted by the store_
schema.sql scrpt us loows:
CREATE TABLE more_employees (
employee_id INTEGER
CONSTRAINT more_employees_pk PRIMARY KEY,
manager_id INTEGER
CONSTRAINT more_empl_fk_fk_more_empl
REFERENCES more_employees(employee_id),
first_name VARCHAR2(10) NOT NULL,
last_name VARCHAR2(10) NOT NULL,
title VARCHAR2(20),
salary NUMBER(6, 0)
);
1he manager_id coumn s u sel-relerence buck to the employee_id coumn ol the
more_employees tube, manager_id ndcutes the munuger ol un empoyee (l uny). 1he
loowng query returns the rows lrom more_employees:
SELECT *
FROM more_employees;
EMPLOYEE_ID MANAGER_ID FIRST_NAME LAST_NAME TITLE SALARY
----------- ---------- ---------- ---------- ------------- ----------
1 James Smith CEO 800000
2 1 Ron Johnson Sales Manager 600000
3 2 Fred Hobbs Sales Person 200000
4 1 Susan Jones Support Manager 500000
5 2 Rob Green Sales Person 40000
6 4 Jane Brown Support Person 45000
7 4 John Grey Support Manager 30000
8 7 Jean Blue Support Person 29000
Chupter 7: Advunced Queres
197
9 6 Henry Heyson Support Person 30000
10 1 Kevin Black Ops Manager 100000
11 10 Keith Long Ops Person 50000
12 10 Frank Howard Ops Person 45000
13 10 Doreen Penn Ops Person 47000
As you cun see, t's dllcut to pck out the empoyee reutonshps lrom ths dutu. lgure 7-l
shows the reutonshps n u gruphcu lorm.
As you cun see lrom lgure 7-l, the eementsor nodclorm u tree. 1rees ol nodes huve the
loowng techncu terms ussocuted wth them:
Ruut nudc 1he root s the node ut the top ol the tree. ln the exumpe shown n
lgure 7-l, the root node s }umes Smth, the CLC.
Parcnt nudc A purent s u node thut hus one or more nodes beneuth t. lor exumpe,
}umes Smth s the purent to the loowng nodes: Ron }ohnson, Susun }ones, und
Kevn uck.
ChiId nudc A chd s u node thut hus one purent node ubove t. lor exumpe,
Ron }ohnson's purent s }umes Smth.
lcaf nudc A eul s u node thut hus no chdren. lor exumpe, lred Hobbs und
Rob Creen ure eul nodes.
You use the CONNECT BY und START WITH cuuses ol u SELECT stutement to perlorm
herurchcu queres, us descrbed next.
flGURf 7-1 mpo,cc rca|onhp
198
Cruce Dutubuse ll SQL
Using thc CONNfCT BY and START WlTH CIauscs
1he syntux lor the CONNECT BY und START WITH cuuses ol u SELECT stutement s
SELECT [LEVEL], column, expression, ...
FROM table
[WHERE where_clause]
[[START WITH start_condition] [CONNECT BY PRIOR prior_condition]];
where
LEVEL s u pseudo coumn thut tes you how lur nto u tree you ure. LEVEL returns l lor
u root node, 2 lor u chd ol the root, und so on.
start_condition specles where to sturt the herurchcu query. You must specly u
START WITH cuuse when wrtng u herurchcu query. An exumpe start_condition
s employee_id = 1, whch specles the query sturts lrom empoyee rl.
prior_condition specles the reutonshp between the purent und chd rows. You
must specly u CONNECT BY PRIOR cuuse when wrtng u herurchcu query. An
exumpe prior_condition s employee_id = manager_id, whch specles the
reutonshp s between the purent employee_id und the chd manager_idthut s,
the chd's manager_id ponts to the purent's employee_id.
1he loowng query ustrutes the use ol the START WITH und CONNECT BY PRIOR
cuuses, notce thut the lrst row contuns the detus ol }umes Smth (empoyee rl), the second
row contuns the detus ol Ron }ohnson, whose manager_id s l, und so on:
SELECT employee_id, manager_id, first_name, last_name
FROM more_employees
START WITH employee_id = 1
CONNECT BY PRIOR employee_id = manager_id;
EMPLOYEE_ID MANAGER_ID FIRST_NAME LAST_NAME
----------- ---------- ---------- ---------
1 James Smith
2 1 Ron Johnson
3 2 Fred Hobbs
5 2 Rob Green
4 1 Susan Jones
6 4 Jane Brown
9 6 Henry Heyson
7 4 John Grey
8 7 Jean Blue
10 1 Kevin Black
11 10 Keith Long
12 10 Frank Howard
13 10 Doreen Penn
Using thc lfVfl Pscudu CuIumn
1he next query ustrutes the use ol the LEVEL pseudo coumn to dspuy the eve n the tree:
Chupter 7: Advunced Queres
199
SELECT LEVEL, employee_id, manager_id, first_name, last_name
FROM more_employees
START WITH employee_id = 1
CONNECT BY PRIOR employee_id = manager_id
ORDER BY LEVEL;
LEVEL EMPLOYEE_ID MANAGER_ID FIRST_NAME LAST_NAME
---------- ----------- ---------- ---------- ---------
1 1 James Smith
2 2 1 Ron Johnson
2 4 1 Susan Jones
2 10 1 Kevin Black
3 3 2 Fred Hobbs
3 7 4 John Grey
3 12 10 Frank Howard
3 13 10 Doreen Penn
3 11 10 Keith Long
3 5 2 Rob Green
3 6 4 Jane Brown
4 9 6 Henry Heyson
4 8 7 Jean Blue
1he next query uses the COUNT() luncton und LEVEL to get the number ol eves n the tree:
SELECT COUNT(DISTINCT LEVEL)
FROM more_employees
START WITH employee_id = 1
CONNECT BY PRIOR employee_id = manager_id;
COUNT(DISTINCTLEVEL)
--------------------
4
furmatting thc RcsuIts frum a HicrarchicaI Qucry
You cun lormut the resuts lrom u herurchcu query usng LEVEL und the LPAD() luncton,
whch elt-puds vuues wth churucters. 1he loowng query uses LPAD(' ', 2 * LEVEL -
1) to elt-pud u totu ol 2 * LEVEL - 1 spuces, the resut ndents un empoyee's nume wth
spuces bused on ther LEVEL (thut s, LEVEL 1 sn't pudded, LEVEL 2 s pudded by two spuces,
LEVEL 3 by lour spuces, und so on):
SET PAGESIZE 999
COLUMN employee FORMAT A25
SELECT LEVEL,
LPAD(' ', 2 * LEVEL - 1) || first_name || ' ' || last_name AS employee
FROM more_employees
START WITH employee_id = 1
CONNECT BY PRIOR employee_id = manager_id;
LEVEL EMPLOYEE
---------- ------------------
1 James Smith
2 Ron Johnson
200
Cruce Dutubuse ll SQL
3 Fred Hobbs
3 Rob Green
2 Susan Jones
3 Jane Brown
4 Henry Heyson
3 John Grey
4 Jean Blue
2 Kevin Black
3 Keith Long
3 Frank Howard
3 Doreen Penn
1he empoyee reutonshps ure eusy to pck out lrom these resuts.
Starting at a Nudc Othcr than thc Ruut
You don't huve to sturt ut the root node when truversng u tree: you cun sturt ut uny node usng the
START WITH cuuse. 1he loowng query sturts wth Susun }ones, notce thut LEVEL returns l lor
Susun }ones, 2 lor }une rown, und so on:
SELECT LEVEL,
LPAD(' ', 2 * LEVEL - 1) || first_name || ' ' || last_name AS employee
FROM more_employees
START WITH last_name = 'Jones'
CONNECT BY PRIOR employee_id = manager_id;
LEVEL EMPLOYEE
---------- -----------------
1 Susan Jones
2 Jane Brown
3 Henry Heyson
2 John Grey
3 Jean Blue
ll the store hud more thun one empoyee wth the sume nume, you coud smpy use the
employee_id n the query's START WITH cuuse. lor exumpe, the loowng query uses Susun
}ones' employee_id ol 4:
SELECT LEVEL,
LPAD(' ', 2 * LEVEL - 1) || first_name || ' ' || last_name AS employee
FROM more_employees
START WITH employee_id = 4
CONNECT BY PRIOR employee_id = manager_id;
1hs query returns the sume rows us the prevous one.
Using a Subqucry in a START WlTH CIausc
You cun use u subquery n u START WITH cuuse. lor exumpe, the loowng query uses u
subquery to seect the employee_id whose nume s Kevn uck, ths employee_id s pussed
to the START WITH cuuse:
SELECT LEVEL,
LPAD(' ', 2 * LEVEL - 1) || first_name || ' ' || last_name AS employee
Chupter 7: Advunced Queres
201
FROM more_employees
START WITH employee_id = (
SELECT employee_id
FROM more_employees
WHERE first_name = 'Kevin'
AND last_name = 'Black'
)
CONNECT BY PRIOR employee_id = manager_id;
LEVEL EMPLOYEE
---------- ---------------
1 Kevin Black
2 Keith Long
2 Frank Howard
2 Doreen Penn
Travcrsing Upward Thruugh thc Trcc
You don't huve to truverse u tree downwurd lrom purents to chdren: you cun sturt ut u chd und
truverse upwurd. You do ths by swtchng chd und purent coumns n the CONNECT BY PRIOR
cuuse. lor exumpe, CONNECT BY PRIOR manager_id = employee_id connects the
chd's manager_id to the purent's employee_id.
1he loowng query sturts wth }eun ue und truverses upwurd u the wuy to }umes Smth,
notce thut LEVEL returns l lor }eun ue, 2 lor }ohn Crey, und so on:
SELECT LEVEL,
LPAD(' ', 2 * LEVEL - 1) || first_name || ' ' || last_name AS employee
FROM more_employees
START WITH last_name = 'Blue'
CONNECT BY PRIOR manager_id = employee_id;
LEVEL EMPLOYEE
---------- ------------------
1 Jean Blue
2 John Grey
3 Susan Jones
4 James Smith
fIiminating Nudcs and Branchcs frum a HicrarchicaI Qucry
You cun emnute u purtcuur node lrom u query tree usng u WHERE cuuse. 1he loowng query
emnutes Ron }ohnson lrom the resuts usng WHERE last_name != 'Johnson':
SELECT LEVEL,
LPAD(' ', 2 * LEVEL - 1) || first_name || ' ' || last_name AS employee
FROM more_employees
WHERE last_name != 'Johnson'
START WITH employee_id = 1
CONNECT BY PRIOR employee_id = manager_id;
LEVEL EMPLOYEE
---------- ------------------
1 James Smith
3 Fred Hobbs
202
Cruce Dutubuse ll SQL
3 Rob Green
2 Susan Jones
3 Jane Brown
4 Henry Heyson
3 John Grey
4 Jean Blue
2 Kevin Black
3 Keith Long
3 Frank Howard
3 Doreen Penn
You' notce thut uthough Ron }ohnson s emnuted lrom the resuts, hs empoyees lred
Hobbs und Rob Creen ure st ncuded. 1o emnute un entre brunch ol nodes lrom the resuts
ol u query, you udd un AND cuuse to your CONNECT BY PRIOR cuuse. lor exumpe, the
loowng query uses AND last_name != 'Johnson' to emnute Ron }ohnson und u hs
empoyees lrom the resuts:
SELECT LEVEL,
LPAD(' ', 2 * LEVEL - 1) || first_name || ' ' || last_name AS employee
FROM more_employees
START WITH employee_id = 1
CONNECT BY PRIOR employee_id = manager_id
AND last_name != 'Johnson';
LEVEL EMPLOYEE
---------- -------------------
1 James Smith
2 Susan Jones
3 Jane Brown
4 Henry Heyson
3 John Grey
4 Jean Blue
2 Kevin Black
3 Keith Long
3 Frank Howard
3 Doreen Penn
lncIuding Othcr Cunditiuns in a HicrarchicaI Qucry
You cun ncude other condtons n u herurchcu query usng u WHERE cuuse. 1he loowng
exumpe uses u WHERE cuuse to show ony empoyees whose suures ure ess thun or equu
to S50,000:
SELECT LEVEL,
LPAD(' ', 2 * LEVEL - 1) || first_name || ' ' || last_name AS employee,
salary
FROM more_employees
WHERE salary <= 50000
START WITH employee_id = 1
CONNECT BY PRIOR employee_id = manager_id;
Chupter 7: Advunced Queres
203
LEVEL EMPLOYEE SALARY
---------- ------------------------- ----------
3 Rob Green 40000
3 Jane Brown 45000
4 Henry Heyson 30000
3 John Grey 30000
4 Jean Blue 29000
3 Keith Long 50000
3 Frank Howard 45000
3 Doreen Penn 47000
1hs concudes the dscusson ol herurchcu queres. ln the next secton, you' eurn ubout
udvunced group cuuses.
Using thc fxtcndcd GROUP BY CIauscs
ln ths secton, you' eurn ubout
ROLLUP, whch extends the GROUP BY cuuse to return u row contunng u subtotu lor
euch group ol rows, pus u row contunng u grund totu lor u the groups.
CUBE, whch extends the GROUP BY cuuse to return rows contunng u subtotu lor u
combnutons ol coumns, pus u row contunng the grund totu.
lrst, et's ook ut the exumpe tubes used n ths secton.
Thc fxampIc TabIcs
You' see the use ol the loowng tubes thut relne the representuton ol empoyees n our
mugnury store:
divisions, whch stores the dvsons wthn the compuny
jobs, whch stores the obs wthn the compuny
employees2, whch stores the empoyees
1hese tubes ure creuted by the store_schema.sql scrpt. 1he divisions tube s creuted
usng the loowng stutement:
CREATE TABLE divisions (
division_id CHAR(3)
CONSTRAINT divisions_pk PRIMARY KEY,
name VARCHAR2(15) NOT NULL
);
1he loowng query retreves the rows lrom the divisions tube:
SELECT *
FROM divisions;
DIV NAME
--- ----------
SAL Sales

Cruce Dutubuse ll SQL
OPE Operations
SUP Support
BUS Business
1he jobs tube s creuted usng the loowng stutement:
CREATE TABLE jobs (
job_id CHAR(3)
CONSTRAINT jobs_pk PRIMARY KEY,
name VARCHAR2(20) NOT NULL
);
1he next query retreves the rows lrom the jobs tube:
SELECT *
FROM jobs;
JOB NAME
--- ------------
WOR Worker
MGR Manager
ENG Engineer
TEC Technologist
PRE President
1he employees2 tube s creuted usng the loowng stutement:
CREATE TABLE employees2 (
employee_id INTEGER
CONSTRAINT employees2_pk PRIMARY KEY,
division_id CHAR(3)
CONSTRAINT employees2_fk_divisions
REFERENCES divisions(division_id),
job_id CHAR(3) REFERENCES jobs(job_id),
first_name VARCHAR2(10) NOT NULL,
last_name VARCHAR2(10) NOT NULL,
salary NUMBER(6, 0)
);
1he loowng query retreves the lrst lve rows lrom the employees2 tube:
SELECT *
FROM employees2
WHERE ROWNUM <= 5;
EMPLOYEE_ID DIV JOB FIRST_NAME LAST_NAME SALARY
----------- --- --- ---------- ---------- ----------
1 BUS PRE James Smith 800000
2 SAL MGR Ron Johnson 350000
3 SAL WOR Fred Hobbs 140000
4 SUP MGR Susan Jones 200000
5 SAL WOR Rob Green 350000
Chupter 7: Advunced Queres
20S
Using thc ROllUP CIausc
1he ROLLUP cuuse extends GROUP BY to return u row contunng u subtotu lor euch group ol
rows, pus u row contunng u totu lor u the groups.
As you suw n Chupter 4, you use GROUP BY to group rows nto bocks wth u common
coumn vuue. lor exumpe, the loowng query uses GROUP BY to group the rows lrom the
employees2 tube by department_id und uses SUM() to get the sum ol the suures lor euch
division_id:
SELECT division_id, SUM(salary)
FROM employees2
GROUP BY division_id
ORDER BY division_id;
DIV SUM(SALARY)
--- -----------
BUS 1610000
OPE 1320000
SAL 4936000
SUP 1015000
Passing a SingIc CuIumn tu ROllUP
1he loowng query rewrtes the prevous exumpe to use ROLLUP, notce the uddtonu row ut
the end, whch contuns the totu suures lor u the groups:
SELECT division_id, SUM(salary)
FROM employees2
GROUP BY ROLLUP(division_id)
ORDER BY division_id;
DIV SUM(SALARY)
--- -----------
BUS 1610000
OPE 1320000
SAL 4936000
SUP 1015000
8881000
NOTf
| ,ou nccd |hc rov n a pcc|c ordcr, ,ou houd uc an ORDER BY
cauc. You nccd |o do |h ]u| n cac Cracc Corpora|on dccdc |o
changc |hc dc|au| ordcr o| rov rc|urncd b, ROLLUP.
Passing MuItipIc CuIumns tu ROllUP
You cun puss mutpe coumns to ROLLUP, whch then groups the rows nto bocks wth the sume
coumn vuues. 1he loowng exumpe pusses the division_id und job_id coumns ol the
employees2 tube to ROLLUP, whch groups the rows by those coumns, n the output, notce
thut the suures ure summed by division_id und job_id, und thut ROLLUP returns u row
206
Cruce Dutubuse ll SQL
wth the sum ol the suures n euch division_id, pus u row ut the end wth the suury
grund totu:
SELECT division_id, job_id, SUM(salary)
FROM employees2
GROUP BY ROLLUP(division_id, job_id)
ORDER BY division_id, job_id;
DIV JOB SUM(SALARY)
--- --- -----------
BUS MGR 530000
BUS PRE 800000
BUS WOR 280000
BUS 1610000
OPE ENG 245000
OPE MGR 805000
OPE WOR 270000
OPE 1320000
SAL MGR 4446000
SAL WOR 490000
SAL 4936000
SUP MGR 465000
SUP TEC 115000
SUP WOR 435000
SUP 1015000
8881000
Changing thc Pusitiun uf CuIumns Passcd tu ROllUP
1he next exumpe swtches division_id und job_id, ths cuuses ROLLUP to cucuute the sum
ol the suures lor euch job_id:
SELECT job_id, division_id, SUM(salary)
FROM employees2
GROUP BY ROLLUP(job_id, division_id)
ORDER BY job_id, division_id;
JOB DIV SUM(SALARY)
--- --- -----------
ENG OPE 245000
ENG 245000
MGR BUS 530000
MGR OPE 805000
MGR SAL 4446000
MGR SUP 465000
MGR 6246000
PRE BUS 800000
PRE 800000
TEC SUP 115000
TEC 115000
WOR BUS 280000
WOR OPE 270000
Chupter 7: Advunced Queres
207
WOR SAL 490000
WOR SUP 435000
WOR 1475000
8881000
Using Othcr Aggrcgatc functiuns with ROllUP
You cun use uny ol the uggregute lunctons wth ROLLUP (lor u st ol the mun uggregute
lunctons, see 1ube 4-8 n Chupter 4). 1he loowng exumpe uses AVG() to cucuute the
uveruge suures:
SELECT division_id, job_id, AVG(salary)
FROM employees2
GROUP BY ROLLUP(division_id, job_id)
ORDER BY division_id, job_id;
DIV JOB AVG(SALARY)
--- --- -----------
BUS MGR 176666.667
BUS PRE 800000
BUS WOR 280000
BUS 322000
OPE ENG 245000
OPE MGR 201250
OPE WOR 135000
OPE 188571.429
SAL MGR 261529.412
SAL WOR 245000
SAL 259789.474
SUP MGR 232500
SUP TEC 115000
SUP WOR 145000
SUP 169166.667
240027.027
Using thc CUBf CIausc
1he CUBE cuuse extends GROUP BY to return rows contunng u subtotu lor u combnutons
ol coumns, pus u row contunng the grund totu. 1he loowng exumpe pusses division_id
und job_id to CUBE, whch groups the rows by those coumns:
SELECT division_id, job_id, SUM(salary)
FROM employees2
GROUP BY CUBE(division_id, job_id)
ORDER BY division_id, job_id;
DIV JOB SUM(SALARY)
--- --- -----------
BUS MGR 530000
BUS PRE 800000
BUS WOR 280000
BUS 1610000

Cruce Dutubuse ll SQL
OPE ENG 245000
OPE MGR 805000
OPE WOR 270000
OPE 1320000
SAL MGR 4446000
SAL WOR 490000
SAL 4936000
SUP MGR 465000
SUP TEC 115000
SUP WOR 435000
SUP 1015000
ENG 245000
MGR 6246000
PRE 800000
TEC 115000
WOR 1475000
8881000
Notce thut the suures ure summed by division_id und job_id. CUBE returns u row wth
the sum ol the suures lor euch division_id, uong wth the sum ol u suures lor euch job_
id neur the end. At the very end s u row wth the grund totu ol the suures.
1he next exumpe swtches division_id und job_id:
SELECT job_id, division_id, SUM(salary)
FROM employees2
GROUP BY CUBE(job_id, division_id)
ORDER BY job_id, division_id;
JOB DIV SUM(SALARY)
--- --- -----------
ENG OPE 245000
ENG 245000
MGR BUS 530000
MGR OPE 805000
MGR SAL 4446000
MGR SUP 465000
MGR 6246000
PRE BUS 800000
PRE 800000
TEC SUP 115000
TEC 115000
WOR BUS 280000
WOR OPE 270000
WOR SAL 490000
WOR SUP 435000
WOR 1475000
BUS 1610000
OPE 1320000
SAL 4936000
SUP 1015000
8881000
Chupter 7: Advunced Queres
209
Using thc GROUPlNG() functiun
1he GROUPING() luncton uccepts u coumn und returns 0 or l. GROUPING() returns l when
the coumn vuue s nu und returns 0 when the coumn vuue s non-nu. GROUPING() s used
ony n queres thut use ROLLUP or CUBE. GROUPING() s uselu when you wunt to dspuy u
vuue when u nu woud otherwse be returned.
Using GROUPlNG() with a SingIc CuIumn in a ROllUP
As you suw eurer n the secton lussng u Snge Coumn to RCLLLl, the ust row n the
exumpe's resut set contuned u totu ol the suures:
SELECT division_id, SUM(salary)
FROM employees2
GROUP BY ROLLUP(division_id)
ORDER BY division_id;
DIV SUM(SALARY)
--- -----------
BUS 1610000
OPE 1320000
SAL 4936000
SUP 1015000
8881000
1he division_id coumn lor the ust row s nu. You cun use the GROUPING() luncton
to determne whether ths coumn s nu, us shown n the loowng query, notce GROUPING()
returns 0 lor the rows thut huve non-nu division_id vuues und returns l lor the ust row thut
hus u nu division_id:
SELECT GROUPING(division_id), division_id, SUM(salary)
FROM employees2
GROUP BY ROLLUP(division_id)
ORDER BY division_id;
GROUPING(DIVISION_ID) DIV SUM(SALARY)
--------------------- --- -----------
0 BUS 1610000
0 OPE 1320000
0 SAL 4936000
0 SUP 1015000
1 8881000
Using CASf tu Cunvcrt thc Rcturncd VaIuc frum GROUPlNG()
You cun use the CASE expresson to convert the l n the prevous exumpe to u meunnglu vuue.
1he loowng exumpe uses CASE to convert l to the strng 'All divisions':
SELECT
CASE GROUPING(division_id)
WHEN 1 THEN 'All divisions'
ELSE division_id
END AS div,
SUM(salary)
210
Cruce Dutubuse ll SQL
FROM employees2
GROUP BY ROLLUP(division_id)
ORDER BY division_id;
DIV SUM(SALARY)
------------- -----------
BUS 1610000
OPE 1320000
SAL 4936000
SUP 1015000
All divisions 8881000
Using CASf and GROUPlNG() tu Cunvcrt MuItipIc CuIumn VaIucs
1he next exumpe extends the deu ol repucng nu vuues to u ROLLUP contunng mutpe
coumns (division_id und job_id), notce thut nu division_id vuues ure repuced wth
the strng 'All divisions' und thut nu job_id vuues ure repuced wth 'All jobs':
SELECT
CASE GROUPING(division_id)
WHEN 1 THEN 'All divisions'
ELSE division_id
END AS div,
CASE GROUPING(job_id)
WHEN 1 THEN 'All jobs'
ELSE job_id
END AS job,
SUM(salary)
FROM employees2
GROUP BY ROLLUP(division_id, job_id)
ORDER BY division_id, job_id;
DIV JOB SUM(SALARY)
------------- -------- -----------
BUS MGR 530000
BUS PRE 800000
BUS WOR 280000
BUS All jobs 1610000
OPE ENG 245000
OPE MGR 805000
OPE WOR 270000
OPE All jobs 1320000
SAL MGR 4446000
SAL WOR 490000
SAL All jobs 4936000
SUP MGR 465000
SUP TEC 115000
SUP WOR 435000
SUP All jobs 1015000
All divisions All jobs 8881000
Using GROUPlNG() with CUBf
You cun use the GROUPING() luncton wth CUBE, us n ths exumpe:
Chupter 7: Advunced Queres
211
SELECT
CASE GROUPING(division_id)
WHEN 1 THEN 'All divisions'
ELSE division_id
END AS div,
CASE GROUPING(job_id)
WHEN 1 THEN 'All jobs'
ELSE job_id
END AS job,
SUM(salary)
FROM employees2
GROUP BY CUBE(division_id, job_id)
ORDER BY division_id, job_id;
DIV JOB SUM(SALARY)
------------- -------- -----------
BUS MGR 530000
BUS PRE 800000
BUS WOR 280000
BUS All jobs 1610000
OPE ENG 245000
OPE MGR 805000
OPE WOR 270000
OPE All jobs 1320000
SAL MGR 4446000
SAL WOR 490000
SAL All jobs 4936000
SUP MGR 465000
SUP TEC 115000
SUP WOR 435000
SUP All jobs 1015000
All divisions ENG 245000
All divisions MGR 6246000
All divisions PRE 800000
All divisions TEC 115000
All divisions WOR 1475000
All divisions All jobs 8881000
Using thc GROUPlNG SfTS CIausc
You use the GROUPING SETS cuuse to get ust the subtotu rows. 1he loowng exumpe uses
GROUPING SETS to get the subtotus lor suures by division_id und job_id:
SELECT division_id, job_id, SUM(salary)
FROM employees2
GROUP BY GROUPING SETS(division_id, job_id)
ORDER BY division_id, job_id;
DIV JOB SUM(SALARY)
--- --- -----------
BUS 1610000
OPE 1320000
212
Cruce Dutubuse llg SQL
SAL 4936000
SUP 1015000
ENG 245000
MGR 6246000
PRE 800000
TEC 115000
WOR 1475000
Notce thut ony subtotus lor the division_id und job_id coumns ure returned, the totu
lor u suures s not returned. You' see how to get the totu us we us the subtotus usng the
GROUPING_ID() luncton n the next secton.
TlP
Thc GROUPING SETS cauc |,pca, o||cr bc||cr pcr|ormancc |han
CUBE. Thcrc|orc, ,ou houd uc GROUPING SETS ra|hcr |han CUBE
vhcrcvcr pobc.
Using thc GROUPlNG_lD() functiun
You cun use the GROUPING_ID() luncton to lter rows usng u HAVING cuuse to excude rows
thut don't contun u subtotu or totu. 1he GROUPING_ID() luncton uccepts one or more coumns
und returns the decmu equvuent ol the GROUPING bt vector. 1he GROUPING bt vector s
computed by combnng the resuts ol u cu to the GROUPING() luncton lor euch coumn n order.
Cumputing thc GROUPlNG Bit Vcctur
Lurer n the secton Lsng the CRCLllNC() luncton, you suw thut GROUPING() returns l
when the coumn vuue s nu und returns 0 when the coumn vuue s non-nu, lor exumpe:
ll both division_id und job_id ure non-nu, GROUPING() returns 0 lor both
coumns. 1he resut lor division_id s combned wth the resut lor job_id, gvng
u bt vector ol 00, whose decmu equvuent s 0. GROUPING_ID() therelore returns
0 when division_id und job_id ure non-nu.
ll division_id s non-nu (the GROUPING bt s 0), but job_id s nu (the GROUPING
bt s l), the resutng bt vector s 0l und GROUPING_ID() returns l.
ll division_id s nu (the GROUPING bt s l), but job_id s non-nu (the GROUPING
bt s 0), the resutng bt vector s l0 und GROUPING_ID() returns 2.
ll both division_id und job_id ure nu (both GROUPING bts ure 0), the bt vector s
ll und GROUPING_ID() returns 3.
1he loowng tube summurzes these resuts.
divisiun_id jub_id Bit Vcctur GROUPlNG_lD() Rcturn VaIuc
non-nu non-nu 00 0
non-nu nu 0l l
nu non-nu l0 2
nu nu ll 3
Chupter 7: Advunced Queres
213
An fxampIc Qucry That lIIustratcs thc Usc uf GROUPlNG_lD()
1he loowng exumpe pusses division_id und job_id to GROUPING_ID(), notce thut the
output lrom the GROUPING_ID() luncton ugrees wth the expected returned vuues documented
n the prevous secton:
SELECT
division_id, job_id,
GROUPING(division_id) AS DIV_GRP,
GROUPING(job_id) AS JOB_GRP,
GROUPING_ID(division_id, job_id) AS grp_id,
SUM(salary)
FROM employees2
GROUP BY CUBE(division_id, job_id)
ORDER BY division_id, job_id;
DIV JOB DIV_GRP JOB_GRP GRP_ID SUM(SALARY)
--- --- ---------- ---------- ---------- -----------
BUS MGR 0 0 0 530000
BUS PRE 0 0 0 800000
BUS WOR 0 0 0 280000
BUS 0 1 1 1610000
OPE ENG 0 0 0 245000
OPE MGR 0 0 0 805000
OPE WOR 0 0 0 270000
OPE 0 1 1 1320000
SAL MGR 0 0 0 4446000
SAL WOR 0 0 0 490000
SAL 0 1 1 4936000
SUP MGR 0 0 0 465000
SUP TEC 0 0 0 115000
SUP WOR 0 0 0 435000
SUP 0 1 1 1015000
ENG 1 0 2 245000
MGR 1 0 2 6246000
PRE 1 0 2 800000
TEC 1 0 2 115000
WOR 1 0 2 1475000
1 1 3 8881000
A UscfuI AppIicatiun uf GROUPlNG_lD()
Cne uselu uppcuton ol GROUPING_ID() s to lter rows usng u HAVING cuuse. 1he HAVING
cuuse cun excude rows thut don't contun u subtotu or totu by smpy checkng l GROUPING_
ID() returns u vuue greuter thun 0. lor exumpe:
SELECT
division_id, job_id,
GROUPING_ID(division_id, job_id) AS grp_id,
SUM(salary)
FROM employees2
GROUP BY CUBE(division_id, job_id)
214
Cruce Dutubuse ll SQL
HAVING GROUPING_ID(division_id, job_id) > 0
ORDER BY division_id, job_id;
DIV JOB GRP_ID SUM(SALARY)
--- --- ---------- -----------
BUS 1 1610000
OPE 1 1320000
SAL 1 4936000
SUP 1 1015000
ENG 2 245000
MGR 2 6246000
PRE 2 800000
TEC 2 115000
WOR 2 1475000
3 8881000
Using a CuIumn MuItipIc Timcs in a GROUP BY CIausc
You cun use u coumn muny tmes n u GROUP BY cuuse. Dong ths uows you to reorgunze
your dutu or report on dllerent groupngs ol dutu. lor exumpe, the loowng query contuns u
GROUP BY cuuse thut uses division_id twce, once to group by division_id und ugun
n u ROLLUP:
SELECT division_id, job_id, SUM(salary)
FROM employees2
GROUP BY division_id, ROLLUP(division_id, job_id);
DIV JOB SUM(SALARY)
--- --- -----------
BUS MGR 530000
BUS PRE 800000
BUS WOR 280000
OPE ENG 245000
OPE MGR 805000
OPE WOR 270000
SAL MGR 4446000
SAL WOR 490000
SUP MGR 465000
SUP TEC 115000
SUP WOR 435000
BUS 1610000
OPE 1320000
SAL 4936000
SUP 1015000
BUS 1610000
OPE 1320000
SAL 4936000
SUP 1015000
Notce, however, thut the ust lour rows ure dupcutes ol the prevous lour rows. You cun
emnute these dupcutes usng the GROUP_ID() luncton, whch you' eurn ubout next.
Chupter 7: Advunced Queres
21S
Using thc GROUP_lD() functiun
You cun use the GROUP_ID() luncton to remove dupcute rows returned by u GROUP BY
cuuse. GROUP_ID() doesn't uccept uny purumeters. ll dupcutes exst lor u purtcuur
groupng, GROUP_ID returns numbers n the runge 0 to l.
1he loowng exumpe rewrtes the query shown n the prevous secton to ncude the output
lrom GROUP_ID(), notce thut GROUP_ID() returns 0 lor u rows except the ust lour, whch ure
dupcutes ol the prevous lour rows, und thut GROUP_ID() returns l:
SELECT division_id, job_id, GROUP_ID(), SUM(salary)
FROM employees2
GROUP BY division_id, ROLLUP(division_id, job_id);
DIV JOB GROUP_ID() SUM(SALARY)
--- --- ---------- -----------
BUS MGR 0 530000
BUS PRE 0 800000
BUS WOR 0 280000
OPE ENG 0 245000
OPE MGR 0 805000
OPE WOR 0 270000
SAL MGR 0 4446000
SAL WOR 0 490000
SUP MGR 0 465000
SUP TEC 0 115000
SUP WOR 0 435000
BUS 0 1610000
OPE 0 1320000
SAL 0 4936000
SUP 0 1015000
BUS 1 1610000
OPE 1 1320000
SAL 1 4936000
SUP 1 1015000
You cun emnute dupcute rows usng u HAVING cuuse thut uows ony rows whose
GROUP_ID() s 0, lor exumpe:
SELECT division_id, job_id, GROUP_ID(), SUM(salary)
FROM employees2
GROUP BY division_id, ROLLUP(division_id, job_id)
HAVING GROUP_ID() = 0;
DIV JOB GROUP_ID() SUM(SALARY)
--- --- ---------- -----------
BUS MGR 0 530000
BUS PRE 0 800000
BUS WOR 0 280000
OPE ENG 0 245000
OPE MGR 0 805000
OPE WOR 0 270000
216
Cruce Dutubuse ll SQL
SAL MGR 0 4446000
SAL WOR 0 490000
SUP MGR 0 465000
SUP TEC 0 115000
SUP WOR 0 435000
BUS 0 1610000
OPE 0 1320000
SAL 0 4936000
SUP 0 1015000
1hs concudes the dscusson ol the extended GROUP BY cuuses.
Using thc AnaIytic functiuns
1he dutubuse hus muny but-n unuytc lunctons thut enube you to perlorm compex
cucuutons, such us lndng the top-seng product type lor euch month, the top suespersons,
und so on. 1he unuytc lunctons ure orgunzed nto the loowng cutegores:
Ranking functiuns enube you to cucuute runks, percentes, und -tes (tertes,
quurtes, und so on).
lnvcrsc pcrccntiIc functiuns enube you to cucuute the vuue thut corresponds to u
percente.
Winduw functiuns enube you to cucuute cumuutve und movng uggregutes.
Rcpurting functiuns enube you to cucuute thngs ke murket shure.
lag and Icad functiuns enube you to get u vuue n u row where thut row s u certun
number ol rows uwuy lrom the current row.
first and Iast functiuns enube you to get the lrst und ust vuues n un ordered group.
lincar rcgrcssiun functiuns enube you to lt un ordnury-eust-squures regresson ne
to u set ol number purs.
HyputhcticaI rank and distributiun functiuns enube you to cucuute the runk und
percente thut u new row woud huve l you nserted t nto u tube.
You' eurn ubout these lunctons shorty, but lrst et's exumne the exumpe tube used next.
Thc fxampIc TabIc
You' see the use ol the all_sales tube n the loowng sectons. 1he all_sales tube stores
the sum ol u the sues by dour umount lor u purtcuur yeur, month, product type, und empoyee.
1he all_sales tube s creuted by the store_schema.sql scrpt us loows:
CREATE TABLE all_sales (
year INTEGER NOT NULL,
month INTEGER NOT NULL,
prd_type_id INTEGER
CONSTRAINT all_sales_fk_product_types
REFERENCES product_types(product_type_id),
emp_id INTEGER
Chupter 7: Advunced Queres
217
CONSTRAINT all_sales_fk_employees2
REFERENCES employees2(employee_id),
amount NUMBER(8, 2),
CONSTRAINT all_sales_pk PRIMARY KEY (
year, month, prd_type_id, emp_id
)
);
As you cun see, the all_sales tube contuns lve coumns, whch ure us loows:
YEAR stores the yeur the sues took puce.
MONTH stores the month the sues took puce (l to l2).
PRD_TYPE_ID stores the product_type_id ol the product.
EMP_ID stores the employee_id ol the empoyee who hunded the sues.
AMOUNT stores the totu dour umount ol the sues.
1he loowng query retreves the lrst l2 rows lrom the all_sales tube:
SELECT *
FROM all_sales
WHERE ROWNUM <= 12;
YEAR MONTH PRD_TYPE_ID EMP_ID AMOUNT
---------- ---------- ----------- ---------- ----------
2003 1 1 21 10034.84
2003 2 1 21 15144.65
2003 3 1 21 20137.83
2003 4 1 21 25057.45
2003 5 1 21 17214.56
2003 6 1 21 15564.64
2003 7 1 21 12654.84
2003 8 1 21 17434.82
2003 9 1 21 19854.57
2003 10 1 21 21754.19
2003 11 1 21 13029.73
2003 12 1 21 10034.84
NOTf
Thc all_sales |abc ac|ua, con|an a o| morc rov |han |h, bu|
|or pacc condcra|on 'vc om||cd |ng |hcm a hcrc.
Let's exumne the runkng lunctons next.
Using thc Ranking functiuns
You use the runkng lunctons to cucuute runks, percentes, und n-tes. 1he runkng lunctons
ure shown n 1ube 7-2.
Let's exumne the RANK() und DENSE_RANK() lunctons lrst.
218
Cruce Dutubuse llg SQL
Using thc RANk() and DfNSf_RANk() functiuns
You use RANK() und DENSE_RANK() to runk tems n u group. 1he dllerence between these two
lunctons s n the wuy they hunde tems thut te: RANK() euves u gup n the sequence when
there s u te, but DENSE_RANK() euves no gups. lor exumpe, l you were runkng sues by
product type und two product types te lor lrst puce, RANK() woud put the two product types n
lrst puce, but the next product type woud be n thrd puce. DENSE_RANK() woud uso put the
two product types n lrst puce, but the next product type woud be n second puce.
1he loowng query ustrutes the use ol RANK() und DENSE_RANK() to get the runkng ol
sues by product type lor the yeur 2003, notce the use ol the keyword OVER n the syntux when
cung the RANK() und DENSE_RANK() lunctons:
SELECT
prd_type_id, SUM(amount),
RANK() OVER (ORDER BY SUM(amount) DESC) AS rank,
DENSE_RANK() OVER (ORDER BY SUM(amount) DESC) AS dense_rank
FROM all_sales
WHERE year = 2003
AND amount IS NOT NULL
GROUP BY prd_type_id
ORDER BY prd_type_id;
PRD_TYPE_ID SUM(AMOUNT) RANK DENSE_RANK
----------- ----------- ---------- ----------
1 905081.84 1 1
2 186381.22 4 4
3 478270.91 2 2
4 402751.16 3 3
Notce thut sues lor product type rl ure runked lrst, sues lor product type r2 ure runked
lourth, und so on. ecuuse there ure no tes, RANK() und DENSE_RANK() return the sume runks.
functiun Dcscriptiun
RANK()
Returns the runk ol tems n u group. RANK() euves u gup n the
sequence ol runkngs n the event ol u te.
DENSE_RANK()
Returns the runk ol tems n u group. DENSE_RANK() doesn't euve
u gup n the sequence ol runkngs n the event ol u te.
CUME_DIST()
Returns the poston ol u specled vuue reutve to u group ol
vuues. CUME_DIST() s short lor cumuutve dstrbuton.
PERCENT_RANK()
Returns the percent runk ol u vuue reutve to u group ol vuues.
NTILE()
Returns n-tes: tertes, quurtes, und so on.
ROW_NUMBER()
Returns u number wth euch row n u group.
TABlf 7-2 Thc Ran|ng unc|on
Chupter 7: Advunced Queres

1he all_sales tube uctuuy contuns nus n the AMOUNT coumn lor u rows whose
PRD_TYPE_ID coumn s 5, the prevous query omts these rows becuuse ol the ncuson ol the
ne "AND amount IS NOT NULL" n the WHERE cuuse. 1he next exumpe ncudes these rows
by euvng out the AND ne lrom the WHERE cuuse:
SELECT
prd_type_id, SUM(amount),
RANK() OVER (ORDER BY SUM(amount) DESC) AS rank,
DENSE_RANK() OVER (ORDER BY SUM(amount) DESC) AS dense_rank
FROM all_sales
WHERE year = 2003
GROUP BY prd_type_id
ORDER BY prd_type_id;
PRD_TYPE_ID SUM(AMOUNT) RANK DENSE_RANK
----------- ----------- ---------- ----------
1 905081.84 2 2
2 186381.22 5 5
3 478270.91 3 3
4 402751.16 4 4
5 1 1
Notce thut the ust row contuns nu lor the sum ol the AMOUNT coumn und thut RANK() und
DENSE_RANK() return l lor ths row. 1hs s becuuse by deluut RANK() und DENSE_RANK()
ussgn the hghest runk ol l to nu vuues n descendng runkngs (thut s, DESC s used n the
OVER cuuse) und the owest runk n uscendng runkngs (thut s, ASC s used n the OVER cuuse).
Contro||ing kanking of hu|| a|ues using the huLL5 fIk51 and huLL5 Lk51 C|auses \hen
usng un unuytc luncton, you cun expcty contro whether nus ure the hghest or owest n
u group usng NULLS FIRST or NULLS LAST. 1he loowng exumpe uses NULLS LAST to
specly thut nus ure the owest:
SELECT
prd_type_id, SUM(amount),
RANK() OVER (ORDER BY SUM(amount) DESC NULLS LAST) AS rank,
DENSE_RANK() OVER (ORDER BY SUM(amount) DESC NULLS LAST) AS dense_rank
FROM all_sales
WHERE year = 2003
GROUP BY prd_type_id
ORDER BY prd_type_id;
PRD_TYPE_ID SUM(AMOUNT) RANK DENSE_RANK
----------- ----------- ---------- ----------
1 905081.84 1 1
2 186381.22 4 4
3 478270.91 2 2
4 402751.16 3 3
5 5 5

Cruce Dutubuse ll SQL
using the Fkk1I1I0h 8 C|ause with kna|ytic functions You use the PARTITION BY cuuse
wth the unuytc lunctons when you need to dvde the groups nto subgroups. lor exumpe, l
you need to subdvde the sues umount by month, you cun use PARTITION BY month, us
shown n the loowng query:
SELECT
prd_type_id, month, SUM(amount),
RANK() OVER (PARTITION BY month ORDER BY SUM(amount) DESC) AS rank
FROM all_sales
WHERE year = 2003
AND amount IS NOT NULL
GROUP BY prd_type_id, month
ORDER BY prd_type_id, month;
PRD_TYPE_ID MONTH SUM(AMOUNT) RANK
----------- ---------- ----------- ----------
1 1 38909.04 1
1 2 70567.9 1
1 3 91826.98 1
1 4 120344.7 1
1 5 97287.36 1
1 6 57387.84 1
1 7 60929.04 2
1 8 75608.92 1
1 9 85027.42 1
1 10 105305.22 1
1 11 55678.38 1
1 12 46209.04 2
2 1 14309.04 4
2 2 13367.9 4
2 3 16826.98 4
2 4 15664.7 4
2 5 18287.36 4
2 6 14587.84 4
2 7 15689.04 3
2 8 16308.92 4
2 9 19127.42 4
2 10 13525.14 4
2 11 16177.84 4
2 12 12509.04 4
3 1 24909.04 2
3 2 15467.9 3
3 3 20626.98 3
3 4 23844.7 2
3 5 18687.36 3
3 6 19887.84 3
3 7 81589.04 1
3 8 62408.92 2
3 9 46127.42 3
3 10 70325.29 3
3 11 46187.38 2
3 12 48209.04 1
Chupter 7: Advunced Queres

4 1 17398.43 3
4 2 17267.9 2
4 3 31026.98 2
4 4 16144.7 3
4 5 20087.36 2
4 6 33087.84 2
4 7 12089.04 4
4 8 58408.92 3
4 9 49327.42 2
4 10 75325.14 2
4 11 42178.38 3
4 12 30409.05 3
using k0LLuF, Cu8, and 6k0uFIh6 515 0perators with kna|ytic functions You cun use the
ROLLUP, CUBE, und GROUPING SETS operutors wth the unuytc lunctons. 1he loowng query
uses ROLLUP und RANK() to get the sues runkngs by product type lD:
SELECT
prd_type_id, SUM(amount),
RANK() OVER (ORDER BY SUM(amount) DESC) AS rank
FROM all_sales
WHERE year = 2003
GROUP BY ROLLUP(prd_type_id)
ORDER BY prd_type_id;
PRD_TYPE_ID SUM(AMOUNT) RANK
----------- ----------- ----------
1 905081.84 3
2 186381.22 6
3 478270.91 4
4 402751.16 5
5 1
1972485.13 2
1he next query uses CUBE und RANK() to get u runkngs ol sues by product type lD und
empoyee lD:
SELECT
prd_type_id, emp_id, SUM(amount),
RANK() OVER (ORDER BY SUM(amount) DESC) AS rank
FROM all_sales
WHERE year = 2003
GROUP BY CUBE(prd_type_id, emp_id)
ORDER BY prd_type_id, emp_id;
PRD_TYPE_ID EMP_ID SUM(AMOUNT) RANK
----------- ---------- ----------- ----------
1 21 197916.96 19
1 22 214216.96 17
1 23 98896.96 26
1 24 207216.96 18
1 25 93416.96 28
1 26 93417.04 27

Cruce Dutubuse ll SQL
1 905081.84 9
2 21 20426.96 40
2 22 19826.96 41
2 23 19726.96 42
2 24 43866.96 34
2 25 32266.96 38
2 26 50266.42 31
2 186381.22 21
3 21 140326.96 22
3 22 116826.96 23
3 23 112026.96 24
3 24 34829.96 36
3 25 29129.96 39
3 26 45130.11 33
3 478270.91 10
4 21 108326.96 25
4 22 81426.96 30
4 23 92426.96 29
4 24 47456.96 32
4 25 33156.96 37
4 26 39956.36 35
4 402751.16 13
5 21 1
5 22 1
5 23 1
5 24 1
5 25 1
5 26 1
5 1
21 466997.84 11
22 432297.84 12
23 323077.84 15
24 333370.84 14
25 187970.84 20
26 228769.93 16
1972485.13 8
1he next query uses GROUPING SETS und RANK() to get ust the sues umount subtotu
runkngs:
SELECT
prd_type_id, emp_id, SUM(amount),
RANK() OVER (ORDER BY SUM(amount) DESC) AS rank
FROM all_sales
WHERE year = 2003
GROUP BY GROUPING SETS(prd_type_id, emp_id)
ORDER BY prd_type_id, emp_id;
PRD_TYPE_ID EMP_ID SUM(AMOUNT) RANK
----------- ---------- ----------- ----------
1 905081.84 2
2 186381.22 11
Chupter 7: Advunced Queres
223
3 478270.91 3
4 402751.16 6
5 1
21 466997.84 4
22 432297.84 5
23 323077.84 8
24 333370.84 7
25 187970.84 10
26 228769.93 9
Using thc CUMf_DlST() and PfRCfNT_RANk() functiuns
You use CUME_DIST() to cucuute the poston ol u specled vuue reutve to u group ol vuues,
CUME_DIST() s short lor cumuutve dstrbuton. You use PERCENT_RANK() to cucuute the
percent runk ol u vuue reutve to u group ol vuues.
1he loowng query ustrutes the use ol CUME_DIST() und PERCENT_RANK() to get the
cumuutve dstrbuton und percent runk ol sues:
SELECT
prd_type_id, SUM(amount),
CUME_DIST() OVER (ORDER BY SUM(amount) DESC) AS cume_dist,
PERCENT_RANK() OVER (ORDER BY SUM(amount) DESC) AS percent_rank
FROM all_sales
WHERE year = 2003
GROUP BY prd_type_id
ORDER BY prd_type_id;
PRD_TYPE_ID SUM(AMOUNT) CUME_DIST PERCENT_RANK
----------- ----------- ---------- ------------
1 905081.84 .4 .25
2 186381.22 1 1
3 478270.91 .6 .5
4 402751.16 .8 .75
5 .2 0
Using thc NTllf() functiun
You use NTILE(buckets) to cucuute -tes (tertes, quurtes, und so on), buckets specles
the number ol buckets nto whch groups ol rows ure puced. lor exumpe, NTILE(2) specles
two buckets und therelore dvdes the rows nto two groups ol rows, NTILE(4) dvdes the groups
nto lour buckets und therelore dvdes the rows nto lour groups.
1he loowng query ustrutes the use ol NTILE(), notce thut 4 s pussed to NTILE() to
spt the groups ol rows nto lour buckets:
SELECT
prd_type_id, SUM(amount),
NTILE(4) OVER (ORDER BY SUM(amount) DESC) AS ntile
FROM all_sales
WHERE year = 2003
AND amount IS NOT NULL
GROUP BY prd_type_id
ORDER BY prd_type_id;
224
Cruce Dutubuse ll SQL
PRD_TYPE_ID SUM(AMOUNT) NTILE
----------- ----------- ----------
1 905081.84 1
2 186381.22 4
3 478270.91 2
4 402751.16 3
Using thc ROW_NUMBfR() functiun
You use ROW_NUMBER() to return u number wth euch row n u group, sturtng ut l. 1he loowng
query ustrutes the use ol ROW_NUMBER():
SELECT
prd_type_id, SUM(amount),
ROW_NUMBER() OVER (ORDER BY SUM(amount) DESC) AS row_number
FROM all_sales
WHERE year = 2003
GROUP BY prd_type_id
ORDER BY prd_type_id;
PRD_TYPE_ID SUM(AMOUNT) ROW_NUMBER
----------- ----------- ----------
1 905081.84 2
2 186381.22 5
3 478270.91 3
4 402751.16 4
5 1
1hs concudes the dscusson ol runkng lunctons.
Using thc lnvcrsc PcrccntiIc functiuns
ln the secton Lsng the CLML_DlS1() und lLRCLN1_RANK() lunctons, you suw thut CUME_
DIST() s used to cucuute the poston ol u specled vuue reutve to u group ol vuues. You
uso suw thut PERCENT_RANK() s used to cucuute the percent runk ol u vuue reutve to u
group ol vuues.
ln ths secton, you' see how to use the nverse percente lunctons to get the vuue thut
corresponds to u percente. 1here ure two nverse percente lunctons: PERCENTILE_DISC(x)
und PERCENTILE_CONT(x). 1hey operute n u munner the reverse ol CUME_DIST() und
PERCENT_RANK(). PERCENTILE_DISC(x) exumnes the cumuutve dstrbuton vuues n
euch group unt t lnds one thut s greuter thun or equu to x. PERCENTILE_CONT(x) exumnes
the percent runk vuues n euch group unt t lnds one thut s greuter thun or equu to x.
1he loowng query ustrutes the use ol PERCENTILE_CONT() und PERCENTILE_DISC()
to get the sum ol the umount whose percente s greuter thun or equu to 0.6:
SELECT
PERCENTILE_CONT(0.6) WITHIN GROUP (ORDER BY SUM(amount) DESC)
AS percentile_cont,
PERCENTILE_DISC(0.6) WITHIN GROUP (ORDER BY SUM(amount) DESC)
AS percentile_disc
FROM all_sales
WHERE year = 2003
GROUP BY prd_type_id;
Chupter 7: Advunced Queres
22S
PERCENTILE_CONT PERCENTILE_DISC
--------------- ---------------
417855.11 402751.16
ll you compure the sum ol the umounts shown n these resuts wth those shown n the eurer
secton Lsng the CLML_DlS1() und lLRCLN1_RANK() lunctons, you' see thut the sums
correspond to those whose cumuutve dstrbuton und percent runk ure 0.6 und 0.75, respectvey.
Using thc Winduw functiuns
You use the wndow lunctons to cucuute thngs ke cumuutve sums und movng uveruges
wthn u specled runge ol rows, u runge ol vuues, or un ntervu ol tme. As you know, u query
returns u set ol rows known us the resut set. 1he term wndow s used to descrbe u subset ol
rows wthn the resut set. 1he subset ol rows seen through the wndow s then processed by the
wndow lunctons, whch return u vuue. You cun delne the sturt und end ol the wndow.
You cun use u wndow wth the loowng lunctons: SUM(), AVG(), MAX(), MIN(), COUNT(),
VARIANCE(), und STDDEV(), you suw these lunctons n Chupter 4. You cun uso use u wndow
wth FIRST_VALUE() und LAST_VALUE(), whch return the lrst und ust vuues n u wndow.
(You' eurn more ubout the FIRST_VALUE() und LAST_VALUE() lunctons uter n the secton
Cettng the lrst und Lust Rows Lsng llRS1_VALLL() und LAS1_VALLL().)
ln the next secton, you' see how to perlorm u cumuutve sum, u movng uveruge, und u
centered uveruge.
Pcrfurming a CumuIativc Sum
1he loowng query perlorms u cumuutve sum to compute the cumuutve sues umount lor
2003, sturtng wth }unuury und endng n December, notce thut euch monthy sues umount s
udded to the cumuutve umount thut grows ulter euch month:
SELECT
month, SUM(amount) AS month_amount,
SUM(SUM(amount)) OVER
(ORDER BY month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
AS cumulative_amount
FROM all_sales
WHERE year = 2003
GROUP BY month
ORDER BY month;
MONTH MONTH_AMOUNT CUMULATIVE_AMOUNT
---------- ------------ -----------------
1 95525.55 95525.55
2 116671.6 212197.15
3 160307.92 372505.07
4 175998.8 548503.87
5 154349.44 702853.31
6 124951.36 827804.67
7 170296.16 998100.83
8 212735.68 1210836.51
9 199609.68 1410446.19
10 264480.79 1674926.98
11 160221.98 1835148.96
12 137336.17 1972485.13

Cruce Dutubuse ll SQL
1hs query uses the loowng expresson to compute the cumuutve uggregute:
SUM(SUM(amount)) OVER
(ORDER BY month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
AS cumulative_amount
Let's breuk down ths expresson:
SUM(amount) computes the sum ol un umount. 1he outer SUM() computes the
cumuutve umount.
ORDER BY month orders the rows reud by the query by month.
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW delnes the sturt und
end ol the wndow. 1he sturt s set to UNBOUNDED PRECEDING, whch meuns the sturt ol
the wndow s lxed ut the lrst row n the resut set returned by the query. 1he end ol the
wndow s set to CURRENT ROW, CURRENT ROW represents the current row n the resut
set beng processed, und the end ol the wndow sdes down one row ulter the outer
SUM() luncton computes und returns the current cumuutve umount.
1he entre query computes und returns the cumuutve totu ol the sues umounts, sturtng ut
month l, und then uddng the sues umount lor month 2, then month 3, und so on, up to und
ncudng month l2. 1he sturt ol the wndow s lxed ut month l, but the bottom ol the wndow
moves down one row n the resut set ulter euch month's sues umounts ure udded to the cumuutve
totu. 1hs contnues unt the ust row n the resut set s processed by the wndow und the SUM()
lunctons.
Don't conluse the end ol the wndow wth the end ol the resut set. ln the prevous exumpe,
the end ol the wndow sdes down one row n the resut set us euch row s processed (.e., the
sum ol the sues umount lor thut month s udded to the cumuutve totu). ln the exumpe, the end
ol the wndow sturts ut the lrst row, the sum sues umount lor thut month s udded to the cumuutve
totu, und then the end ol the wndow moves down one row to the second row. At ths pont, the
wndow sees two rows. 1he sum ol the sues umount lor thut month s udded to the cumuutve
totu, und the end ol the wndow moves down one row to the thrd row. At ths pont, the wndow
sees three rows. 1hs contnues unt the twelth row s processed. At ths pont, the wndow sees
tweve rows.
1he loowng query uses u cumuutve sum to compute the cumuutve sues umount, sturtng
wth }une ol 2003 (month 6) und endng n December ol 2003 (month l2):
SELECT
month, SUM(amount) AS month_amount,
SUM(SUM(amount)) OVER
(ORDER BY month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS
cumulative_amount
FROM all_sales
WHERE year = 2003
AND month BETWEEN 6 AND 12
GROUP BY month
ORDER BY month;
MONTH MONTH_AMOUNT CUMULATIVE_AMOUNT
---------- ------------ -----------------
6 124951.36 124951.36
7 170296.16 295247.52
Chupter 7: Advunced Queres
227
8 212735.68 507983.2
9 199609.68 707592.88
10 264480.79 972073.67
11 160221.98 1132295.65
12 137336.17 1269631.82
Pcrfurming a Muving Avcragc
1he loowng query computes the movng uveruge ol the sues umount between the current
month und the prevous three months:
SELECT
month, SUM(amount) AS month_amount,
AVG(SUM(amount)) OVER
(ORDER BY month ROWS BETWEEN 3 PRECEDING AND CURRENT ROW)
AS moving_average
FROM all_sales
WHERE year = 2003
GROUP BY month
ORDER BY month;
MONTH MONTH_AMOUNT MOVING_AVERAGE
---------- ------------ --------------
1 95525.55 95525.55
2 116671.6 106098.575
3 160307.92 124168.357
4 175998.8 137125.968
5 154349.44 151831.94
6 124951.36 153901.88
7 170296.16 156398.94
8 212735.68 165583.16
9 199609.68 176898.22
10 264480.79 211780.578
11 160221.98 209262.033
12 137336.17 190412.155
Notce thut the query uses the loowng expresson to compute the movng uveruge:
AVG(SUM(amount)) OVER
(ORDER BY month ROWS BETWEEN 3 PRECEDING AND CURRENT ROW)
AS moving_average
Let's breuk down ths expresson:
SUM(amount) computes the sum ol un umount. 1he outer AVG() computes the uveruge.
ORDER BY month orders the rows reud by the query by month.
ROWS BETWEEN 3 PRECEDING AND CURRENT ROW delnes the sturt ol the wndow
us ncudng the three rows precedng the current row, the end ol the wndow s the
current row beng processed.
So, the entre expresson computes the movng uveruge ol the sues umount between the
current month und the prevous three months. ecuuse lor the lrst two months ess thun the lu
three months ol dutu ure uvuube, the movng uveruge s bused on ony the months uvuube.
228
Cruce Dutubuse ll SQL
oth the sturt und the end ol the wndow begn ut row rl reud by the query. 1he end ol the
wndow moves down ulter euch row s processed. 1he sturt ol the wndow moves down ony ulter
row r4 hus been processed, und subsequenty moves down one row ulter euch row s processed.
1hs contnues unt the ust row n the resut set s reud.
Pcrfurming a Ccntcrcd Avcragc
1he loowng query computes the movng uveruge ol the sues umount centered between the
prevous und next month lrom the current month:
SELECT
month, SUM(amount) AS month_amount,
AVG(SUM(amount)) OVER
(ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
AS moving_average
FROM all_sales
WHERE year = 2003
GROUP BY month
ORDER BY month;
MONTH MONTH_AMOUNT MOVING_AVERAGE
---------- ------------ --------------
1 95525.55 106098.575
2 116671.6 124168.357
3 160307.92 150992.773
4 175998.8 163552.053
5 154349.44 151766.533
6 124951.36 149865.653
7 170296.16 169327.733
8 212735.68 194213.84
9 199609.68 225608.717
10 264480.79 208104.15
11 160221.98 187346.313
12 137336.17 148779.075
Notce thut the query uses the loowng expresson to compute the movng uveruge:
AVG(SUM(amount)) OVER
(ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
AS moving_average
Let's breuk down ths expresson:
SUM(amount) computes the sum ol un umount. 1he outer AVG() computes the uveruge.
ORDER BY month orders the rows reud by the query by month.
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING delnes the sturt ol the wndow us
ncudng the row precedng the current row beng processed. 1he end ol the wndow s
the row loowng the current row.
So, the entre expresson computes the movng uveruge ol the sues umount between the current
month und the prevous month. ecuuse lor the lrst und ust month ess thun the lu three months
ol dutu ure uvuube, the movng uveruge s bused on ony the months uvuube.
Chupter 7: Advunced Queres
229
1he sturt ol the wndow begns ut row rl reud by the query. 1he end ol the wndow begns
ut row r2 und moves down ulter euch row s processed. 1he sturt ol the wndow moves down
ony once row r2 hus been processed. lrocessng contnues unt the ust row reud by the query
s processed.
Gctting thc first and last Ruws Using flRST_VAlUf() and lAST_VAlUf()
You use the FIRST_VALUE() und LAST_VALUE() lunctons to get the lrst und ust rows n u
wndow. 1he loowng query uses FIRST_VALUE() und LAST_VALUE() to get the prevous
und next month's sues umount:
SELECT
month, SUM(amount) AS month_amount,
FIRST_VALUE(SUM(amount)) OVER
(ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
AS previous_month_amount,
LAST_VALUE(SUM(amount)) OVER
(ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
AS next_month_amount
FROM all_sales
WHERE year = 2003
GROUP BY month
ORDER BY month;
MONTH MONTH_AMOUNT PREVIOUS_MONTH_AMOUNT NEXT_MONTH_AMOUNT
---------- ------------ --------------------- -----------------
1 95525.55 95525.55 116671.6
2 116671.6 95525.55 160307.92
3 160307.92 116671.6 175998.8
4 175998.8 160307.92 154349.44
5 154349.44 175998.8 124951.36
6 124951.36 154349.44 170296.16
7 170296.16 124951.36 212735.68
8 212735.68 170296.16 199609.68
9 199609.68 212735.68 264480.79
10 264480.79 199609.68 160221.98
11 160221.98 264480.79 137336.17
12 137336.17 160221.98 137336.17
1he next query dvdes the current month's sues umount by the prevous month's sues umount
(ubeed us curr_div_prev) und uso dvdes the current month's sues umount by the next
month's sues umount (ubeed us curr_div_next):
SELECT
month, SUM(amount) AS month_amount,
SUM(amount)/FIRST_VALUE(SUM(amount)) OVER
(ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
AS curr_div_prev,
SUM(amount)/LAST_VALUE(SUM(amount)) OVER
(ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
AS curr_div_next
FROM all_sales
WHERE year = 2003
230
Cruce Dutubuse ll SQL
GROUP BY month
ORDER BY month;
MONTH MONTH_AMOUNT CURR_DIV_PREV CURR_DIV_NEXT
---------- ------------ ------------- -------------
1 95525.55 1 .818755807
2 116671.6 1.22136538 .727796855
3 160307.92 1.37400978 .910846665
4 175998.8 1.09787963 1.14026199
5 154349.44 .876991434 1.23527619
6 124951.36 .809535558 .733729756
7 170296.16 1.36289961 .800505867
8 212735.68 1.24921008 1.06575833
9 199609.68 .93829902 .754722791
10 264480.79 1.3249898 1.65071478
11 160221.98 .605798175 1.16664081
12 137336.17 .857161858 1
1hs concudes the dscusson ol wndow lunctons.
Using thc Rcpurting functiuns
You use the reportng lunctons to perlorm cucuutons ucross groups und purttons wthn groups.
You cun perlorm reportng wth the loowng lunctons: SUM(), AVG(), MAX(), MIN(),
COUNT(), VARIANCE(), und STDDEV(). You cun uso use the RATIO_TO_REPORT() luncton
to compute the ruto ol u vuue to the sum ol u set ol vuues.
ln ths secton, you' see how to perlorm u report on u sum und use the RATIO_TO_
REPORT() luncton.
Rcpurting un a Sum
lor the lrst three months ol 2003, the loowng query reports
1he totu sum ol u sues lor u three months (ubeed us total_month_amount).
1he totu sum ol u sues lor u product types (ubeed us total_product_type_
amount).
SELECT
month, prd_type_id,
SUM(SUM(amount)) OVER (PARTITION BY month)
AS total_month_amount,
SUM(SUM(amount)) OVER (PARTITION BY prd_type_id)
AS total_product_type_amount
FROM all_sales
WHERE year = 2003
AND month <= 3
GROUP BY month, prd_type_id
ORDER BY month, prd_type_id;
MONTH PRD_TYPE_ID TOTAL_MONTH_AMOUNT TOTAL_PRODUCT_TYPE_AMOUNT
---------- ----------- ------------------ -------------------------
1 1 95525.55 201303.92
1 2 95525.55 44503.92
Chupter 7: Advunced Queres
231
1 3 95525.55 61003.92
1 4 95525.55 65693.31
1 5 95525.55
2 1 116671.6 201303.92
2 2 116671.6 44503.92
2 3 116671.6 61003.92
2 4 116671.6 65693.31
2 5 116671.6
3 1 160307.92 201303.92
3 2 160307.92 44503.92
3 3 160307.92 61003.92
3 4 160307.92 65693.31
3 5 160307.92
Notce thut the query uses the loowng expresson to report the totu sum ol u sues lor u
months (ubeed us total_month_amount):
SUM(SUM(amount)) OVER (PARTITION BY month)
AS total_month_amount
Let's breuk down ths expresson:
SUM(amount) computes the sum ol un umount. 1he outer SUM() computes the totu sum.
OVER (PARTITION BY month) cuuses the outer SUM() to compute the sum lor
euch month.
1he prevous query uso uses the loowng expresson to report the totu sum ol u sues lor
u product types (ubeed us total_product_type_amount):
SUM(SUM(amount)) OVER (PARTITION BY prd_type_id)
AS total_product_type_amount
Let's breuk down ths expresson:
SUM(amount) computes the sum ol un umount. 1he outer SUM() computes the totu sum.
OVER (PARTITION BY prd_type_id) cuuses the outer SUM() to compute the sum
lor euch product type.
Using thc RATlO_TO_RfPORT() functiun
You use the RATIO_TO_REPORT() luncton to compute the ruto ol u vuue to the sum ol u set
ol vuues.
lor the lrst three months ol 2003, the loowng query reports
1he sum ol the sues umount by product type lor euch month (ubeed us prd_type_
amount).
1he ruto ol the product type's sues umount to the entre month's sues (ubeed us prd_
type_ratio), whch s computed usng RATIO_TO_REPORT().
SELECT
month, prd_type_id,
SUM(amount) AS prd_type_amount,
RATIO_TO_REPORT(SUM(amount)) OVER (PARTITION BY month) AS prd_type_ratio
232
Cruce Dutubuse ll SQL
FROM all_sales
WHERE year = 2003
AND month <= 3
GROUP BY month, prd_type_id
ORDER BY month, prd_type_id;
MONTH PRD_TYPE_ID PRD_TYPE_AMOUNT PRD_TYPE_RATIO
---------- ----------- --------------- --------------
1 1 38909.04 .40731553
1 2 14309.04 .149792804
1 3 24909.04 .260757881
1 4 17398.43 .182133785
1 5
2 1 70567.9 .604842138
2 2 13367.9 .114577155
2 3 15467.9 .132576394
2 4 17267.9 .148004313
2 5
3 1 91826.98 .57281624
3 2 16826.98 .104966617
3 3 20626.98 .128670998
3 4 31026.98 .193546145
3 5
Notce thut the query uses the loowng expresson to compute the ruto (ubeed us prd_
type_ratio):
RATIO_TO_REPORT(SUM(amount)) OVER (PARTITION BY month) AS prd_type_ratio
Let's breuk down ths expresson:
SUM(amount) computes the sum ol the sues umount.
OVER (PARTITION BY month) cuuses the outer SUM() to compute the sum ol the
sues umount lor euch month.
1he ruto s computed by dvdng the sum ol the sues umount lor euch product type by
the sum ol the entre month's sues umount.
1hs concudes the dscusson ol reportng lunctons.
Using thc lAG() and lfAD() functiuns
You use the LAG() und LEAD() lunctons to get u vuue n u row where thut row s u certun
number ol rows uwuy lrom the current row. 1he loowng query uses LAG() und LEAD() to
get the prevous und next month's sues umount:
SELECT
month, SUM(amount) AS month_amount,
LAG(SUM(amount), 1) OVER (ORDER BY month) AS previous_month_amount,
LEAD(SUM(amount), 1) OVER (ORDER BY month) AS next_month_amount
FROM all_sales
WHERE year = 2003
Chupter 7: Advunced Queres
233
GROUP BY month
ORDER BY month;
MONTH MONTH_AMOUNT PREVIOUS_MONTH_AMOUNT NEXT_MONTH_AMOUNT
---------- ------------ --------------------- -----------------
1 95525.55 116671.6
2 116671.6 95525.55 160307.92
3 160307.92 116671.6 175998.8
4 175998.8 160307.92 154349.44
5 154349.44 175998.8 124951.36
6 124951.36 154349.44 170296.16
7 170296.16 124951.36 212735.68
8 212735.68 170296.16 199609.68
9 199609.68 212735.68 264480.79
10 264480.79 199609.68 160221.98
11 160221.98 264480.79 137336.17
12 137336.17 160221.98
Notce thut the query uses the loowng expressons to get the prevous und next month's sues:
LAG(SUM(amount), 1) OVER (ORDER BY month) AS previous_month_amount,
LEAD(SUM(amount), 1) OVER (ORDER BY month) AS next_month_amount
LAG(SUM(amount), 1) gets the prevous row's sum ol the umount. LEAD(SUM(amount),
1) gets the next row's sum ol the umount.
Using thc flRST and lAST functiuns
You use the FIRST und LAST lunctons to get the lrst und ust vuues n un ordered group. You cun
use FIRST und LAST wth the loowng lunctons: MIN(), MAX(), COUNT(), SUM(), AVG(),
STDDEV(), und VARIANCE().
1he loowng query uses FIRST und LAST to get the months n 2003 thut hud the hghest
und owest sues:
SELECT
MIN(month) KEEP (DENSE_RANK FIRST ORDER BY SUM(amount))
AS highest_sales_month,
MIN(month) KEEP (DENSE_RANK LAST ORDER BY SUM(amount))
AS lowest_sales_month
FROM all_sales
WHERE year = 2003
GROUP BY month
ORDER BY month;
HIGHEST_SALES_MONTH LOWEST_SALES_MONTH
------------------- ------------------
1 10
Using thc lincar Rcgrcssiun functiuns
You use the neur regresson lunctons to lt un ordnury-eust-squures regresson ne to u set ol
number purs. You cun use the neur regresson lunctons us uggregute, wndowng, or reportng
234
Cruce Dutubuse ll SQL
lunctons. 1he loowng tube shows the neur regresson lunctons. ln the luncton syntux, y s
nterpreted by the lunctons us u vurube thut depends on x.
functiun Dcscriptiun
REGR_AVGX(y, x)
Returns the uveruge ol x ulter emnutng x und y purs where
ether x or y s nu
REGR_AVGY(y, x)
Returns the uveruge ol y ulter emnutng x und y purs where
ether x or y s nu
REGR_COUNT(y, x)
Returns the number ol non-nu number purs thut ure used to
lt the regresson ne
REGR_INTERCEPT(y, x)
Returns the ntercept on the y-uxs ol the regresson ne
REGR_R2(y, x)
Returns the coellcent ol determnuton (R-squured) ol the
regresson ne
REGR_SLOPE(y, x)
Returns the sope ol the regresson ne
REGR_SXX(y, x)
Returns REG_COUNT (y, x) * VAR_POP(x)
REGR_SXY(y, x)
Returns REG_COUNT (y, x) * COVAR_POP(y, x)
REGR_SYY(y, x)
Returns REG_COUNT (y, x) * VAR_POP (y)
1he loowng query shows the use ol the neur regresson lunctons:
SELECT
prd_type_id,
REGR_AVGX(amount, month) AS avgx,
REGR_AVGY(amount, month) AS avgy,
REGR_COUNT(amount, month) AS count,
REGR_INTERCEPT(amount, month) AS inter,
REGR_R2(amount, month) AS r2,
REGR_SLOPE(amount, month) AS slope,
REGR_SXX(amount, month) AS sxx,
REGR_SXY(amount, month) AS sxy,
REGR_SYY(amount, month) AS syy
FROM all_sales
WHERE year = 2003
GROUP BY prd_type_id;
PRD_TYPE_ID AVGX AVGY COUNT INTER R2
----------- ---------- ---------- ---------- ---------- ----------
SLOPE SXX SXY SYY
---------- ---------- ---------- ----------
1 6.5 12570.5811 72 13318.4543 .003746289
-115.05741 858 -98719.26 3031902717
2 6.5 2588.62806 72 2608.11268 .0000508
-2.997634 858 -2571.97 151767392
3 6.5 6642.65153 72 2154.23119 .126338815
Chupter 7: Advunced Queres
23S
690.526206 858 592471.485 3238253324
4 6.5 5593.76611 72 2043.47164 .128930297
546.199149 858 468638.87 1985337488
5 0
Using thc HyputhcticaI Rank and Distributiun functiuns
You use the hypothetcu runk und dstrbuton lunctons to cucuute the runk und percente thut u
new row woud huve l you nserted t nto u tube. You cun perlorm hypothetcu cucuutons wth
the loowng lunctons: RANK(), DENSE_RANK(), PERCENT_RANK(), und CUME_DIST().
An exumpe ol u hypothetcu luncton w be gven ulter the loowng query, whch uses
RANK() und PERCENT_RANK() to get the runk und percent runk ol sues by product type lor 2003:
SELECT
prd_type_id, SUM(amount),
RANK() OVER (ORDER BY SUM(amount) DESC) AS rank,
PERCENT_RANK() OVER (ORDER BY SUM(amount) DESC) AS percent_rank
FROM all_sales
WHERE year = 2003
AND amount IS NOT NULL
GROUP BY prd_type_id
ORDER BY prd_type_id;
PRD_TYPE_ID SUM(AMOUNT) RANK PERCENT_RANK
----------- ----------- ---------- ------------
1 905081.84 1 0
2 186381.22 4 1
3 478270.91 2 .333333333
4 402751.16 3 .666666667
1he next query shows the hypothetcu runk und percent runk ol u sues umount ol S500,000:
SELECT
RANK(500000) WITHIN GROUP (ORDER BY SUM(amount) DESC)
AS rank,
PERCENT_RANK(500000) WITHIN GROUP (ORDER BY SUM(amount) DESC)
AS percent_rank
FROM all_sales
WHERE year = 2003
AND amount IS NOT NULL
GROUP BY prd_type_id
ORDER BY prd_type_id;
RANK PERCENT_RANK
---------- ------------
2 .25
As you cun see, the hypothetcu runk und percent runk ol u sues umount ol S500,000 ure 2
und .25.
1hs concudes the dscusson ol hypothetcu lunctons.
236
Cruce Dutubuse ll SQL
Using thc MODfl CIausc
1he MODEL cuuse wus ntroduced wth Cruce Dutubuse l0 und enubes you to perlorm nter-
row cucuutons. 1he MODEL cuuse uows you to uccess u coumn n u row ke u ce n un
urruy. 1hs gves you the ubty to perlorm cucuutons n u smur munner to spreudsheet
cucuutons. lor exumpe, the all_sales tube contuns sues nlormuton lor the months n
2003. You cun use the MODEL cuuse to cucuute sues n luture months bused on sues n 2003.
An fxampIc uf thc MODfl CIausc
1he eusest wuy to eurn how to use the MODEL cuuse s to see un exumpe. 1he loowng query
retreves the sues umount lor euch month n 2003 mude by empoyee r2l lor product types rl
und r2 und computes the predcted sues lor }unuury, lebruury, und Murch ol 2004 bused on sues
n 2003:
SELECT prd_type_id, year, month, sales_amount
FROM all_sales
WHERE prd_type_id BETWEEN 1 AND 2
AND emp_id = 21
MODEL
PARTITION BY (prd_type_id)
DIMENSION BY (month, year)
MEASURES (amount sales_amount) (
sales_amount[1, 2004] = sales_amount[1, 2003],
sales_amount[2, 2004] = sales_amount[2, 2003] + sales_amount[3, 2003],
sales_amount[3, 2004] = ROUND(sales_amount[3, 2003] * 1.25, 2)
)
ORDER BY prd_type_id, year, month;
Let's breuk down ths query:
PARTITION BY (prd_type_id) specles thut the resuts ure purttoned by prd_
type_id.
DIMENSION BY (month, year) specles thut the dmensons ol the urruy ure month
und year. 1hs meuns thut u ce n the urruy s uccessed by speclyng u month und yeur.
MEASURES (amount sales_amount) specles thut euch ce n the urruy contuns
un umount und thut the urruy nume s sales_amount. 1o uccess the ce n the sales_
amount urruy lor }unuury 2003, you use sales_amount[1, 2003], whch returns the
sues umount lor thut month und yeur.
Alter MEASURES come three nes thut compute the luture sues lor }unuury, lebruury, und
Murch ol 2004:
sales_amount[1, 2004] = sales_amount[1, 2003] sets the sues umount
lor }unuury 2004 to the umount lor }unuury 2003.
sales_amount[2, 2004] = sales_amount[2, 2003] + sales_
amount[3, 2003] sets the sues umount lor lebruury 2004 to the umount lor
lebruury 2003 pus Murch 2003.
Chupter 7: Advunced Queres
237
sales_amount[3, 2004] = ROUND(sales_amount[3, 2003] * 1.25,
2) sets the sues umount lor Murch 2004 to the rounded vuue ol the sues umount lor
Murch 2003 mutped by l.25.
ORDER BY prd_type_id, year, month smpy orders the resuts returned by the
entre query.
1he output lrom the query s shown n the loowng stng, notce thut the resuts contun the
sues umounts lor u months n 2003 lor product types rl und r2, pus the predcted sues
umounts lor the lrst three months n 2004 (whch l've mude bod to muke them stund out):
PRD_TYPE_ID YEAR MONTH SALES_AMOUNT
----------- ---------- ---------- ------------
1 2003 1 10034.84
1 2003 2 15144.65
1 2003 3 20137.83
1 2003 4 25057.45
1 2003 5 17214.56
1 2003 6 15564.64
1 2003 7 12654.84
1 2003 8 17434.82
1 2003 9 19854.57
1 2003 10 21754.19
1 2003 11 13029.73
1 2003 12 10034.84
1 2004 1 10034.84
1 2004 2 35282.48
1 2004 3 25172.29
2 2003 1 1034.84
2 2003 2 1544.65
2 2003 3 2037.83
2 2003 4 2557.45
2 2003 5 1714.56
2 2003 6 1564.64
2 2003 7 1264.84
2 2003 8 1734.82
2 2003 9 1854.57
2 2003 10 2754.19
2 2003 11 1329.73
2 2003 12 1034.84
2 2004 1 1034.84
2 2004 2 3582.48
2 2004 3 2547.29
Using PusitiunaI and SymbuIic Nutatiun tu Acccss CcIIs
ln the prevous exumpe, you suw how to uccess u ce n un urruy usng the loowng notuton:
sales_amount[1, 2004], where l s the month und 2004 s the yeur. 1hs s relerred to us
postonu notuton becuuse the meunng ol the dmensons s determned by ther poston: the
lrst poston contuns the month und the second poston contuns the yeur.
238
Cruce Dutubuse ll SQL
You cun uso use symboc notuton to expcty ndcute the meunng ol the dmensons, us
n, lor exumpe, sales_amount[month=1, year=2004]. 1he loowng query rewrtes the
prevous query to use symboc notuton:
SELECT prd_type_id, year, month, sales_amount
FROM all_sales
WHERE prd_type_id BETWEEN 1 AND 2
AND emp_id = 21
MODEL
PARTITION BY (prd_type_id)
DIMENSION BY (month, year)
MEASURES (amount sales_amount) (
sales_amount[month=1, year=2004] = sales_amount[month=1, year=2003],
sales_amount[month=2, year=2004] =
sales_amount[month=2, year=2003] + sales_amount[month=3, year=2003],
sales_amount[month=3, year=2004] =
ROUND(sales_amount[month=3, year=2003] * 1.25, 2)
)
ORDER BY prd_type_id, year, month;
\hen usng postonu or symboc notuton, t s mportunt to be uwure ol the dllerent wuy
they hunde nu vuues n the dmensons. lor exumpe, sales_amount[null, 2003] returns
the umount whose month s nu und yeur s 2003, but sales_amount[month=null,
year=2004] won't uccess u vud ce becuuse null=null uwuys returns luse.
Acccssing a Rangc uf CcIIs Using BfTWffN and AND
You cun uccess u runge ol ces usng the BETWEEN und AND keywords. lor exumpe, the
loowng expresson sets the sues umount lor }unuury 2004 to the rounded uveruge ol
the sues between }unuury und Murch ol 2003:
sales_amount[1, 2004] =
ROUND(AVG(sales_amount)[month BETWEEN 1 AND 3, 2003], 2)
1he loowng query shows the use ol ths expresson:
SELECT prd_type_id, year, month, sales_amount
FROM all_sales
WHERE prd_type_id BETWEEN 1 AND 2
AND emp_id = 21
MODEL
PARTITION BY (prd_type_id)
DIMENSION BY (month, year)
MEASURES (amount sales_amount) (
sales_amount[1, 2004] =
ROUND(AVG(sales_amount)[month BETWEEN 1 AND 3, 2003], 2)
)
ORDER BY prd_type_id, year, month;
Acccssing AII CcIIs Using ANY and lS ANY
You cun uccess u ces n un urruy usng the ANY und IS ANY predcutes. You use ANY wth
postonu notuton und IS ANY wth symboc notuton. lor exumpe, the loowng expresson
sets the sues umount lor }unuury 2004 to the rounded sum ol the sues lor u months und yeurs:
Chupter 7: Advunced Queres
239
sales_amount[1, 2004] =
ROUND(SUM(sales_amount)[ANY, year IS ANY], 2)
1he loowng query shows the use ol ths expresson:
SELECT prd_type_id, year, month, sales_amount
FROM all_sales
WHERE prd_type_id BETWEEN 1 AND 2
AND emp_id = 21
MODEL
PARTITION BY (prd_type_id)
DIMENSION BY (month, year)
MEASURES (amount sales_amount) (
sales_amount[1, 2004] =
ROUND(SUM(sales_amount)[ANY, year IS ANY], 2)
)
ORDER BY prd_type_id, year, month;
Gctting thc Currcnt VaIuc uf a Dimcnsiun
Using CURRfNTV()
You cun get the current vuue ol u dmenson usng the CURRENTV() luncton. lor exumpe, the
loowng expresson sets the sues umount lor the lrst month ol 2004 to l.25 tmes the sues ol
the sume month n 2003, notce the use ol CURRENTV() to get the current month, whch s l:
sales_amount[1, 2004] =
ROUND(sales_amount[CURRENTV(), 2003] * 1.25, 2)
1he loowng query shows the use ol ths expresson:
SELECT prd_type_id, year, month, sales_amount
FROM all_sales
WHERE prd_type_id BETWEEN 1 AND 2
AND emp_id = 21
MODEL
PARTITION BY (prd_type_id)
DIMENSION BY (month, year)
MEASURES (amount sales_amount) (
sales_amount[1, 2004] =
ROUND(sales_amount[CURRENTV(), 2003] * 1.25, 2)
)
ORDER BY prd_type_id, year, month;
1he output lrom ths query s us loows (l've hghghted the vuues lor 2004 n bod):
PRD_TYPE_ID YEAR MONTH SALES_AMOUNT
----------- ---------- ---------- ------------
1 2003 1 10034.84
1 2003 2 15144.65
1 2003 3 20137.83
1 2003 4 25057.45
1 2003 5 17214.56
1 2003 6 15564.64
1 2003 7 12654.84
240
Cruce Dutubuse ll SQL
1 2003 8 17434.82
1 2003 9 19854.57
1 2003 10 21754.19
1 2003 11 13029.73
1 2003 12 10034.84
1 2004 1 12543.55
2 2003 1 1034.84
2 2003 2 1544.65
2 2003 3 2037.83
2 2003 4 2557.45
2 2003 5 1714.56
2 2003 6 1564.64
2 2003 7 1264.84
2 2003 8 1734.82
2 2003 9 1854.57
2 2003 10 2754.19
2 2003 11 1329.73
2 2003 12 1034.84
2 2004 1 1293.55
Acccssing CcIIs Using a fOR luup
You cun uccess ces usng u FOR oop. lor exumpe, the loowng expresson sets the sues
umount lor the lrst three months ol 2004 to l.25 tmes the sues ol the sume months n 2003,
notce the use ol the FOR oop und the INCREMENT keyword thut specles the umount to
ncrement month by durng euch teruton ol the oop:
sales_amount[FOR month FROM 1 TO 3 INCREMENT 1, 2004] =
ROUND(sales_amount[CURRENTV(), 2003] * 1.25, 2)
1he loowng query shows the use ol ths expresson:
SELECT prd_type_id, year, month, sales_amount
FROM all_sales
WHERE prd_type_id BETWEEN 1 AND 2
AND emp_id = 21
MODEL
PARTITION BY (prd_type_id)
DIMENSION BY (month, year)
MEASURES (amount sales_amount) (
sales_amount[FOR month FROM 1 TO 3 INCREMENT 1, 2004] =
ROUND(sales_amount[CURRENTV(), 2003] * 1.25, 2)
)
ORDER BY prd_type_id, year, month;
1he output lrom ths query s us loows (l've hghghted the vuues lor 2004 n bod):
PRD_TYPE_ID YEAR MONTH SALES_AMOUNT
----------- ---------- ---------- ------------
1 2003 1 10034.84
1 2003 2 15144.65
1 2003 3 20137.83
1 2003 4 25057.45
Chupter 7: Advunced Queres
241
1 2003 5 17214.56
1 2003 6 15564.64
1 2003 7 12654.84
1 2003 8 17434.82
1 2003 9 19854.57
1 2003 10 21754.19
1 2003 11 13029.73
1 2003 12 10034.84
1 2004 1 12543.55
1 2004 2 18930.81
1 2004 3 25172.29
2 2003 1 1034.84
2 2003 2 1544.65
2 2003 3 2037.83
2 2003 4 2557.45
2 2003 5 1714.56
2 2003 6 1564.64
2 2003 7 1264.84
2 2003 8 1734.82
2 2003 9 1854.57
2 2003 10 2754.19
2 2003 11 1329.73
2 2003 12 1034.84
2 2004 1 1293.55
2 2004 2 1930.81
2 2004 3 2547.29
HandIing NuII and Missing VaIucs
ln ths secton, you' eurn how to hunde nu und mssng vuues usng the MODEL cuuse.
Using lS PRfSfNT
IS PRESENT returns true l the row specled by the ce relerence exsted pror to the executon
ol the MODEL cuuse. lor exumpe:
sales_amount[CURRENTV(), 2003] IS PRESENT
w return true l sales_amount[CURRENTV(), 2003] exsts.
1he loowng expresson sets the sues umount lor the lrst three months ol 2004 to l.25
mutped by the sues ol the sume months n 2003:
sales_amount[FOR month FROM 1 TO 3 INCREMENT 1, 2004] =
CASE WHEN sales_amount[CURRENTV(), 2003] IS PRESENT THEN
ROUND(sales_amount[CURRENTV(), 2003] * 1.25, 2)
ELSE
0
END
1he loowng query shows the use ol ths expresson:
SELECT prd_type_id, year, month, sales_amount
FROM all_sales
WHERE prd_type_id BETWEEN 1 AND 2
242
Cruce Dutubuse ll SQL
AND emp_id = 21
MODEL
PARTITION BY (prd_type_id)
DIMENSION BY (month, year)
MEASURES (amount sales_amount) (
sales_amount[FOR month FROM 1 TO 3 INCREMENT 1, 2004] =
CASE WHEN sales_amount[CURRENTV(), 2003] IS PRESENT THEN
ROUND(sales_amount[CURRENTV(), 2003] * 1.25, 2)
ELSE
0
END
)
ORDER BY prd_type_id, year, month;
1he output ol ths query s the sume us the exumpe n the prevous secton.
Using PRfSfNTV()
PRESENTV(cell, expr1, expr2) returns the expresson expr1 l the row specled by
the cell relerence exsted pror to the executon ol the MODEL cuuse. ll the row doesn't exst,
the expresson expr2 s returned. lor exumpe:
PRESENTV(sales_amount[CURRENTV(), 2003],
ROUND(sales_amount[CURRENTV(), 2003] * 1.25, 2), 0)
w return the rounded sues umount l sales_amount[CURRENTV(), 2003] exsts,
otherwse 0 w be returned.
1he loowng query shows the use ol ths expresson:
SELECT prd_type_id, year, month, sales_amount
FROM all_sales
WHERE prd_type_id BETWEEN 1 AND 2
AND emp_id = 21
MODEL
PARTITION BY (prd_type_id)
DIMENSION BY (month, year)
MEASURES (amount sales_amount) (
sales_amount[FOR month FROM 1 TO 3 INCREMENT 1, 2004] =
PRESENTV(sales_amount[CURRENTV(), 2003],
ROUND(sales_amount[CURRENTV(), 2003] * 1.25, 2), 0)
)
ORDER BY prd_type_id, year, month;
Using PRfSfNTNNV()
PRESENTNNV(cell, expr1, expr2) returns the expresson expr1 l the row specled by the
cell relerence exsted pror to the executon ol the MODEL cuuse und the ce vuue s not nu.
ll the row doesn't exst or the ce vuue s nu, the expresson expr2 s returned. lor exumpe,
PRESENTNNV(sales_amount[CURRENTV(), 2003],
ROUND(sales_amount[CURRENTV(), 2003] * 1.25, 2), 0)
Chupter 7: Advunced Queres
243
w return the rounded sues umount l sales_amount[CURRENTV(), 2003] exsts und s not
nu, otherwse 0 w be returned.
Using lGNORf NAV and kffP NAV
IGNORE NAV returns
0 lor nu or mssng numerc vuues.
An empty strng lor nu or mssng strng vuues.
0l-}AN-2000 lor nu or mssng dute vuues.
Nu lor u other dutubuse types.
KEEP NAV returns nu lor nu or mssng numerc vuues. e uwure thut KEEP NAV s the
deluut.
1he loowng query shows the use ol IGNORE NAV:
SELECT prd_type_id, year, month, sales_amount
FROM all_sales
WHERE prd_type_id BETWEEN 1 AND 2
AND emp_id = 21
MODEL IGNORE NAV
PARTITION BY (prd_type_id)
DIMENSION BY (month, year)
MEASURES (amount sales_amount) (
sales_amount[FOR month FROM 1 TO 3 INCREMENT 1, 2004] =
ROUND(sales_amount[CURRENTV(), 2003] * 1.25, 2)
)
ORDER BY prd_type_id, year, month;
Updating fxisting CcIIs
y deluut, l the ce relerenced on the elt sde ol un expresson exsts, then t s upduted. ll the
ce doesn't exst, then u new row n the urruy s creuted. You cun chunge ths deluut behuvor
usng RULES UPDATE, whch specles thut l the ce doesn't exst, u new row w not be creuted.
1he loowng query shows the use ol RULES UPDATE:
SELECT prd_type_id, year, month, sales_amount
FROM all_sales
WHERE prd_type_id BETWEEN 1 AND 2
AND emp_id = 21
MODEL
PARTITION BY (prd_type_id)
DIMENSION BY (month, year)
MEASURES (amount sales_amount)
RULES UPDATE (
sales_amount[FOR month FROM 1 TO 3 INCREMENT 1, 2004] =
ROUND(sales_amount[CURRENTV(), 2003] * 1.25, 2)
)
ORDER BY prd_type_id, year, month;
244
Cruce Dutubuse ll SQL
ecuuse ces lor 2004 don't exst und RULES UPDATE s used, no new rows ure creuted n
the urruy lor 2004, therelore, the query doesn't return rows lor 2004. 1he loowng stng shows
the output lor the querynotce there ure no rows lor 2004:
PRD_TYPE_ID YEAR MONTH SALES_AMOUNT
----------- ---------- ---------- ------------
1 2003 1 10034.84
1 2003 2 15144.65
1 2003 3 20137.83
1 2003 4 25057.45
1 2003 5 17214.56
1 2003 6 15564.64
1 2003 7 12654.84
1 2003 8 17434.82
1 2003 9 19854.57
1 2003 10 21754.19
1 2003 11 13029.73
1 2003 12 10034.84
2 2003 1 1034.84
2 2003 2 1544.65
2 2003 3 2037.83
2 2003 4 2557.45
2 2003 5 1714.56
2 2003 6 1564.64
2 2003 7 1264.84
2 2003 8 1734.82
2 2003 9 1854.57
2 2003 10 2754.19
2 2003 11 1329.73
2 2003 12 1034.84
Using thc PlVOT and UNPlVOT CIauscs
1he PIVOT cuuse s new lor Cruce Dutubuse ll und enubes you to rotute rows nto coumns
n the output lrom u query, und, ut the sume tme, to run un uggreguton luncton on the dutu.
Cruce Dutubuse ll uso hus un UNPIVOT cuuse thut rotutes coumns nto rows n the output
lrom u query.
PIVOT und UNPIVOT ure uselu to see overu trends n urge umounts ol dutu, such us trends
n sues over u perod ol tme. You' see queres thut show the use ol PIVOT und UNPIVOT n the
loowng sectons.
A SimpIc fxampIc uf thc PlVOT CIausc
1he eusest wuy to eurn how to use the PIVOT cuuse s to see un exumpe. 1he loowng query
shows the totu sues umount ol product types rl, r2, und r3 lor the lrst lour months n 2003,
notce thut the ces n the query's output show the sum ol the sues umounts lor euch product
type n euch month:
Chupter 7: Advunced Queres

SELECT *
FROM (
SELECT month, prd_type_id, amount
FROM all_sales
WHERE year = 2003
AND prd_type_id IN (1, 2, 3)
)
PIVOT (
SUM(amount) FOR month IN (1 AS JAN, 2 AS FEB, 3 AS MAR, 4 AS APR)
)
ORDER BY prd_type_id;
PRD_TYPE_ID JAN FEB MAR APR
----------- ---------- ---------- ---------- ----------
1 38909.04 70567.9 91826.98 120344.7
2 14309.04 13367.9 16826.98 15664.7
3 24909.04 15467.9 20626.98 23844.7
Sturtng wth the lrst ne ol output, you cun see there wus
S38,909.04 ol product type rl sod n }unuury.
S70,567.90 ol product type rl sod n lebruury.
.und so on lor the rest ol the lrst ne.
1he second ne ol output shows there wus
Sl4,309.04 ol product type r2 sod n }unuury.
Sl3,367.90 ol product type r2 sod n lebruury.
.und so on lor the rest ol the output.

PIVOT a povcr|u |oo |ha| aov ,ou |o cc |rcnd n ac o| |,pc


o| produc| ovcr a pcrod o| mon|h. acd on uch |rcnd, a rca |orc
coud uc |hc n|orma|on |o a|cr |hcr ac |ac|c and |ormua|c ncv
mar|c|ng campagn.
1he prevous SELECT stutement hus the loowng structure:
SELECT *
FROM (
inner_query
)
PIVOT (
aggregate_function FOR pivot_column IN (list_of_values)
)
ORDER BY ...;
246
Cruce Dutubuse ll SQL
Let's breuk down the prevous exumpe nto the structuru eements:
1here s un nner und outer query. 1he nner query gets the month, product type, und
umount lrom the all_sales tube und pusses the resuts to the outer query.
SUM(amount) FOR month IN (1 AS JAN, 2 AS FEB, 3 AS MAR, 4 AS
APR)s the ne n the PIVOT cuuse.
1he SUM() luncton udds up the sues umounts lor the product types n the lrst lour
months (the months ure sted n the IN purt). lnsteud ol returnng the months us l, 2,
3, und 4 n the output, the AS purt renumes the numbers to JAN, FEB, MAR, und APR
to muke the months more reudube n the output.
1he month coumn lrom the all_sales tube s used us the pvot coumn. 1hs
meuns thut the months uppeur us coumns n the output. ln ellect, the rows ure
rotutedor to vew the months us coumns.
At the very end ol the exumpe, the ORDER BY prd_type_id ne smpy orders the
resuts by the product type.
Pivuting un MuItipIc CuIumns
You cun pvot on mutpe coumns by pucng those coumns n the FOR purt ol the PIVOT. 1he
loowng exumpe pvots on both the month und prd_type_id coumns, whch ure relerenced
n the FOR purt, notce thut the st ol vuues n the IN purt ol the PIVOT contuns u vuue lor the
month und prd_type_id coumns:
SELECT *
FROM (
SELECT month, prd_type_id, amount
FROM all_sales
WHERE year = 2003
AND prd_type_id IN (1, 2, 3)
)
PIVOT (
SUM(amount) FOR (month, prd_type_id) IN (
(1, 2) AS JAN_PRDTYPE2,
(2, 3) AS FEB_PRDTYPE3,
(3, 1) AS MAR_PRDTYPE1,
(4, 2) AS APR_PRDTYPE2
)
);
JAN_PRDTYPE2 FEB_PRDTYPE3 MAR_PRDTYPE1 APR_PRDTYPE2
------------ ------------ ------------ ------------
14309.04 15467.9 91826.98 15664.7
1he ces n the output show the sum ol the sues umounts lor euch product type n the specled
month (the product type und month to query ure puced n the st ol vuues n the IN purt). As you
cun see lrom the query output, there were the loowng sues umounts:
Sl4,309.04 ol product type r2 n }unuury
Chupter 7: Advunced Queres
247
Sl5,467.90 ol product type r3 n lebruury
S9l,826.98 ol product type rl n Murch
Sl5,664.70 ol product type r2 n Apr
You cun put uny vuues n the IN purt to get the vuues ol nterest to you. ln the loowng
exumpe, the vuues ol the product types ure shulled n the IN purt to get the sues lor those
product types n the specled months:
SELECT *
FROM (
SELECT month, prd_type_id, amount
FROM all_sales
WHERE year = 2003
AND prd_type_id IN (1, 2, 3)
)
PIVOT (
SUM(amount) FOR (month, prd_type_id) IN (
(1, 1) AS JAN_PRDTYPE1,
(2, 2) AS FEB_PRDTYPE2,
(3, 3) AS MAR_PRDTYPE3,
(4, 1) AS APR_PRDTYPE1
)
);
JAN_PRDTYPE1 FEB_PRDTYPE2 MAR_PRDTYPE3 APR_PRDTYPE1
------------ ------------ ------------ ------------
38909.04 13367.9 20626.98 120344.7
As you cun see lrom ths output, there were the loowng sues umounts:
S38,909.04 ol product type rl n }unuury
Sl3,367.90 ol product type r2 n lebruury
S20,626.98 ol product type r3 n Murch
Sl20,344.70 ol product type rl n Apr
Using MuItipIc Aggrcgatc functiuns in a Pivut
You cun use mutpe uggregute lunctons n u pvot. lor exumpe, the loowng query uses SUM()
to get the totu sues lor the product types n }unuury und lebruury und AVG() to get the uveruges
ol the sues:
SELECT *
FROM (
SELECT month, prd_type_id, amount
FROM all_sales
WHERE year = 2003
AND prd_type_id IN (1, 2, 3)
)
248
Cruce Dutubuse ll SQL
PIVOT (
SUM(amount) AS sum_amount,
AVG(amount) AS avg_amount
FOR (month) IN (
1 AS JAN, 2 AS FEB
)
)
ORDER BY prd_type_id;
PRD_TYPE_ID JAN_SUM_AMOUNT JAN_AVG_AMOUNT FEB_SUM_AMOUNT FEB_AVG_AMOUNT
----------- -------------- -------------- -------------- --------------
1 38909.04 6484.84 70567.9 11761.3167
2 14309.04 2384.84 13367.9 2227.98333
3 24909.04 4151.50667 15467.9 2577.98333
As you cun see, the lrst ne ol output shows lor product type rl:
A totu ol S38,909.04 und un uveruge ol S6,484.84 sod n }unuury
A totu ol S70,567.90 und un uveruge ol Sll,76l.32 sod n lebruury
1he second ne ol output shows lor product type r2:
A totu ol Sl4,309.04 und un uveruge ol S2,384.84 sod n }unuury
A totu ol Sl3,367.90 und un uveruge ol S2,227.98 sod n lebruury
.und so on lor the rest ol the output.
Using thc UNPlVOT CIausc
1he UNPIVOT cuuse rotutes coumns nto rows. 1he exumpes n ths secton use the loowng
tube numed pivot_sales_data (creuted by the store_schema.sql scrpt), pivot_
sales_data s popuuted by u query thut returns u pvoted verson ol the sues dutu:
CREATE TABLE pivot_sales_data AS
SELECT *
FROM (
SELECT month, prd_type_id, amount
FROM all_sales
WHERE year = 2003
AND prd_type_id IN (1, 2, 3)
)
PIVOT (
SUM(amount) FOR month IN (1 AS JAN, 2 AS FEB, 3 AS MAR, 4 AS APR)
)
ORDER BY prd_type_id;
1he loowng query returns the contents ol the pivot_sales_data tube:
SELECT *
FROM pivot_sales_data;
Chupter 7: Advunced Queres
249
PRD_TYPE_ID JAN FEB MAR APR
----------- ---------- ---------- ---------- ----------
1 38909.04 70567.9 91826.98 120344.7
2 14309.04 13367.9 16826.98 15664.7
3 24909.04 15467.9 20626.98 23844.7
1he next query uses UNPIVOT to get the sues dutu n un unpvoted lorm:
SELECT *
FROM pivot_sales_data
UNPIVOT (
amount FOR month IN (JAN, FEB, MAR, APR)
)
ORDER BY prd_type_id;
PRD_TYPE_ID MON AMOUNT
----------- --- ----------
1 JAN 38909.04
1 FEB 70567.9
1 MAR 91826.98
1 APR 120344.7
2 JAN 14309.04
2 FEB 13367.9
2 APR 15664.7
2 MAR 16826.98
3 JAN 24909.04
3 MAR 20626.98
3 FEB 15467.9
3 APR 23844.7
Notce thut the query rotutes the pvoted dutu. lor exumpe, the monthy sues totus thut
uppeur n the horzontu rows ol pivot_sales_data ure shown n the vertcu AMOUNT
coumn.
TlP
Condcr ung UNPIVOT vhcn ,ou havc a qucr, |ha| rc|urn rov
v|h man, coumn and ,ou van| |o vcv |hoc coumn a rov.
Summary
ln ths chupter, you eurned the loowng:
1he set operutors (UNION ALL, UNION, INTERSECT, und MINUS) uow you to combne
rows returned by two or more queres.
TRANSLATE(x, from_string, to_string) trunsutes churucters n one strng to
churucters n unother strng.
DECODE(value, search_value, result, default_value) compures value
wth search_value. ll the vuues ure equu, DECODE() returns search_value,
otherwse default_value s returned. DECODE() uows you to perlorm l-then-ese
ogc n SQL.

Cruce Dutubuse ll SQL
CASE s smur to DECODE(). You shoud use CASE becuuse t s ANSl-compunt.
Queres muy be run ugunst dutu thut s orgunzed nto u herurchy.
ROLLUP extends the GROUP BY cuuse to return u row contunng u subtotu lor euch
group ol rows, pus u row contunng u grund totu lor u the groups.
CUBE extends the GROUP BY cuuse to return rows contunng u subtotu lor u
combnutons ol coumns, pus u row contunng the grund totu.
1he dutubuse hus muny but-n unuytc lunctons thut enube you to perlorm compex
cucuutons, such us lndng the top-seng product type lor euch month, the top
suespersons, und so on.
1he MODEL cuuse perlorms nter-row cucuutons und uows you to treut tube dutu
us un urruy. 1hs gves you the ubty to perlorm cucuutons n u smur munner to
spreudsheet cucuutons.
1he Cruce Dutubuse ll PIVOT und UNPIVOT cuuses ure uselu lor seeng overu
trends n urge umounts ol dutu.
ln the next chupter, you' eurn ubout chungng the contents ol u tube.

Chungng 1ube Contents


25l
2S2
Cruce Dutubuse ll SQL
n ths chupter, you' eurn more ubout chungng the contents ol tubes. Speclcuy,
you' eurn the loowng:
How to udd, modly, und remove rows usng the INSERT, UPDATE, und DELETE
stutements
How dutubuse trunsuctons muy consst ol mutpe INSERT, UPDATE, und DELETE
stutements
How to muke the resuts ol your trunsuctons permunent usng the COMMIT stutement or
undo ther resuts entrey usng the ROLLBACK stutement
How un Cruce dutubuse cun process mutpe trunsuctons ut the sume tme
How to use query lushbucks to vew rows us they orgnuy were belore you mude
chunges to them
Adding Ruws Using thc lNSfRT Statcmcnt
You use the INSERT stutement to udd rows to u tube. You cun specly the loowng nlormuton
n un INSERT stutement:
1he tube nto whch the row s to be nserted
A st ol coumns lor whch you wunt to specly coumn vuues
A st ol vuues to store n the specled coumns
\hen uddng u row, you typcuy suppy u vuue lor the prmury key und u other coumns
thut ure delned us NOT NULL. You don't huve to specly vuues lor NULL coumns l you don't
wunt to, by deluut they w be set to nu.
You cun lnd out whch coumns ure delned us NOT NULL usng the SQL*lus DESCRIBE
commund. 1he loowng exumpe descrbes the customers tube:
DESCRIBE customers
Name Null? Type
----------------------------------------- -------- ------------
CUSTOMER_ID NOT NULL NUMBER(38)
FIRST_NAME NOT NULL VARCHAR2(10)
LAST_NAME NOT NULL VARCHAR2(10)
DOB DATE
PHONE VARCHAR2(12)
As you cun see, the customer_id, first_name, und last_name coumns ure NOT NULL,
meunng thut you must suppy u vuue lor these coumns. 1he dob und phone coumns don't
requre u vuue: ll you omt these vuues when uddng u row, the coumns woud be set to nu.
1he loowng INSERT stutement udds u row to the customers tube. Notce thut the order
ol vuues n the VALUES cuuse mutches the order n whch the coumns ure specled n the
coumn st. Aso notce thut the stutement hus three purts: the tube nume, the coumn st, und
the vuues to be udded:

Chupter 8: Chungng 1ube Contents


2S3
INSERT INTO customers (
customer_id, first_name, last_name, dob, phone
) VALUES (
6, 'Fred', 'Brown', '01-JAN-1970', '800-555-1215'
);
1 row created.
SQL*lus responds thut one row hus been creuted. You cun verly ths by perlormng the
loowng SELECT stutement:
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
6 Fred Brown 01-JAN-70 800-555-1215
Notce the new row uppeurs n the resuts returned by the query.
Omitting thc CuIumn list
You muy omt the coumn st when suppyng vuues lor every coumn, us n ths exumpe:
INSERT INTO customers
VALUES (7, 'Jane', 'Green', '01-JAN-1970', '800-555-1216');
\hen you omt the coumn st, the order ol the vuues you suppy must mutch the order ol
the coumns us sted n the output lrom the DESCRIBE commund.
Spccifying a NuII VaIuc fur a CuIumn
You cun specly u nu vuue lor u coumn usng the NULL keyword. lor exumpe, the loowng
INSERT specles u nu vuue lor the dob und phone coumns:
INSERT INTO customers
VALUES (8, 'Sophie', 'White', NULL, NULL);
\hen you vew ths row usng u query, you won't see u vuue lor the dob und phone
coumns, becuuse they've been set to nu vuues:
SELECT *
FROM customers
WHERE customer_id = 8;
CUSTOMER_ID FIRST_NAME LAST_NAME DOB PHONE
----------- ---------- ---------- --------- ------------
8 Sophie White
Notce the dob und phone coumn vuues ure bunk.
2S4
Cruce Dutubuse llg SQL
lncIuding SingIc and DuubIc Quutcs in a CuIumn VaIuc
You cun ncude u snge und doube quote n u coumn vuue. lor exumpe, the loowng
INSERT specles u ust nume ol O'Malley lor u new customer, notce the use ol two snge
quotes n the ust nume ulter the etter O:
INSERT INTO customers
VALUES (9, 'Kyle', 'O''Malley', NULL, NULL);
1he next exumpe specles the nume The "Great" Gatsby lor u new product:
INSERT INTO products (
product_id, product_type_id, name, description, price
) VALUES (
13, 1, 'The "Great" Gatsby', NULL, 12.99
);
Cupying Ruws frum Onc TabIc tu Anuthcr
You cun copy rows lrom one tube to unother usng u query n the puce ol the coumn vuues n
the INSERT stutement. 1he number ol coumns und the coumn types n the source und
destnuton must mutch. 1he loowng exumpe uses u SELECT to retreve the first_name und
last_name coumns lor customer rl und suppes those coumns to un INSERT stutement:
INSERT INTO customers (customer_id, first_name, last_name)
SELECT 10, first_name, last_name
FROM customers
WHERE customer_id = 1;
Notce thut the customer_id lor the new row s set to 10.
NOTf
Cracc Da|abac 9 n|roduccd |hc MERGE |a|cmcn|, vhch aov
,ou |o mcrgc rov |rom onc |abc |o ano|hcr. MERGE much morc
|cxbc |han combnng an INSERT and a SELECT |o cop, rov |rom
onc |abc |o ano|hcr. You' carn abou| MERGE a|cr n |hc cc|on
\crgng Rov Lng \RC."
Mudifying Ruws Using thc UPDATf Statcmcnt
You use the UPDATE stutement to modly rows n u tube. \hen you use the UPDATE stutement,
you typcuy specly the loowng nlormuton:
1he tube nume
A WHERE cuuse thut specles the rows to be chunged
A st ol coumn numes, uong wth ther new vuues, specled usng the SET cuuse
You cun chunge one or more rows usng the sume UPDATE stutement. ll more thun one row s
specled, the sume chunge w be mpemented lor u ol those rows. lor exumpe, the loowng
UPDATE stutement sets the last_name coumn to Orange lor the row whose customer_id s 2:
Chupter 8: Chungng 1ube Contents
2SS
UPDATE customers
SET last_name = 'Orange'
WHERE customer_id = 2;
1 row updated.
SQL*lus conlrms thut one row wus upduted. ll the WHERE cuuse were omtted, then u the
rows woud be upduted. 1he loowng query conlrms the chunge wus mude:
SELECT *
FROM customers
WHERE customer_id = 2;
CUSTOMER_ID FIRST_NAME LAST_NAME DOB PHONE
----------- ---------- ---------- --------- ------------
2 Cynthia Orange 05-FEB-68 800-555-1212
You cun chunge mutpe rows und mutpe coumns n the sume UPDATE stutement. lor
exumpe, the loowng UPDATE ruses the prce by 20 percent lor u products whose current
prce s greuter thun or equu to S20. 1he UPDATE uso chunges those products' numes to
owercuse:
UPDATE products
SET
price = price * 1.20,
name = LOWER(name)
WHERE
price >= 20;
3 rows updated.
As you cun see, three rows ure upduted by ths stutement. 1he loowng query conlrms the
chunge:
SELECT product_id, name, price
FROM products
WHERE price >= (20 * 1.20);
ID NAME PRICE
---------- ------------------------------ ----------
2 chemistry 36
3 supernova 31.19
5 z-files 59.99
NOTf
You can ao uc a ubqucr, v|h an UPDATE |a|cmcn|. Th
covcrcd n Chap|cr n |hc cc|on Vr|ng an LDAT S|a|cmcn|
Con|anng a Subqucr,."
Thc RfTURNlNG CIausc
ln Cruce Dutubuse l0g und ubove, you cun use the RETURNING cuuse to return the vuue lrom
un uggregute luncton such us AVG(). Aggregute lunctons were covered n Chupter 4.
2S6
Cruce Dutubuse llg SQL
1he loowng tusks ure perlormed by the next exumpe:
Decures u vurube numed average_product_price
Decreuses the price coumn ol the rows n the products tube und suves the uveruge
prce n the average_product_price vurube usng the RETURNING cuuse
lrnts the vuue ol the average_product_price vurube
VARIABLE average_product_price NUMBER
UPDATE products
SET price = price * 0.75
RETURNING AVG(price) INTO :average_product_price;
12 rows updated.
PRINT average_product_price
AVERAGE_PRODUCT_PRICE
---------------------
16.1216667
Rcmuving Ruws Using thc DflfTf Statcmcnt
You use the DELETE stutement to remove rows lrom u tube. Ceneruy, you shoud specly u
WHERE cuuse thut mts the rows thut you wsh to deete, l you don't, a the rows w be
deeted.
1he loowng DELETE stutement removes the row lrom the customers tube whose
customer_id s l0:
DELETE FROM customers
WHERE customer_id = 10;
1 row deleted.
SQL*lus conlrms thut one row hus been deeted.
You cun uso use u subquery wth u DELETE stutement. 1hs s covered n Chupter 6 n the
secton \rtng u DLLL1L Stutement Contunng u Subquery.
NOTf
| ,ou'vc bccn |oovng aong v|h |hc prcvou INSERT, UPDATE,
and DELETE |a|cmcn|, ro |hcm bac| ung ROLLBACK o |ha| ,our
rcu| ma|ch |hoc hovn n |hc rc| o| |h chap|cr. Don'| vorr,
| ,ou'vc arcad, dconncc|cd |rom |hc da|abac: mp, rcrun |hc
store_schema.sql crp| |o rc-crca|c cvcr,|hng.
Databasc lntcgrity
\hen you execute u DML stutement (un INSERT, UPDATE, or DELETE, lor exumpe), the dutubuse
ensures thut the rows n the tubes muntun ther ntegrty. 1hs meuns thut uny chunges mude to
the rows do not ullect the prmury key und loregn key reutonshps lor the tubes.
Chupter 8: Chungng 1ube Contents
2S7
fnfurccmcnt uf Primary kcy Cunstraints
Let's exumne some exumpes thut show the enlorcement ol u prmury key construnt. 1he
customers tube's prmury key s the customer_id coumn, whch meuns thut every vuue
stored n the customer_id coumn must be unque. ll you try to nsert u row wth u dupcute
vuue lor u prmury key, the dutubuse returns the error ORA-00001, us n ths exumpe:
SQL> INSERT INTO customers (
2 customer_id, first_name, last_name, dob, phone
3 ) VALUES (
4 1, 'Jason', 'Price', '01-JAN-60', '800-555-1211'
5 );
INSERT INTO customers (
*
ERROR at line 1:
ORA-00001: unique constraint (STORE.CUSTOMERS_PK) violated
ll you uttempt to updute u prmury key vuue to u vuue thut ureudy exsts n the tube, the
dutubuse returns the sume error:
SQL> UPDATE customers
2 SET customer_id = 1
3 WHERE customer_id = 2;
UPDATE customers
*
ERROR at line 1:
ORA-00001: unique constraint (STORE.CUSTOMERS_PK) violated
fnfurccmcnt uf furcign kcy Cunstraints
A loregn key reutonshp s one n whch u coumn lrom one tube s relerenced n unother. lor
exumpe, the product_type_id coumn n the products tube relerences the product_
type_id coumn n the product_types tube. 1he product_types tube s known us the
parcn| tube, und the products tube s known us the chd tube, relectng the dependence ol
the product_type_id coumn n the products tube on the product_type_id coumn
n the product_types tube.
ll you try to nsert u row nto the products tube wth u nonexstent product_type_id,
the dutubuse w return the error ORA-02291. 1hs error ndcutes the dutubuse coudn't lnd u
mutchng purent key vuue (the purent key s the product_type_id coumn ol the product_
types tube). ln the loowng exumpe, the error s returned becuuse there s no row n the
product_types tube whose product_type_id s 6:
SQL> INSERT INTO products (
2 product_id, product_type_id, name, description, price
3 ) VALUES (
4 13, 6, 'Test', 'Test', NULL
5 );
INSERT INTO products (
*
ERROR at line 1:
ORA-02291: integrity constraint (STORE.PRODUCTS_FK_PRODUCT_TYPES)
violated - parent key not found
2S8
Cruce Dutubuse llg SQL
Smury, l you uttempt to updute the product_type_id ol u row n the products tube
to u nonexstent purent key vuue, the dutubuse returns the sume error, us n ths exumpe:
SQL> UPDATE products
2 SET product_type_id = 6
3 WHERE product_id = 1;
UPDATE products
*
ERROR at line 1:
ORA-02291: integrity constraint (STORE.PRODUCTS_FK_PRODUCT_TYPES)
violated - parent key not found
lnuy, l you uttempt to deete u row n the purent tube thut hus dependent chd rows,
the dutubuse returns error ORA-02292. lor exumpe, l you uttempt to deete the row whose
product_type_id s l lrom the product_types tube, the dutubuse w return ths error
becuuse the products tube contuns rows whose product_type_id s l:
SQL> DELETE FROM product_types
2 WHERE product_type_id = 1;
DELETE FROM product_types
*
ERROR at line 1:
ORA-02292: integrity constraint (STORE.PRODUCTS_FK_PRODUCT_TYPES)
violated - child record found
ll the dutubuse were to uow ths deeton, the chd rows woud be nvud becuuse they
woudn't pont to vud vuues n the purent tube.
Using DcfauIt VaIucs
Cruce Dutubuse 9 ntroduced u leuture thut uows you to delne u deluut vuue lor u coumn.
lor exumpe, the loowng stutement creutes u tube numed order_status, the status
coumn s deluuted to 'Order placed' und the last_modified coumn s deluuted to
the dute und tme returned by SYSDATE:
CREATE TABLE order_status (
order_status_id INTEGER
CONSTRAINT default_example_pk PRIMARY KEY,
status VARCHAR2(20) DEFAULT 'Order placed' NOT NULL,
last_modified DATE DEFAULT SYSDATE
);
NOTf
Thc order_status |abc crca|cd b, |hc store_schema.sql
crp|. Th mcan ,ou don'| havc |o |,pc n |hc prcvou CREATE
TABLE |a|cmcn| ,ourc|. Ao, ,ou don'| havc |o |,pc n |hc INSERT
|a|cmcn| hovn n |h cc|on.
\hen you udd u new row to the order_status tube but don't specly the vuues lor the
status und last_modified coumns, those coumns ure set to the deluut vuues. lor exumpe,
the loowng INSERT stutement omts vuues lor the status und last_modified coumns:
Chupter 8: Chungng 1ube Contents
2S9
INSERT INTO order_status (order_status_id)
VALUES (1);
1he status coumn s set to the deluut vuue ol 'Order placed', und the last_modified
coumn s set to the current dute und tme.
You cun overrde the deluuts by speclyng u vuue lor the coumns, us shown n the loowng
exumpe:
INSERT INTO order_status (order_status_id, status, last_modified)
VALUES (2, 'Order shipped', '10-JUN-2004');
1he loowng query retreves the rows lrom order_status:
SELECT *
FROM order_status;
ORDER_STATUS_ID STATUS LAST_MODI
--------------- -------------------- ---------
1 Order placed 25-JUL-07
2 Order shipped 10-JUN-04
You cun set u coumn buck to the deluut usng the DEFAULT keyword n un UPDATE
stutement. lor exumpe, the loowng UPDATE sets the status coumn to the deluut:
UPDATE order_status
SET status = DEFAULT
WHERE order_status_id = 2;
1he loowng query shows the chunge mude by ths UPDATE stutement:
SELECT *
FROM order_status;
ORDER_STATUS_ID STATUS LAST_MODI
--------------- -------------------- ---------
1 Order placed 25-JUL-07
2 Order placed 10-JUN-04
Mcrging Ruws Using MfRGf
Cruce Dutubuse 9 ntroduced the MERGE stutement, whch uows you to merge rows lrom one
tube nto unother. lor exumpe, you mght wunt to merge chunges to products sted n one tube
nto the products tube.
1he store schemu contuns u tube numed product_changes thut wus creuted usng the
loowng CREATE TABLE stutement n store_schema.sql:
CREATE TABLE product_changes (
product_id INTEGER
CONSTRAINT prod_changes_pk PRIMARY KEY,
product_type_id INTEGER
CONSTRAINT prod_changes_fk_product_types
REFERENCES product_types(product_type_id),
name VARCHAR2(30) NOT NULL,

Cruce Dutubuse ll SQL
description VARCHAR2(50),
price NUMBER(5, 2)
);
1he loowng query retreves the product_id, product_type_id, name, und price
coumns lrom ths tube:
SELECT product_id, product_type_id, name, price
FROM product_changes;
PRODUCT_ID PRODUCT_TYPE_ID NAME PRICE
---------- --------------- ------------------------------ ----------
1 1 Modern Science 40
2 1 New Chemistry 35
3 1 Supernova 25.99
13 2 Lunar Landing 15.99
14 2 Submarine 15.99
15 2 Airplane 15.99
Let's suy you wunt to merge the rows lrom the product_changes tube nto the products
tube us loows:
lor rows wth mutchng product_id vuues n the two tubes, updute the exstng rows
n products wth the coumn vuues lrom product_changes. lor exumpe, product
rl hus u dllerent prce n product_changes lrom the one n products, therelore,
product rl's prce must be upduted n the products tube. Smury, product r2 hus u
dllerent nume und prce, so both vuues must be upduted n products. lnuy, product
r3 hus u dllerent product_type_id, und so ths vuue must be upduted n products.
lor new rows n product_changes, nsert those new rows nto the products tube.
lroducts rl3, rl4, und rl5 ure new n product_changes und must therelore be
nserted nto products.
1he eusest wuy to eurn how to use the MERGE stutement s to see un exumpe. 1he loowng
exumpe perlorms the merge us delned n the prevous buet ponts:
MERGE INTO products p
USING product_changes pc ON (
p.product_id = pc.product_id
)
WHEN MATCHED THEN
UPDATE
SET
p.product_type_id = pc.product_type_id,
p.name = pc.name,
p.description = pc.description,
p.price = pc.price
WHEN NOT MATCHED THEN
INSERT (
p.product_id, p.product_type_id, p.name,
p.description, p.price
) VALUES (
Chupter 8: Chungng 1ube Contents

pc.product_id, pc.product_type_id, pc.name,


pc.description, pc.price
);
6 rows merged.

You' |nd a crp| namcd merge_example.sql n |hc SQL


drcc|or,. Th crp| con|an |hc prcvou MERGE |a|cmcn|.
Notce the loowng ponts ubout the MERGE stutement:
1he MERGE INTO cuuse specles the nume ol the tube to merge the rows nto. ln the
exumpe, ths s the products tube, whch s gven un uus ol p.
1he USING ... ON cuuse specles u tube on. ln the exumpe, the on s mude
on the product_id coumns n the products und product_changes tubes. 1he
product_changes tube s uso gven un uus ol pc.
1he WHEN MATCHED THEN cuuse specles the ucton to tuke when the USING ...
ON cuuse s sutsled lor u row. ln the exumpe, ths ucton s un UPDATE stutement thut
sets the product_type_id, name, description, und price coumns ol the exstng
row n the products tube to the coumn vuues lor the mutchng row n the product_
changes tube.
1he WHEN NOT MATCHED THEN cuuse specles the ucton to tuke when the USING
... ON cuuse s no| sutsled lor u row. ln the exumpe, ths ucton s un INSERT
stutement thut udds u row to the products tube, tukng the coumn vuues lrom the
row n the product_changes tube.
ll you run the prevous MERGE stutement, you' see thut t reports sx rows ure merged, these
ure the rows wth product_id vuues ol l, 2, 3, l3, l4, und l5. 1he loowng query retreves
the sx merged rows lrom the products tube:
SELECT product_id, product_type_id, name, price
FROM products
WHERE product_id IN (1, 2, 3, 13, 14, 15);
PRODUCT_ID PRODUCT_TYPE_ID NAME PRICE
---------- --------------- ------------------------------ ----------
1 1 Modern Science 40
2 1 New Chemistry 35
3 1 Supernova 25.99
13 2 Lunar Landing 15.99
14 2 Submarine 15.99
15 2 Airplane 15.99
1he loowng chunges were mude to these rows:
lroduct rl hus u new prce.
lroduct r2 hus u new nume und prce.
262
Cruce Dutubuse llg SQL
lroduct r3 hus u new product type lD.
lroducts rl3, rl4, und rl5 ure new.
Now thut you've seen how to muke chunges to the contents ol tubes, et's move on to
dutubuse trunsuctons.
Databasc Transactiuns
A dutubuse |ranac|on s u group ol SQL stutements thut perlorm u ogca un| o| vor|. You cun
thnk ol u trunsucton us un nsepurube set ol SQL stutements whose resuts shoud be mude
permunent n the dutubuse us u whoe (or undone us u whoe).
An exumpe ol u dutubuse trunsucton s u trunsler ol money lrom one bunk uccount to unother.
Cne UPDATE stutement woud subtruct lrom the totu umount ol money lrom one uccount, und
unother UPDATE woud udd money to the other uccount. oth the subtructon und the uddton
must be permunenty recorded n the dutubuse, otherwse, money w be ost. ll there s u probem
wth the money trunsler, then the subtructon und uddton must both be undone. 1he smpe
exumpe outned n ths purugruph uses ony two UPDATE stutements, but u trunsucton muy
consst ol muny INSERT, UPDATE, und DELETE stutements.
Cummitting and RuIIing Back a Transactiun
1o permunenty record the resuts mude by SQL stutements n u trunsucton, you perlorm u comm|,
usng the SQL COMMIT stutement. ll you need to undo the resuts, you perlorm u robac|, usng
the SQL ROLLBACK stutement, whch resets u the rows buck to whut they were orgnuy.
1he loowng exumpe udds u row to the customers tube und then mukes the chunge
permunent by perlormng u COMMIT:
INSERT INTO customers
VALUES (6, 'Fred', 'Green', '01-JAN-1970', '800-555-1215');
1 row created.
COMMIT;
Commit complete.
1he loowng exumpe updutes customer rl und then undoes the chunge by perlormng u
ROLLBACK:
UPDATE customers
SET first_name = 'Edward'
WHERE customer_id = 1;
1 row updated.
ROLLBACK;
Rollback complete.
Chupter 8: Chungng 1ube Contents
263
1he loowng query shows the new row lrom the COMMIT stutement:
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
6 Fred Green 01-JAN-70 800-555-1215
Notce thut customer r6 hus been mude permunent by the COMMIT, but the chunge to
customer rl's lrst nume hus been undone by the ROLLBACK.
Starting and fnding a Transactiun
A trunsucton s u ogcu unt ol work thut enubes you to spt up your SQL stutements. A
trunsucton hus u begnnng und un end, t begns when one ol the loowng events occurs:
You connect to the dutubuse und perlorm u DML stutement (un INSERT, UPDATE,
or DELETE).
A prevous trunsucton ends und you enter unother DML stutement.
A trunsucton ends when one ol the loowng events occurs:
You perlorm u COMMIT or u ROLLBACK.
You perlorm u DDL stutement, such us u CREATE TABLE stutement, n whch cuse u
COMMIT s uutomutcuy perlormed.
You perlorm u DCL stutement, such us u GRANT stutement, n whch cuse u COMMIT s
uutomutcuy perlormed. You' eurn ubout GRANT n the next chupter.
You dsconnect lrom the dutubuse. ll you ext SQL*lus normuy, by enterng the
EXIT commund, u COMMIT s uutomutcuy perlormed lor you. ll SQL*lus termnutes
ubnormuylor exumpe, l the computer on whch SQL*lus wus runnng were to
crushu ROLLBACK s uutomutcuy perlormed. 1hs uppes to uny progrum thut
uccesses u dutubuse. lor exumpe, l you wrote u }uvu progrum thut uccessed u dutubuse
und your progrum crushed, u ROLLBACK woud be uutomutcuy perlormed.
You perlorm u DML stutement thut lus, n whch cuse u ROLLBACK s uutomutcuy
perlormed lor thut ndvduu DML stutement.
TlP
| poor prac|cc no| |o cxpc|, comm| or ro bac| ,our |ranac|on,
o pcr|orm a COMMIT or ROLLBACK a| |hc cnd o| ,our |ranac|on.
264
Cruce Dutubuse llg SQL
Savcpuints
You cun uso set u avcpon| ut uny pont wthn u trunsucton. 1hese uow you to ro buck chunges
to thut suvepont. Suveponts cun be uselu to breuk up very ong trunsuctons, becuuse, l you muke
u mstuke ulter you've set u suvepont, you don't huve to ro buck the trunsucton u the wuy to
the sturt. However, you shoud use suveponts spurngy: you mght be better oll restructurng your
trunsucton nto smuer trunsuctons nsteud.
You' see un exumpe ol u suvepont shorty, but lrst et's see the current prce lor products r4
und r5:
SELECT product_id, price
FROM products
WHERE product_id IN (4, 5);
PRODUCT_ID PRICE
---------- ----------
4 13.95
5 49.99
1he prce lor product r4 s Sl3.95, und the prce lor product r5 s S49.99. 1he loowng
UPDATE ncreuses the prce ol product r4 by 20 percent:
UPDATE products
SET price = price * 1.20
WHERE product_id = 4;
1 row updated.
1he loowng stutement sets u suvepont numed save1:
SAVEPOINT save1;
Savepoint created.
Any DML stutements run ulter ths pont cun be roed buck to the suvepont, und the chunge
mude to product r4 w be kept.
1he loowng UPDATE ncreuses the prce ol product r5 by 30 percent:
UPDATE products
SET price = price * 1.30
WHERE product_id = 5;
1 row updated.
1he loowng query gets the prces ol the two products:
SELECT product_id, price
FROM products
WHERE product_id IN (4, 5);
PRODUCT_ID PRICE
---------- ----------
4 16.74
5 64.99
Chupter 8: Chungng 1ube Contents
26S
lroduct r4's prce s 20 percent greuter, und product r5's prce s 30 percent greuter. 1he
loowng stutement ros buck the trunsucton to the suvepont estubshed eurer:
ROLLBACK TO SAVEPOINT save1;
Rollback complete.
1hs hus undone the prce chunge lor product r5, but elt the prce chunge lor product r4
ntuct. 1he loowng query shows ths:
SELECT product_id, price
FROM products
WHERE product_id IN (4, 5);
PRODUCT_ID PRICE
---------- ----------
4 16.74
5 49.99
As expected, product r4 hus kept ts ncreused prce, but product r5's prce s buck to the
orgnu. 1he loowng ROLLBACK undoes the entre trunsucton:
ROLLBACK;
Rollback complete.
1hs hus undone the chunge mude to product r4's prce, us s shown by the loowng query:
SELECT product_id, price
FROM products
WHERE product_id IN (4, 5);
PRODUCT_ID PRICE
---------- ----------
4 13.95
5 49.99
AClD Transactiun Prupcrtics
Lurer, l delned u trunsucton us beng u ogca un| o| vor|, thut s, u group ol reuted SQL
stutements thut ure ether comm||cd or rocd bac| us one unt. Dutubuse theory's more rgorous
delnton ol u trunsucton stutes thut u trunsucton hus lour lundumentu propertes, known us
ACD propertes (lrom the lrst etter ol euch property n the loowng st):
Atumic 1runsuctons ure utomc, meunng thut the SQL stutements contuned n u
trunsucton muke up u snge unt ol work.
Cunsistcnt 1runsuctons ensure thut the dutubuse stute remuns consstent, meunng thut
the dutubuse s n u consstent stute when u trunsucton begns und thut t ends n unother
consstent stute when the trunsucton lnshes.
lsuIatcd Sepurute trunsuctons shoud not nterlere wth euch other.
DurabIc Cnce u trunsucton hus been commtted, the dutubuse chunges ure preserved,
even l the muchne on whch the dutubuse soltwure s runnng crushes uter.
266
Cruce Dutubuse llg SQL
1he Cruce dutubuse soltwure hundes these AClD propertes und hus extensve recovery
luctes lor restorng dutubuses ulter system crushes.
Cuncurrcnt Transactiuns
1he Cruce dutubuse soltwure supports muny users nteructng wth u dutubuse, und euch user cun
run ther own trunsuctons ut the sume tme. 1hese trunsuctons ure known us concurrcn| trunsuctons.
ll users ure runnng trunsuctons thut ullect the sume tube, the ellects ol those trunsuctons ure
sepuruted lrom euch other unt u COMMIT s perlormed. 1he loowng sequence ol events, bused
on two trunsuctons numed 1l und 12 thut uccess the customers tube, ustrutes the sepuruton
ol trunsuctons:
1. 1l und 12 perlorm u SELECT thut retreves u the rows lrom the customers tube.
2. 1l perlorms un INSERT to udd u row n the customers tube, but 1l doesn't perlorm u
COMMIT.
3. 12 perlorms unother SELECT und retreves the sume rows us those n step l. 12 doesn't
see the new row udded by 1l n step 2.
4. 1l lnuy perlorms u COMMIT to permunenty record the new row udded n step 2.
S. 12 perlorms unother SELECT und lnuy sees the new row udded by 1l.
1o summurze: 12 doesn't see the chunges mude by 1l unt 1l commts ts chunges. 1hs s
the deluut eve ol souton between trunsuctons, but, us you' eurn uter n the secton 1runsucton
lsouton Leves, you cun chunge the eve ol souton.
1ube 8-l shows sumpe SQL stutements thut lurther ustrute how concurrent trunsuctons work.
1he tube shows the ntereuved order n whch the stutements ure perlormed by two trunsuctons
numed 1l und 12. 1l retreves rows, udds u row, und updutes u row n the customers tube. 12
retreves rows lrom the customers tube. 12 doesn't see the chunges mude by 1l unt 1l commts
ts chunges. You cun enter the stutements shown n 1ube 8-l und see ther resuts by sturtng two
sepurute SQL*lus sessons und connectng us the store user lor both sessons, you enter the
stutements n the ntereuved order shown n the tube nto the SQL*lus sessons.
Transactiun lucking
1o support concurrent trunsuctons, the Cruce dutubuse soltwure must ensure thut the dutu n the
tubes remuns vud. lt does ths through the use ol oc|. Consder the loowng exumpe n whch
two trunsuctons numed 1l und 12 uttempt to modly customer rl n the customers tube:
1. 1l perlorms un UPDATE to modly customer rl, but 1l doesn't perlorm u COMMIT. 1l s
sud to huve ocked the row.
2. 12 uso uttempts to perlorm un UPDATE to modly customer rl, but snce ths row s
ureudy ocked by 1l, 12 s prevented lrom gettng u ock on the row. 12's UPDATE
stutement hus to wut unt 1l ends und lrees the ock on the row.
3. 1l ends by perlormng u COMMIT, thus lreeng the ock on the row.
4. 12 gets the ock on the row und the UPDATE s perlormed. 12 hods the ock on the row
unt 12 ends.
1o summurze: A trunsucton cunnot get u ock on u row whe unother trunsucton ureudy
hods the ock on thut row.
Chupter 8: Chungng 1ube Contents
267
NOTf
Thc cac| va, |o undcr|and dc|au| oc|ng a |oov: reuders
don't bock reuders, wrters don't bock reuders, und wrters ony bock
wrters when they uttempt to modly the sume row.
Transactiun lsuIatiun lcvcIs
1he |ranac|on oa|on cvc s the degree to whch the chunges mude by one trunsucton ure
sepuruted lrom other trunsuctons runnng concurrenty. elore you see the vurous trunsucton
souton eves uvuube, you need to understund the types ol probems thut muy occur when
current trunsuctons uttempt to uccess the sume rows n u tube.
ln the loowng st, you' see exumpes ol two concurrent trunsuctons numed 1l und 12 thut
ure uccessng the sume rows, sted ure the three types ol potentu trunsucton processng probems:
Phantum rcads 1l reuds u set ol rows returned by u specled WHERE cuuse. 12
then nserts u new row, whch uso huppens to sutsly the WHERE cuuse ol the query
prevousy used by 1l. 1l then reuds the rows ugun usng the sume query, but now sees
Transactiun 1 T1 Transactiun 2 T2
(l) SELECT *
FROM customers;
(2) SELECT *
FROM customers;
(3) INSERT INTO customers (
customer_id, first_name, last_name
) VALUES (
7, 'Jason', 'Price'
);
(4) UPDATE customers
SET last_name = 'Orange'
WHERE customer_id = 2;
(5) SELECT *
FROM customers;
1he returned resut set contuns the new row und
the updute.
(6) SELECT *
FROM customers;
1he returned resut set doesn't contun
the new row or the updute mude by
1l. lnsteud, the resut set contuns the
orgnu rows retreved n step 2.
(7) COMMIT;
1hs commts the new row und the updute.
(8) SELECT *
FROM customers;
1he returned resut set contuns the
new row und the updute mude by 1l
n steps 3 und 4.
TABlf 8-1 Concurrcn| Tranac|on
268
Cruce Dutubuse llg SQL
the uddtonu row ust nserted by 12. 1hs new row s known us u phuntom becuuse to
1l ths row seems to huve mugcuy uppeured.
NunrcpcatabIc rcads 1l reuds u row, und 12 updutes the sume row ust reud by 1l. 1l
then reuds the sume row ugun und dscovers thut the row t reud eurer s now dllerent.
1hs s known us u nonrepeutube reud, becuuse the row orgnuy reud by 1l hus been
chunged.
Dirty rcads 1l updutes u row, but doesn't commt the updute. 12 then reuds the
upduted row. 1l then perlorms u robuck, undong the prevous updute. Now the row
ust reud by 12 s no onger vud (t's drty) becuuse the updute mude by 1l wusn't
commtted when the row wus reud by 12.
1o deu wth these potentu probems, dutubuses mpement vurous eves ol trunsucton
souton to prevent concurrent trunsuctons lrom nterlerng wth euch other. 1he SQL stundurd
delnes the loowng trunsucton souton eves, shown n order ol ncreusng souton:
RfAD UNCOMMlTTfD lhuntom reuds, nonrepeutube reuds, und drty reuds ure
permtted.
RfAD COMMlTTfD lhuntom reuds und nonrepeutube reuds ure permtted, but drty
reuds ure not.
RfPfATABlf RfAD lhuntom reuds ure permtted, but nonrepeutube und drty reuds
ure not.
SfRlAllZABlf lhuntom reuds, nonrepeutube reuds, und drty reuds ure not permtted.
1he Cruce dutubuse soltwure supports the READ COMMITTED und SERIALIZABLE trunsucton
souton eves. lt doesn't support READ UNCOMMITTED or REPEATABLE READ eves.
1he deluut trunsucton souton eve delned by the SQL stundurd s SERIALIZABLE, but
the deluut used by the Cruce dutubuse s READ COMMITTED, whch s ucceptube lor neury u
uppcutons.
CAUTlON
A|hough ,ou can uc SERIALIZABLE v|h |hc Cracc da|abac,
| ma, ncrcac |hc |mc ,our S |a|cmcn| |a|c |o compc|c. You
houd on, uc SERIALIZABLE | ,ou abou|c, havc |o.
You set the trunsucton souton eve usng the SET TRANSACTION stutement. lor exumpe,
the loowng stutement sets the trunsucton souton eve to SERIALIZABLE:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Chupter 8: Chungng 1ube Contents
269
You' see un exumpe ol u trunsucton thut uses the souton eve ol SERIALIZABLE next.
A SfRlAllZABlf Transactiun fxampIc
ln ths secton, you' see un exumpe thut shows the ellect ol settng the trunsucton souton eve
to SERIALIZABLE.
1he exumpe uses two trunsuctons numed 1l und 12. 1l hus the deluut souton eve ol READ
COMMITTED, 12 hus u trunsucton souton eve ol SERIALIZABLE. 1l und 12 w reud the
rows n the customers tube, und then 1l w nsert u new row und updute un exstng row n
the customers tube. ecuuse 12 s SERIALIZABLE, t doesn't see the nserted row or the updute
mude to the exstng row mude by 1l, even a||cr 1l commts ts chunges. 1hut's becuuse reudng
the nserted row woud be u phuntom reud, und reudng the updute woud be u nonrepeutube
reud, whch ure not permtted by SERIALIZABLE trunsuctons.
1ube 8-2 shows the SQL stutements thut muke up 1l und 12 n the ntereuved order n whch
the stutements ure to be perlormed.
Transactiun 1 T1 (RfAD COMMlTTfD) Transactiun 2 T2 (SfRlAllZABlf)
(l) SET TRANSACTION ISOLATION
LEVEL SERIALIZABLE;
(3) SELECT *
FROM customers;
(2) SELECT *
FROM customers;
(4) INSERT INTO customers (
customer_id, first_name, last_name
) VALUES (
8, 'Steve', 'Button'
);
(5) UPDATE customers
SET last_name = 'Yellow'
WHERE customer_id = 3;
(6) COMMIT;
(7) SELECT *
FROM customers;
1he returned resut set contuns the new row und
the updute.
(8) SELECT *
FROM customers;
1he returned resut set | doesn't
contun the new row or the updute
mude by 1l. 1hut's becuuse 12 s
SERIALIZABLE.
TABlf 8-2 SERIALIZABLE Tranac|on
270
Cruce Dutubuse llg SQL
Qucry fIashbacks
ll you mstukeny commt chunges und you wunt to vew rows us they orgnuy were, you cun
use u query lushbuck. You cun then use the resuts ol u query lushbuck to munuuy chunge rows
buck to ther orgnu vuues l you need to.
Query lushbucks cun be bused on u dutetme or system chunge number (SCN). 1he dutubuse
uses SCNs to truck chunges mude to dutu, und you cun use them to lush buck to u purtcuur SCN
n the dutubuse.
Granting thc PriviIcgc fur Using fIashbacks
lushbucks use the lL/SQL DBMS_FLASHBACK puckuge, lor whch you must huve the EXECUTE
prvege to run. 1he loowng exumpe connects us the sys user und grunts the EXECUTE
prvege on DBMS_FLASHBACK to the store user:
CONNECT sys/change_on_install AS sysdba
GRANT EXECUTE ON SYS.DBMS_FLASHBACK TO store;
NOTf
Spca| v|h ,our DA | ,ou arc unabc |o pcr|orm |hcc |a|cmcn|.
You' carn abou| prvcgc n |hc ncx| chap|cr, and ,ou' carn abou|
/S pac|agc n Chap|cr 11.
Timc Qucry fIashbacks
1he loowng exumpe connects us store und retreves the product_id, name, und price
coumns lor the lrst lve rows lrom the products tube:
CONNECT store/store_password
SELECT product_id, name, price
FROM products
WHERE product_id <= 5;
PRODUCT_ID NAME PRICE
---------- ------------------------------ ----------
1 Modern Science 19.95
2 Chemistry 30
3 Supernova 25.99
4 Tank War 13.95
5 Z Files 49.99
NOTf
| ,ou cc d||crcn| prcc |or an, o| |hcc produc|, go ahcad and
rcrun |hc store_schema.sql |c.
1he next exumpe reduces the prce ol these rows, commts the chunge, und retreves the rows
ugun so you cun see the new prces:
UPDATE products
SET price = price * 0.75
WHERE product_id <= 5;
Chupter 8: Chungng 1ube Contents
271
COMMIT;
SELECT product_id, name, price
FROM products
WHERE product_id <= 5;
PRODUCT_ID NAME PRICE
---------- ------------------------------ ----------
1 Modern Science 14.96
2 Chemistry 22.5
3 Supernova 19.49
4 Tank War 10.46
5 Z Files 37.49
1he loowng stutement executes the DBMS_FLASHBACK.ENABLE_AT_TIME() procedure,
whch enubes you to perlorm u lushbuck to u purtcuur dutetme, notce the DBMS_
FLASHBACK.ENABLE_AT_TIME() procedure uccepts u dutetme und the exumpe pusses
SYSDATE 10 / 1440 to the procedure (ths expresson evuuutes to u dutetme ten mnutes
n the pust):
EXECUTE DBMS_FLASHBACK.ENABLE_AT_TIME(SYSDATE 10 / 1440);
NOTf
24 hour 0 mnu|c pcr hour = 1440 mnu|c. Thcrc|orc SYSDATE
10 / 1440 a da|c|mc |cn mnu|c n |hc pa|.
Any queres you execute now w dspuy the rows us they were ten mnutes ugo. Assumng
you perlormed the eurer UPDATE ess thun ten mnutes ugo, the loowng query w dspuy the
prces us they were belore you upduted them:
SELECT product_id, name, price
FROM products
WHERE product_id <= 5;
PRODUCT_ID NAME PRICE
---------- ------------------------------ ----------
1 Modern Science 19.95
2 Chemistry 30
3 Supernova 25.99
4 Tank War 13.95
5 Z Files 49.99
1o dsube u lushbuck, you execute DBMS_FLASHBACK.DISABLE(), us shown n the
loowng exumpe:
EXECUTE DBMS_FLASHBACK.DISABLE();
CAUTlON
You mu| dabc a |ahbac| bc|orc ,ou can cnabc | agan.
272
Cruce Dutubuse ll SQL
Now when you perlorm queres, the rows us they currenty exst w be retreved, us
shown here:
SELECT product_id, name, price
FROM products
WHERE product_id <= 5;
PRODUCT_ID NAME PRICE
---------- ------------------------------ ----------
1 Modern Science 14.96
2 Chemistry 22.5
3 Supernova 19.49
4 Tank War 10.46
5 Z Files 37.49
Systcm Changc Numbcr Qucry fIashbacks
lushbucks bused on system chunge numbers (SCNs) cun be more precse thun those bused on u
tme, becuuse the dutubuse uses SCNs to truck chunges mude to dutu. 1o get the current SCN, you
cun execute DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER(), us shown n the loowng
exumpe:
VARIABLE current_scn NUMBER
EXECUTE :current_scn := DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER();
PRINT current_scn
CURRENT_SCN
-----------
292111
1he next exumpe udds u row to the products tube, commts the chunge, und retreves the
new row:
INSERT INTO products (
product_id, product_type_id, name, description, price
) VALUES (
15, 1, 'Physics', 'Textbook on physics', 39.95
);
COMMIT;
SELECT *
FROM products
WHERE product_id = 15;
PRODUCT_ID PRODUCT_TYPE_ID NAME
---------- --------------- ------------------------------
DESCRIPTION PRICE
-------------------------------------------------- ----------
15 1 Physics
Textbook on physics 39.95
Chupter 8: Chungng 1ube Contents
273
1he next exumpe executes the loowng procedure, DBMS_FLASHBACK.ENABLE_AT_
SYSTEM_CHANGE_NUMBER(), whch enubes you to perlorm u lushbuck to un SCN, notce thut
ths procedure uccepts un SCN und thut the exumpe pusses the current_scn vurube to the
procedure:
EXECUTE DBMS_FLASHBACK.ENABLE_AT_SYSTEM_CHANGE_NUMBER(:current_scn);
Any queres you execute now w dspuy the rows us they were ut the SCN stored n
current_scn belore you perlormed the INSERT. 1he loowng query uttempts to get the
row wth u product_id ol l5, t lus becuuse thut new row wus udded ulter the SCN stored
n current_scn:
SELECT product_id
FROM products
WHERE product_id = 15;
no rows selected
1o dsube u lushbuck, you execute DBMS_FLASHBACK.DISABLE(), us shown n the
loowng exumpe:
EXECUTE DBMS_FLASHBACK.DISABLE();
ll you perlorm the prevous query ugun, you' see the new row thut wus udded by the INSERT.
NOTf
| ,ou |oovcd aong v|h |hc cxampc, go ahcad and rcrun |hc
store_schema.sql crp| |o rccrca|c cvcr,|hng. Tha| va,, |hc
rcu| o| ,our S |a|cmcn| v ma|ch mnc a ,ou progrc
|hrough |hc rc| o| |h boo|.
Summary
ln ths chupter, you huve eurned the loowng:
How to udd rows usng the INSERT stutement.
How to modly rows usng the UPDATE stutement.
How to remove rows usng the DELETE stutement.
How the dutubuse muntuns relerentu ntegrty through the enlorcement ol construnts.
How to use the DEFAULT keyword to specly deluut vuues lor coumns.
How to merge rows usng the MERGE stutement.
A dutubuse trunsucton s u group ol SQL stutements thut comprse u ogcu unt ol work.
1he Cruce dutubuse soltwure cun hunde mutpe concurrent trunsuctons.
How to use query lushbucks to vew rows us they orgnuy were belore you mude
chunges to them.
ln the next chupter, you' eurn ubout users, prveges, und roes.
This page intentionally left blank

Lsers, lrveges,
und Roes
275
276
Cruce Dutubuse llg SQL
n ths chupter, you w do the loowng:
Leurn more ubout users
See how prveges ure used to enube users to perlorm tusks n the dutubuse
Lxpore the two types ol prveges: system prveges und obect prveges
Leurn how system prveges uow you to perlorm uctons such us executng DDL
stutements
See how obect prveges uow you to perlorm uctons such us executng DML stutements
Lxpore how to group prveges together nto roes
Leurn how to uudt the executon ol SQL stutements
NOTf
You' nccd |o |,pc n |hc S |a|cmcn| hovn n |h chap|cr |
,ou van| |o |oov |hc cxampc: Thc |a|cmcn| arc no| con|ancd
n an, crp|.
Uscrs
ln ths secton, you' eurn how to creute u user, uter u user's pussword, und drop u user.
You w see the term tubespuce used n ths chupter. 1ubespuces ure used by the dutubuse
to store sepurute obects, whch cun ncude tubes, types, lL/SQL code, und so on. 1ypcuy,
reuted obects ure grouped together und stored n the sume tubespuce. lor exumpe, you mght
creute un order entry uppcuton und store u the obects lor thut uppcuton n one tubespuce,
und you mght creute u suppy chun uppcuton und store the obects lor thut uppcuton n u
dllerent tubespuce. lor more detus on tubespuces, you shoud reud the Cracc Da|abac
Conccp| munuu pubshed by Cruce Corporuton.
Crcating a Uscr
1o creute u user n the dutubuse, you use the CREATE USER stutement. 1he smpled syntux lor
the CREATE USER stutement s us loows:
CREATE USER user_name IDENTIFIED BY password
[DEFAULT TABLESPACE default_tablespace]
[TEMPORARY TABLESPACE temporary_tablespace];
where
user_name s the nume ol the dutubuse user.
password s the pussword lor the dutubuse user.
default_tablespace s the deluut tubespuce where dutubuse obects ure stored. ll
you omt u deluut tubespuce, the deluut SYSTEM tubespuce, whch uwuys exsts n u
dutubuse, s used.

Chupter 9: Lsers, lrveges, und Roes


277
temporary_tablespace s the deluut tubespuce where temporury obects ure stored.
1hese obects ncude temporury tubes thut you' eurn ubout n the next chupter. ll you
omt u temporury tubespuce, the deluut SYSTEM tubespuce s used.
1he loowng exumpe connects us system und creutes u user numed jason wth u
pussword ol price:
CONNECT system/manager
CREATE USER jason IDENTIFIED BY price;
NOTf
| ,ou van| |o |oov aong v|h |hcc cxampc ,ou' nccd |o
conncc| |o |hc da|abac a a prvcgcd ucr. ucd |hc system ucr
n |hc cxampc, vhch ha a pavord o| manager n m, da|abac.
1he next exumpe creutes u user numed henry und specles u deluut und temporury
tubespuce:
CREATE USER henry IDENTIFIED BY hooray
DEFAULT TABLESPACE users
TEMPORARY TABLESPACE temp;
NOTf
| ,our da|abac docn'| havc |abcpacc namcd users and temp,
,ou can |p |h cxampc. Thc henry ucr n'| ucd ccvhcrc n |h
boo|, and ncudcd |hc cxampc on, o ,ou can cc hov |o pcc|,
|abcpacc |or a ucr. You can vcv a |hc |abcpacc n a da|abac
b, conncc|ng a |hc system ucr and runnng |hc qucr, SELECT
tablespace_name FROM dba_tablespaces.
ll you wunt u user to be ube to do thngs n the dutubuse, thut user must be grunted the
necessury permssons to do those thngs. lor exumpe, to connect to the dutubuse u user must
be grunted the permsson to creute u sesson, whch s the CREATE SESSION system prvege.
lermssons ure grunted by u prveged user (system, lor exumpe) usng the GRANT stutement.
1he loowng exumpe grunts the CREATE SESSION permsson to jason:
GRANT CREATE SESSION TO jason;
1he jason user w now be ube to connect to the dutubuse.
1he loowng exumpe creutes other users thut ure used n ths chupter und grunts the CREATE
SESSION prvege to those users:
CREATE USER steve IDENTIFIED BY button;
CREATE USER gail IDENTIFIED BY seymour;
GRANT CREATE SESSION TO steve, gail;
Changing a Uscr's Passwurd
You cun chunge u user's pussword usng the ALTER USER stutement. lor exumpe, the loowng
stutement chunges the pussword lor jason to marcus:
ALTER USER jason IDENTIFIED BY marcus;
278
Cruce Dutubuse llg SQL
You cun uso chunge the pussword lor the user you're currenty ogged n us usng the
PASSWORD commund. Alter you enter PASSWORD, SQL*lus prompts you to enter the od
pussword und the new pussword twce lor conlrmuton. 1he loowng exumpe connects
us jason und executes PASSWORD, notce the pussword tsel s musked usng ustersks:
CONNECT jason/marcus
PASSWORD
Changing password for JASON
Old password: ******
New password: ******
Retype new password: ******
Password changed
DcIcting a Uscr
You deete u user usng the DROP USER stutement. 1he loowng exumpe connects us system
und uses DROP USER to deete jason:
CONNECT system/manager
DROP USER jason;
NOTf
You mu| add |hc |c,vord CASCADE a||cr |hc ucr' namc n |hc DROP
USER |a|cmcn| | |ha| ucr' chcma con|an ob]cc| uch
a |abc. Hovcvcr, ,ou houd cnurc no o|hcr ucr nccd accc
|o |hoc ob]cc| bc|orc dong |h.
Systcm PriviIcgcs
A ,|cm prvcgc uows u user to perlorm certun uctons wthn the dutubuse, such us executng
DDL stutements. lor exumpe, CREATE TABLE uows u user to creute u tube n ther schemu.
Some ol the commony used system prveges ure shown n 1ube 9-l.
NOTf
You can gc| |hc |u | o| ,|cm prvcgc n |hc Cruce Dutubuse
SQL Relerence manua pubhcd b, Cracc Corpora|on.
As you' see uter, prveges cun be grouped together nto roc. 1wo uselu roes to grunt to u
user ure CONNECT und RESOURCE, CONNECT uows u user to connect to the dutubuse, RESOURCE
uows u user to creute vurous dutubuse obects ke tubes, sequences, lL/SQL code, und so on.
Granting Systcm PriviIcgcs tu a Uscr
You use GRANT to grunt u system prvege to u user. 1he loowng exumpe grunts some system
prveges to steve (ussumng you're st connected to the dutubuse us system):
GRANT CREATE SESSION, CREATE USER, CREATE TABLE TO steve;
Chupter 9: Lsers, lrveges, und Roes
279
You cun uso use WITH ADMIN OPTION to uow u user to grunt u prvege to unother user.
1he loowng exumpe grunts the EXECUTE ANY PROCEDURE prvege wth the ADMIN opton
to steve:
GRANT EXECUTE ANY PROCEDURE TO steve WITH ADMIN OPTION;
EXECUTE ANY PROCEDURE cun then be grunted to unother user by steve. 1he loowng
exumpe connects us steve und grunts EXECUTE ANY PROCEDURE to gail:
CONNECT steve/button
GRANT EXECUTE ANY PROCEDURE TO gail;
You cun grunt u prvege to u users by gruntng to PUBLIC. 1he loowng exumpe connects
us system und grunts EXECUTE ANY PROCEDURE to PUBLIC:
CONNECT system/manager
GRANT EXECUTE ANY PROCEDURE TO PUBLIC;
Lvery user n the dutubuse now hus the EXECUTE ANY PROCEDURE prvege.
Systcm PriviIcgc AIIuws Yuu tu.
CREATE SESSION
Connect to u dutubuse.
CREATE SEQUENCE
Creute u sequence, whch s u seres ol numbers thut ure
typcuy used to uutomutcuy popuute u prmury key
coumn. You' eurn ubout sequences n the next chupter.
CREATE SYNONYM
Creute u synonym. A synonym uows you to relerence u
tube n unother schemu. You' eurn ubout synonyms uter
n ths chupter.
CREATE TABLE
Creute u tube n the user's schemu.
CREATE ANY TABLE
Creute u tube n uny schemu.
DROP TABLE
Drop u tube lrom the user's schemu.
DROP ANY TABLE
Drop u tube lrom uny schemu.
CREATE PROCEDURE
Creute u stored procedure.
EXECUTE ANY PROCEDURE
Lxecute u procedure n uny schemu.
CREATE USER
Creute u user.
DROP USER
Drop u user.
CREATE VIEW
Creute u vew. A vew s u stored query thut uows you to
uccess mutpe tubes und coumns. You muy then query
the vew us you woud u tube. You' eurn ubout vews n
the next chupter.
TABlf 9-1 Common, Lcd S,|cm rvcgc
280
Cruce Dutubuse llg SQL
Chccking Systcm PriviIcgcs Grantcd tu a Uscr
You cun check whch system prveges u user hus by queryng user_sys_privs. 1ube 9-2
descrbes some ol the coumns n user_sys_privs.
NOTf
user_sys_privs |orm par| o| |hc Cracc da|abac' da|a
dc|onar,. Thc da|a dc|onar, |orc n|orma|on abou| |hc
da|abac |c|.
1he loowng exumpe connects us steve und queres user_sys_privs:
CONNECT steve/button
SELECT *
FROM user_sys_privs
ORDER BY privilege;
USERNAME PRIVILEGE ADM
------------------------------ ---------------------------------------- ---
STEVE CREATE SESSION NO
STEVE CREATE TABLE NO
STEVE CREATE USER NO
PUBLIC EXECUTE ANY PROCEDURE NO
STEVE EXECUTE ANY PROCEDURE YES
1he next exumpe connects us gail und queres user_sys_privs:
CONNECT gail/seymour
SELECT *
FROM user_sys_privs
ORDER BY privilege;
USERNAME PRIVILEGE ADM
-------------------- ---------------------------------- ---
GAIL CREATE SESSION NO
GAIL EXECUTE ANY PROCEDURE NO
PUBLIC EXECUTE ANY PROCEDURE NO
Notce gail hus the EXECUTE ANY PROCEDURE prvege thut wus grunted eurer by steve.
CuIumn Typc Dcscriptiun
username VARCHAR2(30)
Nume ol the current user
privilege VARCHAR2(40)
1he system prvege the user hus
admin_option VARCHAR2(3)
\hether the user s ube to grunt the prvege to
unother user
TABlf 9-2 Somc Coumn n user_sys_privs
Chupter 9: Lsers, lrveges, und Roes
281
Making Usc uf Systcm PriviIcgcs
Cnce u user hus been grunted u system prvege, they cun use t to perlorm the specled tusk. lor
exumpe, steve hus the CREATE USER prvege, so he s ube to creute u user:
CONNECT steve/button
CREATE USER roy IDENTIFIED BY williams;
ll steve were to uttempt to use u system prvege he doesn't huve, the dutubuse w return
the error ORA-01031: insufficient privileges. lor exumpe, steve doesn't huve the
DROP USER prvege, und n the loowng exumpe steve uttempts to drop roy und lus:
SQL> DROP USER roy;
DROP USER roy
*
ERROR at line 1:
ORA-01031: insufficient privileges
Rcvuking Systcm PriviIcgcs frum a Uscr
You revoke system prveges lrom u user usng REVOKE. 1he loowng exumpe connects us system
und revokes the CREATE TABLE prvege lrom steve:
CONNECT system/manager
REVOKE CREATE TABLE FROM steve;
1he next exumpe revokes EXECUTE ANY PROCEDURE lrom steve:
REVOKE EXECUTE ANY PROCEDURE FROM steve;
\hen you revoke EXECUTE ANY PROCEDURE lrom stevewho hus ureudy pussed on ths
prvege to gailthen gail st keeps the prvege:
CONNECT gail/seymour
SELECT *
FROM user_sys_privs
ORDER BY privilege;
USERNAME PRIVILEGE ADM
------------------- ------------------------------ ---
GAIL CREATE SESSION NO
GAIL EXECUTE ANY PROCEDURE NO
PUBLIC EXECUTE ANY PROCEDURE NO
Objcct PriviIcgcs
An ob]cc| prvcgc uows u user to perlorm certun uctons on dutubuse obects, such us
executng DML stutements on tubes. lor exumpe, INSERT ON store.products uows u
user to nsert rows nto the products tube ol the store schemu. Some ol the commony used
obect prveges ure shown n 1ube 9-3.
282
Cruce Dutubuse llg SQL
NOTf
You can gc| |hc |u | o| ,|cm prvcgc n |hc Cruce Dutubuse
SQL Relerence manua pubhcd b, Cracc Corpora|on.
Granting Objcct PriviIcgcs tu a Uscr
You use GRANT to grunt un obect prvege to u user. 1he loowng exumpe connects us store
und grunts the SELECT, INSERT, und UPDATE obect prveges on the products tube to
steve uong wth the SELECT prvege on the employees tube:
CONNECT store/store_password
GRANT SELECT, INSERT, UPDATE ON store.products TO steve;
GRANT SELECT ON store.employees TO steve;
1he next exumpe grunts the UPDATE prvege on the last_name und salary coumns
to steve:
GRANT UPDATE (last_name, salary) ON store.employees TO steve;
You cun uso use the GRANT opton to enube u user to grunt u prvege to unother user. 1he
loowng exumpe grunts the SELECT prvege on the customers tube wth the GRANT opton
to steve:
GRANT SELECT ON store.customers TO steve WITH GRANT OPTION;
NOTf
You uc |hc GRANT op|on |o aov a ucr |o gran| an obect prvege
|o ano|hcr ucr, and ,ou uc |hc ADMIN op|on |o aov a ucr |o gran|
a system prvege |o ano|hcr ucr.
1he SELECT ON store.customers prvege cun then be grunted to unother user by steve.
1he loowng exumpe connects us steve und grunts ths prvege to gail:
CONNECT steve/button
GRANT SELECT ON store.customers TO gail;
Objcct PriviIcgc AIIuws a Uscr tu.
SELECT
lerlorm u seect.
INSERT
lerlorm un nsert.
UPDATE
lerlorm un updute.
DELETE
lerlorm u deete.
EXECUTE
Lxecute u stored procedure.
TABlf 9-3 Common, Lcd Cb]cc| rvcgc
Chupter 9: Lsers, lrveges, und Roes
283
Chccking Objcct PriviIcgcs Madc
You cun check whch tube obect prveges u user hus mude to other users by queryng user_
tab_privs_made. 1ube 9-4 documents the coumns n user_tab_privs_made.
1he loowng exumpe connects us store und queres user_tab_privs_made. ecuuse
there ure so muny rows, l' mt the retreved rows to those where table_name s PRODUCTS:
CONNECT store/store_password
SELECT *
FROM user_tab_privs_made
WHERE table_name = 'PRODUCTS';
GRANTEE TABLE_NAME
---------------------- ------------------------------
GRANTOR PRIVILEGE GRA HIE
---------------------- ---------------------------- --- ---
STEVE PRODUCTS
STORE INSERT NO NO
STEVE PRODUCTS
STORE SELECT NO NO
STEVE PRODUCTS
STORE UPDATE NO NO
You cun check whch coumn obect prveges u user hus mude by queryng user_col_
privs_made. 1ube 9-5 documents the coumns n user_col_privs_made.
CuIumn Typc Dcscriptiun
grantee VARCHAR2(30)
Lser to whom the prvege wus grunted
table_name VARCHAR2(30)
Nume ol the obect (such us u tube) on
whch the prvege wus grunted
grantor VARCHAR2(30)
Lser who grunted the prvege
privilege VARCHAR2(40)
lrvege on the obect
grantable VARCHAR2(3)
\hether the gruntee cun grunt the prvege
to unother (YES or NO)
hierarchy VARCHAR2(3)
\hether the prvege lorms purt ol u
herurchy (YES or NO)
TABlf 9-4 Somc Coumn n user_tab_privs_made
284
Cruce Dutubuse llg SQL
1he loowng exumpe queres user_col_privs_made:
SELECT *
FROM user_col_privs_made;
GRANTEE TABLE_NAME
------------------------------ -------------
COLUMN_NAME GRANTOR
------------------------------ -------------
PRIVILEGE GRA
---------------------------------------- ---
STEVE EMPLOYEES
LAST_NAME STORE
UPDATE NO
STEVE EMPLOYEES
SALARY STORE
UPDATE NO
Chccking Objcct PriviIcgcs Rcccivcd
You cun check whch obect prveges on u tube u user hus receved by queryng the
user_tab_privs_recd tube. 1ube 9-6 documents the coumns n user_tab_
privs_recd.
1he next exumpe connects us steve und queres user_tab_privs_recd:
CuIumn Typc Dcscriptiun
grantee VARCHAR2(30)
Lser to whom the prvege wus grunted
table_name VARCHAR2(30)
Nume ol the obect on whch the prvege wus grunted
column_name VARCHAR2(30)
Nume ol the obect on whch the prvege wus grunted
grantor VARCHAR2(30)
Lser who grunted the prvege
privilege VARCHAR2(40)
lrvege on the obect
grantable VARCHAR2(3)
\hether the gruntee cun grunt the prvege to
unother (YES or NO)
TABlf 9-S Somc Coumn n user_col_privs_made
Chupter 9: Lsers, lrveges, und Roes
28S
CONNECT steve/button
SELECT *
FROM user_tab_privs_recd
ORDER BY privilege;
OWNER TABLE_NAME
------------------------------ ------------------------------
GRANTOR PRIVILEGE GRA HIE
------------------------------ ---------------------------------------- --- ---
STORE PRODUCTS
STORE INSERT NO NO
STORE CUSTOMERS
STORE SELECT YES NO
STORE EMPLOYEES
STORE SELECT NO NO
STORE PRODUCTS
STORE SELECT NO NO
STORE PRODUCTS
STORE UPDATE NO NO
You cun check whch coumn obect prveges u user hus receved by queryng user_col_
privs_recd. 1ube 9-7 documents the coumns n user_col_privs_recd.
CuIumn Typc Dcscriptiun
owner VARCHAR2(30)
Lser who owns the obect
table_name VARCHAR2(30)
Nume ol the obect on whch the prvege
wus grunted
grantor VARCHAR2(30)
Lser who grunted the prvege
privilege VARCHAR2(40)
lrvege on the obect
grantable VARCHAR2(3)
\hether the gruntee cun grunt the prvege
to unother (YES or NO)
hierarchy VARCHAR2(3)
\hether the prvege lorms purt ol u
herurchy (YES or NO)
TABlf 9-6 Somc Coumn n ucr_|ab_prv_rccd
286
Cruce Dutubuse llg SQL
1he loowng exumpe queres user_col_privs_recd:
SELECT *
FROM user_col_privs_recd;
OWNER TABLE_NAME
------------------------------ -------------
COLUMN_NAME GRANTOR
------------------------------ -------------
PRIVILEGE GRA
---------------------------------------- ---
STORE EMPLOYEES
LAST_NAME STORE
UPDATE NO
STORE EMPLOYEES
SALARY STORE
UPDATE NO
Making Usc uf Objcct PriviIcgcs
Cnce u user hus been grunted un obect prvege, they cun use t to perlorm the specled tusk.
lor exumpe, steve hus the SELECT prvege on store.customers:
CONNECT steve/button
SELECT *
FROM store.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
CuIumn Typc Dcscriptiun
owner VARCHAR2(30)
Lser who owns the obect
table_name VARCHAR2(30)
Nume ol the tube on whch the prvege
wus grunted
column_name VARCHAR2(30)
Nume ol the coumn on whch the prvege
wus grunted
grantor VARCHAR2(30)
Lser who grunted the prvege
privilege VARCHAR2(40)
lrvege on the obect
grantable VARCHAR2(3)
\hether the gruntee cun grunt the prvege
to unother (YES or NO)
TABlf 9-7 Somc Coumn n user_col_privs_recd
Chupter 9: Lsers, lrveges, und Roes
287
ll steve were to uttempt to retreve lrom the purchases tubelor whch he doesn't huve
uny permssonsthe dutubuse w return the error ORA-00942: table or view does
not exist:
SQL> SELECT *
2 FROM store.purchases;
FROM store.purchases
*
ERROR at line 2:
ORA-00942: table or view does not exist
Synunyms
ln the exumpes n the prevous secton, you suw thut you cun uccess tubes n unother schemu
by speclyng the schemu nume loowed by the tube. lor exumpe, when steve retreved rows
lrom the customers tube n the store schemu, he perlormed u query on store.customers.
You cun uvod huvng to enter the schemu nume by creutng u ,non,m lor u tube, whch you do
by usng the CREATE SYNONYM stutement.
Let's tuke u ook ut un exumpe. lrst, connect us system und grunt the CREATE SYNONYM
system prvege to steve:
CONNECT system/manager
GRANT CREATE SYNONYM TO steve;
Next, connect us steve und perlorm u CREATE SYNONYM stutement to creute u synonym lor
the store.customers tube:
CONNECT steve/button
CREATE SYNONYM customers FOR store.customers;
1o retreve rows lrom store.customers, u steve hus to do s to relerence the
customers synonym n the FROM cuuse ol u SELECT stutement. lor exumpe:
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
PubIic Synunyms
You cun uso creute u pubc synonym lor u tube. \hen you do ths, u users see the synonym.
1he loowng tusks
Connect us system
Crunt the CREATE PUBLIC SYNONYM system prvege to store
288
Cruce Dutubuse ll SQL
Connect us store
Creute u pubc synonym numed products lor store.products
ure perlormed by the loowng stutements:
CONNECT system/manager
GRANT CREATE PUBLIC SYNONYM TO store;
CONNECT store/store_password
CREATE PUBLIC SYNONYM products FOR store.products;
ll you connect us steve, who hus the SELECT prvege on store.products, you cun
now retreve rows lrom store.products through the products pubc synonym:
CONNECT steve/button
SELECT *
FROM products;
Lven though u pubc synonym hus been creuted lor store.products, u user st needs
obect prveges on thut tube to uctuuy uccess the tube. lor exumpe, gail cun see the products
pubc synonym, but gail doesn't huve uny obect prveges on store.products. 1herelore,
l gail uttempts to retreve rows lrom products, the dutubuse returns the error ORA-00942:
table or view does not exist:
SQL> CONNECT gail/seymour
Connected.
SQL> SELECT * FROM products;
SELECT * FROM products
*
ERROR at line 1:
ORA-00942: table or view does not exist
ll gail hud the SELECT obect prvege on the store.products tube, the prevous
SELECT woud succeed.
ll u user hus other obect prveges, thut user cun exercse those obect prveges through
u synonym. lor exumpe, l gail hud the INSERT obect prvege on the store.products
tube, gail woud be ube to udd u row to store.products through the products synonym.
Rcvuking Objcct PriviIcgcs
You revoke obect prveges usng REVOKE. 1he loowng exumpe connects us store und
revokes the INSERT prvege on the products tube lrom steve:
CONNECT store/store_password
REVOKE INSERT ON products FROM steve;
1he next exumpe revokes the SELECT prvege on the customers tube lrom steve:
REVOKE SELECT ON store.customers FROM steve;
\hen you revoke SELECT ON store.customers lrom stevewho hus ureudy pussed
on ths prvege to gailgail uso oses the prvege.
Chupter 9: Lsers, lrveges, und Roes
289
RuIcs
A roc s u group ol prveges thut you cun ussgn to u user or to unother roe. 1he loowng ponts
summurze the benelts und leutures ol roes:
Ruther thun ussgnng prveges one ut u tme drecty to u user, you cun creute u roe,
ussgn prveges to thut roe, und then grunt thut roe to mutpe users und roes.
\hen you udd or deete u prvege lrom u roe, u users und roes ussgned thut roe
uutomutcuy receve or ose thut prvege.
You cun ussgn mutpe roes to u user or roe.
You cun ussgn u pussword to u roe.
As you cun see lrom these ponts, roes cun hep you munuge mutpe prveges ussgned to
mutpe users.
Crcating RuIcs
1o creute u roe, you must huve the CREATE ROLE system prvege. As you' see n u uter
exumpe, the store user uso needs the ubty to grunt the CREATE USER system prvege
wth the ADMIN opton. 1he loowng exumpe connects us system und grunts the requred
prveges to store:
CONNECT system/manager
GRANT CREATE ROLE TO store;
GRANT CREATE USER TO store WITH ADMIN OPTION;
1ube 9-8 shows the roes you' creute shorty.
You creute u roe usng the CREATE ROLE stutement. 1he loowng stutements connect us
store und creute the three roes shown n 1ube 9-8:
CONNECT store/store_password
CREATE ROLE product_manager;
CREATE ROLE hr_manager;
CREATE ROLE overall_manager IDENTIFIED by manager_password;
Notce overall_manager hus u pussword ol manager_password.
RuIc Namc Has Pcrmissiuns tu.
product_manager
lerlorm SELECT, INSERT, UPDATE, und DELETE operutons
on the product_types und products tubes.
hr_manager
lerlorm SELECT, INSERT, UPDATE, und DELETE operutons
on the salary_grades und employees tubes. Aso, hr_
manager s ube to creute users.
overall_manager
lerlorm SELECT, INSERT, UPDATE, und DELETE operutons
on u the tubes shown n the prevous roes, overall_
manager w be grunted the prevous roes.
TABlf 9-8 Roc |o c Crca|cd
290
Cruce Dutubuse llg SQL
Granting PriviIcgcs tu RuIcs
You grunt prveges to u roe usng the GRANT stutement. You cun grunt both system und obect
prveges to u roe us we us grunt unother roe to u roe. 1he loowng exumpe grunts the requred
prveges to the product_manager und hr_manager roes und grunts these two roes to
overall_manager:
GRANT SELECT, INSERT, UPDATE, DELETE ON product_types TO product_manager;
GRANT SELECT, INSERT, UPDATE, DELETE ON products TO product_manager;
GRANT SELECT, INSERT, UPDATE, DELETE ON salary_grades TO hr_manager;
GRANT SELECT, INSERT, UPDATE, DELETE ON employees TO hr_manager;
GRANT CREATE USER TO hr_manager;
GRANT product_manager, hr_manager TO overall_manager;
Granting RuIcs tu a Uscr
You grunt u roe to u user usng GRANT. 1he loowng exumpe grunts the overall_manager
roe to steve:
GRANT overall_manager TO steve;
Chccking RuIcs Grantcd tu a Uscr
You cun check whch roes huve been grunted to u user by queryng user_role_privs. 1ube
9-9 delnes the coumns n user_role_privs.
1he loowng exumpe connects us steve und queres user_role_privs:
CONNECT steve/button
SELECT *
FROM user_role_privs;
USERNAME GRANTED_ROLE ADM DEF OS_
------------------ -------------------------- --- --- ---
STEVE OVERALL_MANAGER NO YES NO
CuIumn Typc Dcscriptiun
username VARCHAR2(30)
Nume ol the user to whom the roe hus
been grunted
granted_role VARCHAR2(30)
Nume ol the roe grunted to the user
admin_option VARCHAR2(3)
\hether the user s ube to grunt the roe
to unother user or roe (YES or NO)
default_role VARCHAR2(3)
\hether the roe s enubed by deluut
when the user connects to the dutubuse
(YES or NO)
os_granted VARCHAR2(3)
\hether the roe wus grunted by the
operutng system (YES or NO)
TABlf 9-9 Somc Coumn n user_role_privs
Chupter 9: Lsers, lrveges, und Roes
291
A user who creutes u roe s uso grunted thut roe by deluut. 1he loowng exumpe connects
us store und queres user_role_privs:
CONNECT store/store_password
SELECT *
FROM user_role_privs;
USERNAME GRANTED_ROLE ADM DEF OS_
------------------ -------------------------- --- --- ---
STORE CONNECT NO YES NO
STORE HR_MANAGER YES YES NO
STORE OVERALL_MANAGER YES YES NO
STORE PRODUCT_MANAGER YES YES NO
STORE RESOURCE NO YES NO
Notce store hus the roes CONNECT und RESOURCE n uddton to the roes store creuted
eurer.
NOTf
CONNECT and RESOURCE arc bu|-n roc |ha| vcrc gran|cd |o
store vhcn ,ou ran |hc store_schema.sql crp|. A ,ou' cc n
|hc ncx| cc|on, |hc CONNECT and RESOURCE roc con|an mu|pc
prvcgc.
Chccking Systcm PriviIcgcs Grantcd tu a RuIc
You cun check whch system prveges huve been grunted to u roe by queryng role_sys_
privs. 1ube 9-l0 delnes the coumns n role_sys_privs.
1he loowng exumpe retreves the rows lrom role_sys_privs (ussumng you're st
connected us store):
SELECT *
FROM role_sys_privs
ORDER BY privilege;
ROLE PRIVILEGE ADM
------------------------------ ---------------------------------------- ---
RESOURCE CREATE CLUSTER NO
RESOURCE CREATE INDEXTYPE NO
RESOURCE CREATE OPERATOR NO
RESOURCE CREATE PROCEDURE NO
RESOURCE CREATE SEQUENCE NO
CONNECT CREATE SESSION NO
RESOURCE CREATE TABLE NO
RESOURCE CREATE TRIGGER NO
RESOURCE CREATE TYPE NO
HR_MANAGER CREATE USER NO
Notce thut the RESOURCE roe hus muny prveges ussgned to t.
NOTf
Thc prcvou qucr, va run ung Cracc Da|abac 11g. | ,ou arc
ung a d||crcn| vcron o| |hc da|abac o||varc, ,ou ma, gc| gh|,
d||crcn| rcu|.
292
Cruce Dutubuse llg SQL
Chccking Objcct PriviIcgcs Grantcd tu a RuIc
You cun check whch obect prveges huve been grunted to u roe by queryng role_tab_
privs. 1ube 9-ll delnes the coumns n role_tab_privs.
1he loowng exumpe queres role_tab_privs where role equus HR_MANAGER:
SELECT *
FROM role_tab_privs
WHERE role='HR_MANAGER'
ORDER BY table_name;
ROLE OWNER
------------------------------ ------------------------------
TABLE_NAME COLUMN_NAME
------------------------------ ------------------------------
PRIVILEGE GRA
---------------------------------------- ---
HR_MANAGER STORE
EMPLOYEES
DELETE NO
HR_MANAGER STORE
EMPLOYEES
INSERT NO
HR_MANAGER STORE
EMPLOYEES
SELECT NO
HR_MANAGER STORE
EMPLOYEES
UPDATE NO
HR_MANAGER STORE
SALARY_GRADES
DELETE NO
HR_MANAGER STORE
SALARY_GRADES
INSERT NO
CuIumn Typc Dcscriptiun
role VARCHAR2(30)
Nume ol the roe
privilege VARCHAR2(40)
System prvege grunted to the roe
admin_option VARCHAR2(3)
\hether the prvege wus grunted wth the
ADMIN opton (YES or NO)
TABlf 9-10 Somc Coumn n role_sys_privs
Chupter 9: Lsers, lrveges, und Roes
293
HR_MANAGER STORE
SALARY_GRADES
SELECT NO
HR_MANAGER STORE
SALARY_GRADES
UPDATE NO
Making Usc uf PriviIcgcs Grantcd tu a RuIc
Cnce u user hus been grunted u prvege vu u roe, they cun use thut prvege to perlorm
the uuthorzed tusks. lor exumpe, steve hus the overall_manager roe. 1he overall_
manager wus grunted the product_manager und hr_manager roes. 1he product_manager
wus grunted the SELECT obect prvege on the products und product_types tubes.
1herelore, steve s ube to retreve rows lrom these tubes, us shown n the loowng exumpe:
CONNECT steve/button
SELECT p.name, pt.name
FROM store.products p, store.product_types pt
WHERE p.product_type_id = pt.product_type_id;
NAME NAME
------------------------------ ----------
Modern Science Book
Chemistry Book
Supernova Video
Tank War Video
Z Files Video
2412: The Return Video
Space Force 9 DVD
From Another Planet DVD
Classical Music CD
Pop 3 CD
Creative Yell CD
CuIumn Typc Dcscriptiun
role VARCHAR2(30)
Lser to whom the prvege wus grunted
owner VARCHAR2(30)
Lser who owns the obect
table_name VARCHAR2(30)
Nume ol the obect on whch the prvege wus grunted
column_name VARCHAR2(30)
Nume ol the coumn (l uppcube)
privilege VARCHAR2(40)
lrvege on the obect
grantable VARCHAR2(3)
\hether the prvege wus grunted wth the GRANT
opton (YES or NO)
TABlf 9-11 Somc Coumn n role_tab_privs
294
Cruce Dutubuse ll SQL
DcfauIt RuIcs
y deluut, when u roe s grunted to u user, thut roe s enubed lor thut user. 1hs meuns thut
when the user connects to the dutubuse, the roe s uutomutcuy uvuube to them. 1o enhunce
securty, you cun dsube u roe by deluut, when the user connects, they w huve to enube
the roe themseves belore they cun use t. ll the roe hus u pussword, the user must enter thut
pussword belore the roe s enubed. lor exumpe, the overall_manager roe hus u pussword
ol manager_passsword, und overall_manager s grunted to steve. ln the exumpe you'
see next, you' dsube overall_manager so thut steve hus to enube ths roe und enter the
pussword belore he cun use t. You do ths by uterng u roe so thut t s no onger u deluut roe
usng the ALTER ROLE stutement. 1he loowng exumpe connects us system und uters steve
so thut overall_manager s no onger u deluut roe:
CONNECT system/manager
ALTER USER steve DEFAULT ROLE ALL EXCEPT overall_manager;
\hen you connect us steve, you need to enube overall_manager usng SET ROLE:
CONNECT steve/button
SET ROLE overall_manager IDENTIFIED BY manager_password;
Cnce you've set the roe, you cun use the prveges grunted to thut roe. You cun set your roe
to none (.e. no roe) usng the loowng stutement:
SET ROLE NONE;
You cun uso set your roe to u roes except overall_manager usng the loowng
stutement:
SET ROLE ALL EXCEPT overall_manager;
y ussgnng pusswords to roes und settng roes to not be enubed by deluut lor u user, you
ntroduce un uddtonu eve ol securty.
Rcvuking a RuIc
You revoke u roe usng REVOKE. 1he loowng exumpe connects us store und revokes the
overall_manager roe lrom steve:
CONNECT store/store_password
REVOKE overall_manager FROM steve;
Rcvuking PriviIcgcs frum a RuIc
You revoke u prvege lrom u roe usng REVOKE. 1he loowng exumpe connects us store und
revokes u prveges on the products und product_types tubes lrom product_manager
(ussumng you're st connected us store):
REVOKE ALL ON products FROM product_manager;
REVOKE ALL ON product_types FROM product_manager;
Chupter 9: Lsers, lrveges, und Roes
29S
Drupping a RuIc
You drop u roe usng DROP ROLE. 1he loowng exumpe drops the overall_manager,
product_manager, und hr_manager roes (ussumng you're st connected us store):
DROP ROLE overall_manager;
DROP ROLE product_manager;
DROP ROLE hr_manager;
Auditing
1he Cruce dutubuse soltwure contuns uudtng cupubtes thut enube you to keep truck ol
dutubuse operutons. Some operutons muy be uudted ut u hgh eve, such us lued uttempts to
og nto the dutubuse, whe others muy be uudted ut u detued eve, such us when u user retreved
rows lrom u speclc tube. 1ypcuy, your dutubuse udmnstrutor w be responsbe lor enubng
uudtng und montorng the output lor securty voutons. ln ths secton, you w see some smpe
exumpes ol uudtng, whch s perlormed usng the AUDIT stutement.
PriviIcgcs Rcquircd tu Pcrfurm Auditing
elore u user cun ssue AUDIT stutements, thut user must huve been grunted certun prveges:
lor uudtng hgh-eve operutons, the user must huve the AUDIT SYSTEM prvege. An
exumpe ol u hgh-eve operuton s the ssuunce ol SELECT stutement, regurdess ol
the tube nvoved.
lor truckng operutons on speclc dutubuse obects, the user must ether huve the AUDIT
ANY prvege or the dutubuse obect must be n ther schemu. An exumpe ol speclc
dutubuse obect operuton s the ssuunce ol u SELECT stutement lor u purtcuur tube.
1he loowng exumpe connects to the dutubuse us the system user und grunts the AUDIT
SYSTEM und AUDIT ANY prveges to the store user:
CONNECT system/manager
GRANT AUDIT SYSTEM TO store;
GRANT AUDIT ANY TO store;
Auditing fxampIcs
1he loowng exumpe connects to the dutubuse us the store user und uudts the ssuunce ol
CREATE TABLE stutements:
CONNECT store/store_password
AUDIT CREATE TABLE;
As u resut ol ths AUDIT stutement, uny CREATE TABLE stutements ssued w be uudted,
lor exumpe, the loowng stutement creutes u smpe test tube:
CREATE TABLE test (
id INTEGER
);

Cruce Dutubuse ll SQL
You cun vew the uudt tru ol nlormuton lor the user you ure currenty ogged n us through
the USER_AUDIT_TRAIL vew. 1he loowng exumpe shows the uudt record generuted by the
prevous CREATE TABLE stutement:
SELECT username, extended_timestamp, audit_option
FROM user_audit_trail
WHERE audit_option='CREATE TABLE';
USERNAME
------------------------------
EXTENDED_TIMESTAMP
-----------------------------------
AUDIT_OPTION
-----------------------------------
STORE
20-MAY-07 04.13.43.453000 PM -07:00
CREATE TABLE
You muy uso uudt the ssuunce ol stutements by u purtcuur user. 1he loowng exumpe
uudts u SELECT stutements ssued by the store user:
AUDIT SELECT TABLE BY store;
1he next exumpe uudts u INSERT, UPDATE, und DELETE stutements mude by the store
und steve users:
AUDIT INSERT TABLE, UPDATE TABLE, DELETE TABLE BY store, steve;
You muy uso uudt the ssuunce ol stutements mude lor u purtcuur dutubuse obect. 1he
loowng exumpe uudts u SELECT stutements ssued lor the products tube:
AUDIT SELECT ON store.products;
1he next exumpe uudts u stutements ssued lor the employees tube:
AUDIT ALL ON store.employees;
You muy uso use the WHENEVER SUCCESSFUL und WHENEVER NOT SUCCESSFUL optons
to ndcute when uudtng shoud be perlormed. WHENEVER SUCCESSFUL ndcutes uudtng w
be perlormed when the stutement executed successluy. WHENEVER NOT SUCCESSFUL ndcutes
uudtng w be perlormed when the stutement dd not execute successluy. 1he deluut s to
do both, thut s, uudt regurdess ol success. 1he loowng exumpes use the WHENEVER NOT
SUCCESSFUL opton:
AUDIT UPDATE TABLE BY steve WHENEVER NOT SUCCESSFUL;
AUDIT INSERT TABLE WHENEVER NOT SUCCESSFUL;
1he next exumpe uses the WHENEVER SUCCESSFUL opton to uudt the creuton und
deeton ol u user:
Chupter 9: Lsers, lrveges, und Roes
297
AUDIT CREATE USER, DROP USER WHENEVER SUCCESSFUL;
1he next exumpe uses the WHENEVER SUCCESSFUL opton to uudt the creuton und
deeton ol u user by the store user:
AUDIT CREATE USER, DROP USER BY store WHENEVER SUCCESSFUL;
You muy uso use the BY SESSION und BY ACCESS optons. 1he BY SESSION opton
cuuses ony one uudt record to be ogged when the sume type ol stutement s ssued durng the
sume user dutubuse sesson, u dutubuse sesson sturts when the user ogs nto the dutubuse und
ends when the user ogs out. 1he BY ACCESS opton cuuses one uudt record to be ogged every
tme the sume type ol stutement s ssued, regurdess ol the user sesson. 1he loowng exumpes
show the use ol the BY SESSION und BY ACCESS optons:
AUDIT SELECT ON store.products BY SESSION;
AUDIT DELETE ON store.employees BY ACCESS;
AUDIT INSERT, UPDATE ON store.employees BY ACCESS;
Audit TraiI Vicws
Lurer, you suw the use ol the USER_AUDIT_TRAIL vew. 1hs und the other uudt tru vews ure
outned n the loowng st:
USER_AUDIT_OBJECT dspuys the uudt records lor u obects uccessbe to the
current user.
USER_AUDIT_SESSION dspuys the uudt records lor connectons und dsconnectons
ol the current user.
USER_AUDIT_STATEMENT dspuys the uudt records lor GRANT, REVOKE, AUDIT,
NOAUDIT, und ALTER SYSTEM stutements ssued by the current user.
USER_AUDIT_TRAIL dspuys u uudt tru entres reuted to the current user.
You muy use these vews to exumne the contents ol the uudt tru. 1here ure u number ol
smury numed vews thut the dutubuse udmnstrutor muy use to exumne the uudt tru, these
vews ure numed DBA_AUDIT_OBJECT, DBA_AUDIT_SESSION, DBA_AUDIT_STATEMENT,
DBA_AUDIT_TRAIL, pus others. 1hese vews uow the DA to vew uudt records ucross u
users. lor more detus on these vews, you shoud consut the Cracc Da|abac Rc|crcncc munuu
pubshed by Cruce Corporuton.
Summary
ln ths chupter, you've eurned the loowng:
A user s creuted usng the CREATE USER stutement.
System prveges uow you to perlorm certun uctons wthn the dutubuse, such us
executng DDL stutements.

Cruce Dutubuse ll SQL
Cbect prveges uow you to perlorm certun uctons on dutubuse obects, such us
executng DML stutements on tubes.
You cun uvod huvng to enter the schemu nume by creutng u synonym lor u tube.
A roe s u group ol prveges thut you cun ussgn to u user or unother roe.
Audtng the executon ol SQL stutements cun be perlormed usng the AUDIT stutement.
ln the next chupter, you' eurn more ubout creutng tubes und see how to creute ndexes,
sequences, und vews.
\IAI1II
10
Creutng 1ubes,
Sequences, lndexes,
und Vews
299
300
Cruce Dutubuse ll SQL
n ths chupter, you w do the loowng:
Leurn more ubout tubes
See how to creute und use sequences, whch generute u seres ol numbers
Lxpore how to creute und use ndexes, whch cun mprove the perlormunce ol queres
Leurn how to creute und use vews, whch ure predelned queres thut uow you to hde
compexty lrom users, umong other benelts
Lxumne lushbuck dutu urchves, new lor Cruce Dutubuse ll, whch store chunges
mude to u tube over u perod ol tme
Let's punge n und exumne tubes.
TabIcs
ln ths secton, you' eurn more ubout creutng u tube. You' see how to modly und drop u tube
us we us how to retreve nlormuton ubout u tube lrom the dutu dctonury. 1he dutu dctonury
contuns nlormuton ubout u the dutubuse tems, such us tubes, sequences, ndexes, und so on.
Crcating a TabIc
You use the CREATE TABLE stutement to creute u tube. 1he smpled syntux lor the CREATE
TABLE stutement s us loows:
CREATE [GLOBAL TEMPORARY] TABLE table_name (
column_name type [CONSTRAINT constraint_def DEFAULT default_exp]
[, column_name type [CONSTRAINT constraint_def DEFAULT default_exp] ...]
)
[ON COMMIT {DELETE | PRESERVE} ROWS]
TABLESPACE tab_space;
where
GLOBAL TEMPORARY meuns the tube's rows ure temporury (these tubes ure known us
temporury tubes). 1he rows n u temporury tube ure speclc to u user sesson, und how
ong the rows persst s set n the ON COMMIT cuuse.
table_name s the nume ol the tube.
column_name s the nume ol u coumn.
type s the type ol u coumn.
constraint_def s u construnt on u coumn.
default_exp s un expresson to ussgn u deluut vuue to u coumn.

Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews

ON COMMIT contros the duruton ol the rows n u temporury tube. DELETE meuns the
rows ure deeted ut the end ol u trunsucton. PRESERVE meuns the rows ure kept unt the
end ol u user sesson, ut whch pont the rows ure deeted. ll you omt ON COMMIT lor u
temporury tube, then the deluut DELETE s used.
tab_space s the tubespuce lor the tube. ll you omt u tubespuce, then the tube s
stored n the user's deluut tubespuce.

Thc |u CREATE TABLE ,n|ax |ar rchcr |han |ha| hovn abovc. or
|u dc|a, cc |hc Cruce Dutubuse SQL Relerence boo| pubhcd
b, Cracc Corpora|on.
1he loowng exumpe connects us the store user und creutes u tube numed order_
status2:
CONNECT store/store_password
CREATE TABLE order_status2 (
id INTEGER CONSTRAINT order_status2_pk PRIMARY KEY,
status VARCHAR2(10),
last_modified DATE DEFAULT SYSDATE
);

| ,ou van| |o |oov aong v|h |hc cxampc n |h chap|cr, ,ou'


nccd |o cn|cr and run |hc S |a|cmcn| ung S*u.
1he next exumpe creutes u temporury tube numed order_status_temp whose rows w
be kept unt the end ol u user sesson (ON COMMIT PRESERVE ROWS):
CREATE GLOBAL TEMPORARY TABLE order_status_temp (
id INTEGER,
status VARCHAR2(10),
last_modified DATE DEFAULT SYSDATE
)
ON COMMIT PRESERVE ROWS;
1he next exumpe perlorms the loowng:
Adds u row to order_status_temp.
Dsconnects lrom the dutubuse to end the sesson, whch cuuses the row n order_
status_temp to be deeted.
Reconnects us store und queres order_status_temp, whch shows there ure no
rows n ths tube.
INSERT INTO order_status_temp (
id, status
) VALUES (
1, 'New'
);
302
Cruce Dutubuse llg SQL
1 row created.
DISCONNECT
CONNECT store/store_password
SELECT *
FROM order_status_temp;
no rows selected
Gctting lnfurmatiun un TabIcs
You cun get nlormuton ubout your tubes by
lerlormng u DESCRIBE commund on the tube. You've ureudy seen exumpes thut use
the DESCRIBE commund n eurer chupters.
Queryng the user_tables vew, whch lorms purt ol the dutu dctonury.
1ube l0-l descrbes some ol the coumns n the user_tables vew.
NOTf
You can rc|rcvc n|orma|on on a |hc |abc ,ou havc accc |o b,
qucr,ng |hc all_tables vcv.
1he loowng exumpe retreves some ol the coumns lrom user_tables where the
table_name s order_status2 or order_status_temp:
SELECT table_name, tablespace_name, temporary
FROM user_tables
WHERE table_name IN ('ORDER_STATUS2', 'ORDER_STATUS_TEMP');
TABLE_NAME TABLESPACE_NAME T
------------------------------ ------------------------------ -
ORDER_STATUS2 USERS N
ORDER_STATUS_TEMP Y
Notce the order_status_temp tube s temporury, us ndcuted by the Y n the ust
coumn.
CuIumn Typc Dcscriptiun
table_name VARCHAR2(30)
Nume ol the tube.
tablespace_name VARCHAR2(30)
Nume ol the tubespuce n whch the tube
s stored. A tubespuce s un ureu used by the
dutubuse to store obects such us tubes.
temporary VARCHAR2(1)
\hether the tube s temporury. 1hs s set to
Y l temporury or N l not temporury.
TABlf 10-1 Somc Coumn n |hc user_tables Vcv
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews
303
Gctting lnfurmatiun un CuIumns in TabIcs
You cun retreve nlormuton ubout the coumns n your tubes lrom the user_tab_columns
vew. 1ube l0-2 descrbes some ol the coumns n user_tab_columns.
NOTf
You can rc|rcvc n|orma|on on a |hc coumn n |abc ,ou havc
accc |o b, qucr,ng |hc all_tab_columns vcv.
1he loowng exumpe retreves some ol the coumns lrom user_tab_columns lor the
products tube:
COLUMN column_name FORMAT a15
COLUMN data_type FORMAT a10
SELECT column_name, data_type, data_length, data_precision, data_scale
FROM user_tab_columns
WHERE table_name = 'PRODUCTS';
COLUMN_NAME DATA_TYPE DATA_LENGTH DATA_PRECISION DATA_SCALE
--------------- ---------- ----------- -------------- ----------
PRODUCT_ID NUMBER 22 38 0
PRODUCT_TYPE_ID NUMBER 22 38 0
NAME VARCHAR2 30
DESCRIPTION VARCHAR2 50
PRICE NUMBER 22 5 2
AItcring a TabIc
You uter u tube usng the ALTER TABLE stutement. You cun use ALTER TABLE to perlorm tusks
such us
Addng, modlyng, or droppng u coumn
Addng or droppng u construnt
Lnubng or dsubng u construnt
ln the loowng sectons, you' eurn how to use ALTER TABLE to perlorm euch ol these tusks.
CuIumn Typc Dcscriptiun
table_name VARCHAR2(30)
Nume ol the tube
column_name VARCHAR2(30)
Nume ol the coumn
data_type VARCHAR2(106)
Dutu type ol the coumn
data_length NUMBER
Length ol the dutu
data_precision NUMBER
lrecson ol u numerc coumn l u precson
wus specled lor the coumn.
data_scale NUMBER
Scue ol u numerc coumn
TABlf 10-2 Somc Coumn n |hc user_tab_columns Vcv
304
Cruce Dutubuse ll SQL
Adding a CuIumn
1he loowng exumpe uses ALTER TABLE to udd un INTEGER coumn numed modified_by
to the order_status2 tube:
ALTER TABLE order_status2
ADD modified_by INTEGER;
1he next exumpe udds u coumn numed initially_created to order_status2:
ALTER TABLE order_status2
ADD initially_created DATE DEFAULT SYSDATE NOT NULL;
You cun verly the uddton ol the new coumn by executng u DESCRIBE commund on
order_status2:
DESCRIBE order_status2
Name Null? Type
----------------------------------------- -------- ------------
ID NOT NULL NUMBER(38)
STATUS VARCHAR2(10)
LAST_MODIFIED DATE
MODIFIED_BY NUMBER(38)
INITIALLY_CREATED NOT NULL DATE
Adding a VirtuaI CuIumn
ln Cruce Dutubuse ll, you cun udd u vrtuu coumn, whch s u coumn thut relers ony to other
coumns ureudy n the tube. lor exumpe, the loowng ALTER TABLE stutement udds u vrtuu
coumn numed average_salary to the salary_grades tube:
ALTER TABLE salary_grades
ADD (average_salary AS ((low_salary + high_salary)/2));
Notce average_salary s set to the uveruge ol the low_salary und high_salary vuues.
1he loowng DESCRIBE commund conlrms the uddton ol the average_salary coumn to
the salary_grades tube:
DESCRIBE salary_grades
Name Null? Type
----------------------------------------- -------- ----------
SALARY_GRADE_ID NOT NULL NUMBER(38)
LOW_SALARY NUMBER(6)
HIGH_SALARY NUMBER(6)
AVERAGE_SALARY NUMBER
1he loowng query retreves the rows lrom the salary_grades tube:
SELECT *
FROM salary_grades;
SALARY_GRADE_ID LOW_SALARY HIGH_SALARY AVERAGE_SALARY
--------------- ---------- ----------- --------------
1 1 250000 125000.5
2 250001 500000 375000.5
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews
30S
3 500001 750000 625000.5
4 750001 999999 875000
Mudifying a CuIumn
1he loowng st shows some ol the coumn uspects you cun modly usng ALTER TABLE:
Chunge the sze ol u coumn (l the dutu type s one whose ength muy be chunged, such
us CHAR or VARCHAR2)
Chunge the precson ol u numerc coumn
Chunge the dutu type ol u coumn
Chunge the deluut vuue ol u coumn
You' see exumpes ol how to chunge these coumn uspects n the loowng sectons.
Changing thc Sizc uf a CuIumn
1he loowng ALTER TABLE stutement ncreuses the muxmum ength ol the order_status2
.status coumn to l5 churucters:
ALTER TABLE order_status2
MODIFY status VARCHAR2(15);
CAUTlON
You can on, decreuse |hc cng|h o| a coumn | |hcrc arc no rov n
|hc |abc or a |hc rov con|an nu vauc |or |ha| coumn.
Changing thc Prccisiun uf a Numcric CuIumn
1he loowng ALTER TABLE stutement chunges the precson ol the order_status2.id
coumn to 5:
ALTER TABLE order_status2
MODIFY id NUMBER(5);
CAUTlON
You can on, decreuse |hc prccon o| a numcrc coumn | |hcrc arc
no rov n |hc |abc or |hc coumn con|an nu vauc.
Changing thc Data Typc uf a CuIumn
1he loowng ALTER TABLE stutement chunges the dutu type ol the order_status2.status
coumn to CHAR:
ALTER TABLE order_status2
MODIFY status CHAR(15);
ll the tube s empty or the coumn contuns nu vuues, you cun chunge the coumn to uny
dutu type (ncudng u dutu type thut s shorter), otherwse, you cun chunge the dutu type ol u
coumn ony to u computbe dutu type. lor exumpe, you cun chunge u VARCHAR2 to CHAR (und
vce versu) us ong us you don't muke the coumn shorter, you cunnot chunge u DATE to u NUMBER.
306
Cruce Dutubuse llg SQL
Changing thc DcfauIt VaIuc uf a CuIumn
1he loowng ALTER TABLE stutement chunges the deluut vuue lor the order_status2
.last_modified coumn to SYSDATE - 1:
ALTER TABLE order_status2
MODIFY last_modified DEFAULT SYSDATE - 1;
1he deluut vuue uppes ony to new rows udded to the tube. New rows w get ther last_
modified coumn set to the current dute mnus one duy.
Drupping a CuIumn
1he loowng ALTER TABLE stutement drops the order_status2.initially_created
coumn:
ALTER TABLE order_status2
DROP COLUMN initially_created;
Adding a Cunstraint
ln eurer chupters, you've seen exumpes ol tubes wth PRIMARY KEY, FOREIGN KEY, und NOT
NULL construnts. 1hese construnts, uong wth the other types ol construnts, ure summurzed n
1ube l0-3.
You' see how to udd some ol the construnts shown n 1ube l0-3 n the loowng sectons.
Cunstraint Cunstraint Typc Mcaning
CHECK C
1he vuue lor u coumn, or group ol coumns, must
sutsly u certun condton.
NOT NULL C
1he coumn cunnot store u nu vuue. 1hs s
uctuuy enlorced us u CHECK construnt.
PRIMARY KEY P
1he prmury key ol u tube. A prmury key s mude
up ol one or more coumns thut unquey dently
euch row n u tube.
FOREIGN KEY R
A loregn key lor u tube. A loregn key relerences
u coumn n unother tube or u coumn n the sume
tube (known us u sel-relerence).
UNIQUE U
1he coumn, or group ol coumns, cun store ony
unque vuues.
CHECK OPTION V
Chunges to the tube rows mude through u vew
must puss u check lrst. (You' eurn ubout ths
uter n the secton Vews.)
READ ONLY O
1he vew muy ony be reud lrom. (You' eurn
ubout ths uter n the secton Vews.)
TABlf 10-3 Con|ran| and Thcr \canng
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews
307
Adding a CHfCk Cunstraint
1he loowng ALTER TABLE stutement udds u CHECK construnt to the order_status2 tube:
ALTER TABLE order_status2
ADD CONSTRAINT order_status2_status_ck
CHECK (status IN ('PLACED', 'PENDING', 'SHIPPED'));
1hs construnt ensures the status coumn s uwuys set to PLACED, PENDING, or SHIPPED.
1he loowng INSERT udds u row to the order_status2 tube (status s set to PENDING):
INSERT INTO order_status2 (
id, status, last_modified, modified_by
) VALUES (
1, 'PENDING', '01-JAN-2005', 1
);
ll you uttempt to udd u row thut doesn't sutsly the CHECK construnt, the dutubuse returns the
error ORA-02290. lor exumpe, the loowng INSERT uttempts to udd u row whose status s
not n the st:
INSERT INTO order_status2 (
id, status, last_modified, modified_by
) VALUES (
2, 'CLEARED', '01-JAN-2005', 2
);
INSERT INTO order_status2 (
*
ERROR at line 1:
ORA-02290: check constraint (STORE.ORDER_STATUS2_STATUS_CK) violated
ecuuse the CHECK construnt s vouted, the dutubuse reects the new row.
You cun use other compurson operutors wth u CHECK construnt. 1he next exumpe udds u
CHECK construnt thut enlorces thut the id vuue s greuter thun zero:
ALTER TABLE order_status2
ADD CONSTRAINT order_status2_id_ck CHECK (id > 0);
\hen uddng u construnt, the exstng rows n the tube must sutsly the construnt. lor
exumpe, l the order_status2 tube hud rows n t, then the id coumn lor the rows woud
need to be greuter thun zero.
NOTf
Thcrc arc cxccp|on |o |hc ruc rcqurng |ha| cx|ng rov a||,
|hc con|ran|. You can dabc a con|ran| vhcn ,ou n|a, add |,
and ,ou can c| a con|ran| |o app, on, |o ncv da|a, b, pcc|,ng
ENABLE NOVALIDATE. You' carn morc abou| |h a|cr.
Adding a NOT NUll Cunstraint
1he loowng ALTER TABLE stutement udds u NOT NULL construnt to the status coumn ol
the order_status2 tube:
ALTER TABLE order_status2
MODIFY status CONSTRAINT order_status2_status_nn NOT NULL;
308
Cruce Dutubuse llg SQL
Notce thut you use MODIFY to udd u NOT NULL construnt ruther thun ADD CONSTRAINT.
1he next exumpe udds u NOT NULL construnt to the modified_by coumn:
ALTER TABLE order_status2
MODIFY modified_by CONSTRAINT order_status2_modified_by_nn NOT NULL;
1he loowng exumpe udds u NOT NULL construnt to the last_modified coumn:
ALTER TABLE order_status2
MODIFY last_modified NOT NULL;
Notce thut l ddn't suppy u nume lor ths construnt. ln ths cuse, the dutubuse uutomutcuy
ussgns un unlrendy nume to the construnt, ke SYS_C003381.
TlP
Ava, pcc|, a mcanng|u namc |o ,our con|ran|. Tha| va,, vhcn
a con|ran| crror occur, ,ou can ca, dcn||, |hc probcm.
Adding a fORflGN kfY Cunstraint
elore you see un exumpe ol uddng u FOREIGN KEY construnt, the loowng ALTER TABLE
stutement drops the order_status2.modified_by coumn:
ALTER TABLE order_status2
DROP COLUMN modified_by;
1he next stutement udds u FOREIGN KEY construnt thut relerences the employees
.employee_id coumn:
ALTER TABLE order_status2
ADD CONSTRAINT order_status2_modified_by_fk
modified_by REFERENCES employees(employee_id);
You use the ON DELETE CASCADE cuuse wth u FOREIGN KEY construnt to specly thut
when u row n the purent tube s deeted, uny mutchng rows n the chd tube ure uso deeted.
1he loowng exumpe drops the modified_by coumn und rewrtes the prevous exumpe to
ncude the ON DELETE CASCADE cuuse:
ALTER TABLE order_status2
DROP COLUMN modified_by;
ALTER TABLE order_status2
ADD CONSTRAINT order_status2_modified_by_fk
modified_by REFERENCES employees(employee_id) ON DELETE CASCADE;
\hen u row s deeted lrom the employees tube, uny mutchng rows n order_status2
ure uso deeted.
You use the ON DELETE SET NULL cuuse wth u FOREIGN KEY construnt to specly thut
when u row n the purent tube s deeted, the loregn key coumn lor the row (or rows) n the
chd tube s set to nu. 1he loowng exumpe drops the modified_by coumn lrom order_
status2 und rewrtes the prevous exumpe to ncude the ON DELETE SET NULL cuuse:
ALTER TABLE order_status2
DROP COLUMN modified_by;
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews
309
ALTER TABLE order_status2
ADD CONSTRAINT order_status2_modified_by_fk
modified_by REFERENCES employees(employee_id) ON DELETE SET NULL;
\hen u row s deeted lrom the employees tube, the modified_by coumn lor uny
mutchng rows n order_status2 s set to nu.
1o ceun up belore movng onto the next secton, the loowng stutement drops the
modified_by coumn:
ALTER TABLE order_status2
DROP COLUMN modified_by;
Adding a UNlQUf Cunstraint
1he loowng ALTER TABLE stutement udds u UNIQUE construnt to the order_status2
.status coumn:
ALTER TABLE order_status2
ADD CONSTRAINT order_status2_status_uq UNIQUE (status);
Any exstng or new rows must uwuys huve u unque vuue n the status coumn.
Drupping a Cunstraint
You drop u construnt usng the DROP CONSTRAINT cuuse ol ALTER TABLE. 1he loowng
exumpe drops the order_status2_status_uq construnt:
ALTER TABLE order_status2
DROP CONSTRAINT order_status2_status_uq;
DisabIing a Cunstraint
y deluut, u construnt s enubed when you creute t. You cun ntuy dsube u construnt by
uddng DISABLE to the end ol the CONSTRAINT cuuse. 1he loowng exumpe udds u construnt
to order_status2, but uso dsubes t:
ALTER TABLE order_status2
ADD CONSTRAINT order_status2_status_uq UNIQUE (status) DISABLE;
You cun dsube un exstng construnt usng the DISABLE CONSTRAINT cuuse ol ALTER
TABLE. 1he loowng exumpe dsubes the order_status2_status_nn construnt:
ALTER TABLE order_status2
DISABLE CONSTRAINT order_status2_status_nn;
You cun udd CASCADE ulter DISABLE CONSTRAINT to dsube u construnts thut depend
on the specled construnt. You use CASCADE when dsubng u prmury key or unque construnt
thut s purt ol u loregn key construnt ol unother tube.
fnabIing a Cunstraint
You cun enube un exstng construnt usng the ENABLE CONSTRAINT cuuse ol ALTER TABLE.
1he loowng exumpe enubes the order_status2_status_uq construnt:
ALTER TABLE order_status2
ENABLE CONSTRAINT order_status2_status_uq;
310
Cruce Dutubuse llg SQL
1o enube u construnt, u the rows n the tube must sutsly the construnt. lor exumpe, l the
order_status2 tube contuned rows, then the status coumn woud huve to contun unque
vuues.
You cun uppy u construnt to new dutu ony by speclyng ENABLE NOVALIDATE, lor
exumpe:
ALTER TABLE order_status2
ENABLE NOVALIDATE CONSTRAINT order_status2_status_uq;
NOTf
Thc dc|au| ENABLE VALIDATE, vhch mcan cx|ng rov mu|
pa |hc con|ran| chcc|.
Dcfcrrcd Cunstraints
A delerred construnt s one thut s enlorced when u trunsucton s commtted, you use the
DEFERRABLE cuuse when you ntuy udd the construnt. Cnce you've udded u construnt,
you cunnot chunge t to DEFERRABLE, nsteud, you must drop und re-creute the construnt.
\hen you udd u DEFERRABLE construnt, you cun murk t us INITIALLY IMMEDIATE or
INITIALLY DEFERRED. Murkng us INITIALLY IMMEDIATE meuns thut the construnt s
checked whenever you udd, updute, or deete rows lrom u tube (ths s the sume us the deluut
behuvor ol u construnt). INITIALLY DEFERRED meuns thut the construnt s ony checked
when u trunsucton s commtted. Let's tuke u ook ut un exumpe.
1he loowng stutement drops the order_status2_status_uq construnt:
ALTER TABLE order_status2
DROP CONSTRAINT order_status2_status_uq;
1he next exumpe udds the order_status2_status_uq construnt, settng t to
DEFERRABLE INITIALLY DEFERRED:
ALTER TABLE order_status2
ADD CONSTRAINT order_status2_status_uq UNIQUE (status)
DEFERRABLE INITIALLY DEFERRED;
ll you udd rows to order_status2, the order_status2_status_uq construnt sn't
enlorced unt you perlorm u commit.
Gctting lnfurmatiun un Cunstraints
You cun retreve nlormuton on your construnts by queryng the user_constraints vew.
1ube l0-4 descrbes some ol the coumns n user_constraints.
NOTf
You can rc|rcvc n|orma|on on a |hc con|ran| ,ou havc accc |o
b, qucr,ng |hc all_constraints vcv.
1he loowng exumpe retreves some ol the coumns lrom user_constraints lor the
order_status2 tube:
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews
311
SELECT constraint_name, constraint_type, status, deferrable, deferred
FROM user_constraints
WHERE table_name = 'ORDER_STATUS2';
CONSTRAINT_NAME C STATUS DEFERRABLE DEFERRED
------------------------------ - -------- -------------- ---------
ORDER_STATUS2_PK P ENABLED NOT DEFERRABLE IMMEDIATE
ORDER_STATUS2_STATUS_CK C ENABLED NOT DEFERRABLE IMMEDIATE
ORDER_STATUS2_ID_CK C ENABLED NOT DEFERRABLE IMMEDIATE
ORDER_STATUS2_STATUS_NN C DISABLED NOT DEFERRABLE IMMEDIATE
ORDER_STATUS2_STATUS_UQ U ENABLED DEFERRABLE DEFERRED
SYS_C004807 C ENABLED NOT DEFERRABLE IMMEDIATE
Notce thut u the construnts except one huve u heplu nume. Cne construnt hus the
dutubuse-generuted nume ol SYS_C004807 (ths nume s uutomutcuy generuted, und t w
be dllerent n your dutubuse). 1hs construnt s the one lor whch l omtted the nume when
creutng t eurer.
TlP
Ava, add a dccrp|vc namc |or ,our con|ran|.
Gctting lnfurmatiun un thc Cunstraints fur a CuIumn
You cun retreve nlormuton on the construnts lor u coumn by queryng the user_cons_
columns vew. 1ube l0-5 descrbes some ol the coumns n user_cons_columns.
NOTf
You can rc|rcvc n|orma|on on a |hc coumn con|ran| ,ou havc
accc |o b, qucr,ng |hc all_cons_columns vcv.
CuIumn Typc Dcscriptiun
owner VARCHAR2(30)
Cwner ol the construnt.
constraint_name VARCHAR2(30)
Nume ol the construnt.
constraint_type VARCHAR2(1)
Construnt type (P, R, C, U, V, or O). See 1ube
l0-3 lor the construnt type meunngs.
table_name VARCHAR2(30)
Nume ol the tube on whch the construnt s
delned.
status VARCHAR2(8)
Construnt stutus (ENABLED or DISABLED).
deferrable VARCHAR2(14)
\hether the construnt s delerrube
(DEFERRABLE or NOT DEFERRABLE).
deferred VARCHAR2(9)
\hether the construnt s enlorced mmedutey
or delerred (IMMEDIATE or DEFERRED).
TABlf 10-4 Somc Coumn n |hc user_constraints Vcv
312
Cruce Dutubuse llg SQL
1he loowng exumpe retreves the constraint_name und column_name lrom user_
cons_columns lor the order_status2 tube:
COLUMN column_name FORMAT a15
SELECT constraint_name, column_name
FROM user_cons_columns
WHERE table_name = 'ORDER_STATUS2'
ORDER BY constraint_name;
CONSTRAINT_NAME COLUMN_NAME
------------------------------ ---------------
ORDER_STATUS2_ID_CK ID
ORDER_STATUS2_PK ID
ORDER_STATUS2_STATUS_CK STATUS
ORDER_STATUS2_STATUS_NN STATUS
ORDER_STATUS2_STATUS_UQ STATUS
SYS_C004807 LAST_MODIFIED
1he next query ons user_constraints und user_cons_columns to get the column_
name, constraint_name, constraint_type, und status:
SELECT ucc.column_name, ucc.constraint_name, uc.constraint_type, uc.status
FROM user_constraints uc, user_cons_columns ucc
WHERE uc.table_name = ucc.table_name
AND uc.constraint_name = ucc.constraint_name
AND ucc.table_name = 'ORDER_STATUS2'
ORDER BY ucc.constraint_name;
COLUMN_NAME CONSTRAINT_NAME C STATUS
--------------- ------------------------------ - --------
ID ORDER_STATUS2_ID_CK C ENABLED
ID ORDER_STATUS2_PK P ENABLED
STATUS ORDER_STATUS2_STATUS_CK C ENABLED
STATUS ORDER_STATUS2_STATUS_NN C DISABLED
STATUS ORDER_STATUS2_STATUS_UQ U ENABLED
LAST_MODIFIED SYS_C004807 C ENABLED
CuIumn Typc Dcscriptiun
owner VARCHAR2(30)
Cwner ol the construnt
constraint_name VARCHAR2(30)
Nume ol the construnt
table_name VARCHAR2(30)
Nume ol the tube on whch the construnt
s delned
column_name VARCHAR2(4000)
Nume ol the coumn on whch the
construnt s delned
TABlf 10-S Somc Coumn n |hc user_cons_columns Vcv
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews
313
Rcnaming a TabIc
You renume u tube usng the RENAME stutement. 1he loowng exumpe renumes order_
status2 to order_state:
RENAME order_status2 TO order_state;
NOTf
| ,ou havc ucd |hc |abc namc n ,our con|ran| namc, |hcn ,ou
houd changc |hc namc o| ,our con|ran|.
1he next exumpe chunges the tube nume buck to the orgnu:
RENAME order_state TO order_status2;
Adding a Cummcnt tu a TabIc
A comment cun hep you remember whut the tube or coumn s used lor. You udd u comment
tube or coumn usng the COMMENT stutement. 1he loowng exumpe udds u comment to the
order_status2 tube:
COMMENT ON TABLE order_status2 IS
'order_status2 stores the state of an order';
1he next exumpe udds u comment to the order_status2.last_modified coumn:
COMMENT ON COLUMN order_status2.last_modified IS
'last_modified stores the date and time the order was modified last';
Rctricving TabIc Cummcnts
You cun retreve the comments on your tubes lrom the user_tab_comments vew, us shown here:
SELECT *
FROM user_tab_comments
WHERE table_name = 'ORDER_STATUS2';
TABLE_NAME TABLE_TYPE
------------------------------ -----------
COMMENTS
------------------------------------------
ORDER_STATUS2 TABLE
order_status2 stores the state of an order
Rctricving CuIumn Cummcnts
You cun retreve the comments on your coumns lrom the user_col_comments vew, lor exumpe:
SELECT *
FROM user_col_comments
WHERE table_name = 'ORDER_STATUS2';
TABLE_NAME COLUMN_NAME
------------------------------ ------------------------------
COMMENTS
------------------------------------------------------------------
ORDER_STATUS2 ID
314
Cruce Dutubuse llg SQL
ORDER_STATUS2 STATUS
ORDER_STATUS2 LAST_MODIFIED
last_modified stores the date and time the order was modified last
Truncating a TabIc
You truncute u tube usng the TRUNCATE stutement. 1hs removes a the rows lrom u tube und
resets the storuge ureu lor u tube. 1he loowng exumpe truncutes order_status2:
TRUNCATE TABLE order_status2;
TlP
| ,ou nccd |o rcmovc a |hc rov |rom a |abc, ,ou houd uc
TRUNCATE ra|hcr |han DELETE. Th bccauc TRUNCATE rcc|
|hc |oragc arca |or a |abc rcad, |o rcccvc ncv rov. A TRUNCATE
|a|cmcn| docn'| rcqurc an, undo pacc n |hc da|abac, and ,ou
don'| havc |o run a COMMIT |o ma|c |hc dcc|c pcrmancn|. Lndo
pacc an arca |ha| |hc da|abac o||varc uc |o rccord da|abac
changc.
Drupping a TabIc
You drop u tube usng the DROP TABLE stutement. 1he loowng exumpe drops the order_
status2 tube:
DROP TABLE order_status2;
1hs concudes the dscusson ol tubes. ln the next secton, you' eurn ubout sequences.
Scqucnccs
A cqucncc s u dutubuse tem thut generutes u sequence ol ntegers. You typcuy use the ntegers
generuted by u sequence to popuute u numerc prmury key coumn. ln ths secton, you' eurn
how to
Creute u sequence.
Retreve nlormuton on u sequence lrom the dutu dctonury.
Lse u sequence.
Modly u sequence.
Drop u sequence.
Crcating a Scqucncc
You creute u sequence usng the CREATE SEQUENCE stutement, whch hus the loowng syntux:
CREATE SEQUENCE sequence_name
[START WITH start_num]
[INCREMENT BY increment_num]
[ { MAXVALUE maximum_num | NOMAXVALUE } ]
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews

[ { MINVALUE minimum_num | NOMINVALUE } ]


[ { CYCLE | NOCYCLE } ]
[ { CACHE cache_num | NOCACHE } ]
[ { ORDER | NOORDER } ];
where
sequence_name s the nume ol the sequence.
start_num s the nteger to sturt the sequence. 1he deluut sturt number s l.
increment_num s the nteger to ncrement the sequence by. 1he deluut ncrement
number s l. 1he ubsoute vuue ol increment_num must be ess thun the dllerence
between maximum_num und minimum_num.
maximum_num s the muxmum nteger ol the sequence, maximum_num must be greuter
thun or equu to start_num, und maximum_num must be greuter thun minimum_num.
NOMAXVALUE specles the muxmum s l0
27
lor un uscendng sequence or l lor u
descendng sequence. NOMAXVALUE s the deluut.
minimum_num s the mnmum nteger ol the sequence, minimum_num must be ess
thun or equu to start_num, und minimum_num must be ess thun maximum_num.
NOMINVALUE specles the mnmum s l lor un uscendng sequence or l0
26
lor u
descendng sequence. NOMINVALUE s the deluut.
CYCLE meuns the sequence generutes ntegers even ulter reuchng ts muxmum or
mnmum vuue. \hen un uscendng sequence reuches ts muxmum vuue, the next
vuue generuted s the mnmum. \hen u descendng sequence reuches ts mnmum
vuue, the next vuue generuted s the muxmum.
NOCYCLE meuns the sequence cunnot generute uny more ntegers ulter reuchng ts
muxmum or mnmum vuue. NOCYCLE s the deluut.
cache_num s the number ol ntegers to keep n memory. 1he deluut number ol ntegers
to cuche s 20. 1he mnmum number ol ntegers thut muy be cuched s 2. 1he muxmum
ntegers thut muy be cuched s determned by the lormuu CEIL(maximum_num -
minimum_num)/ABS(increment_num).
NOCACHE meuns no cuchng. 1hs stops the dutubuse lrom pre-uocutng vuues lor
the sequence, whch prevents numerc gups n the sequence but reduces perlormunce.
Cups occur becuuse cuched vuues ure ost when the dutubuse s shut down. ll you omt
CACHE und NOCACHE, the dutubuse cuches 20 sequence numbers by deluut.
ORDER guuruntees the ntegers ure generuted n the order ol the request. You typcuy use
ORDER when usng Reu Appcuton Custers, whch ure set up und munuged by dutubuse
udmnstrutors. Reu Appcuton Custers ure mutpe dutubuse servers thut shure the sume
memory. Reu Appcuton Custers cun mprove perlormunce.
NOORDER doesn't guuruntee the ntegers ure generuted n the order ol the request. NOORDER
s the deluut.
316
Cruce Dutubuse llg SQL
1he loowng exumpe connects us the store user und creutes u sequence numed s_test
(l uwuys put s_ ut the begnnng ol sequences):
CONNECT store/store_password
CREATE SEQUENCE s_test;
ecuuse ths CREATE SEQUENCE stutement omts the optonu purumeters, the deluut vuues
ure used. 1hs meuns thut start_num und increment_num ure set to the deluut ol l.
1he next exumpe creutes u sequence numed s_test2 und specles vuues lor the optonu
purumeters:
CREATE SEQUENCE s_test2
START WITH 10 INCREMENT BY 5
MINVALUE 10 MAXVALUE 20
CYCLE CACHE 2 ORDER;
1he lnu exumpe creutes u sequence numed s_test3 thut sturts ut l0 und counts down to l:
CREATE SEQUENCE s_test3
START WITH 10 INCREMENT BY -1
MINVALUE 1 MAXVALUE 10
CYCLE CACHE 5;
Rctricving lnfurmatiun un Scqucnccs
You cun retreve nlormuton on your sequences lrom the user_sequences vew. 1ube l0-6
descrbes the coumns n user_sequences.
NOTf
You can rc|rcvc n|orma|on on a |hc cqucncc ,ou havc accc |o
b, qucr,ng |hc all_sequences vcv.
CuIumn Typc Dcscriptiun
sequence_name VARCHAR2(30)
Nume ol the sequence
min_value NUMBER
Mnmum vuue
max_value NUMBER
Muxmum vuue
increment_by NUMBER
Number to ncrement or decrement sequence by
cycle_flag VARCHAR2(1)
\hether the sequence cyces (Y or N)
order_flag VARCHAR2(1)
\hether the sequence s ordered (Y or N)
cache_size NUMBER
Number ol sequence vuues stored n memory
last_number NUMBER
Lust number thut wus generuted or cuched by the
sequence
TABlf 10-6 Somc Coumn n |hc user_sequences Vcv
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews
317
1he loowng exumpe retreves the detus lor the sequences lrom user_sequences:
COLUMN sequence_name FORMAT a13
SELECT * FROM user_sequences
ORDER BY sequence_name;
SEQUENCE_NAME MIN_VALUE MAX_VALUE INCREMENT_BY C O CACHE_SIZE LAST_NUMBER
------------- ---------- ---------- ------------ - - ---------- -----------
S_TEST 1 1.0000E+27 1 N N 20 1
S_TEST2 10 20 5 Y Y 2 10
S_TEST3 1 10 -1 Y N 5 10
Using a Scqucncc
A sequence generutes u seres ol numbers. A sequence contuns two pseudo coumns numed
currval und nextval thut you use to get the current vuue und the next vuue lrom the sequence.
elore retrevng the current vuue, you must lrst ntuze the sequence by retrevng the next
vuue. \hen you seect s_test.nextval the sequence s ntuzed to l. lor exumpe, the
loowng query retreves s_test.nextval, notce thut the dual tube s used n the FROM cuuse:
SELECT s_test.nextval
FROM dual;
NEXTVAL
----------
1
1he lrst vuue n the s_test sequence s l. Cnce the sequence s ntuzed, you cun get the
current vuue lrom the sequence by retrevng currval. lor exumpe:
SELECT s_test.currval
FROM dual;
CURRVAL
----------
1
\hen you retreve currval, nextval remuns unchunged, nextval ony chunges when
you retreve nextval to get the next vuue. 1he loowng exumpe retreves s_test.nextval
und s_test.currval, notce thut these vuues ure both 2:
SELECT s_test.nextval, s_test.currval
FROM dual;
NEXTVAL CURRVAL
---------- ----------
2 2
Retrevng s_test.nextval gets the next vuue n the sequence, whch s 2, s_test
.currval s uso 2.

Cruce Dutubuse ll SQL
1he next exumpe ntuzes s_test2 by retrevng s_test2.nextval, notce thut the lrst
vuue n the sequence s l0:
SELECT s_test2.nextval
FROM dual;
NEXTVAL
----------
10
1he muxmum vuue lor s_test2 s 20, und the sequence wus creuted wth the CYCLE
opton, meunng thut the sequence w cyce buck to l0 once t reuches the muxmum ol 20:
SELECT s_test2.nextval
FROM dual;
NEXTVAL
----------
15
SELECT s_test2.nextval
FROM dual;
NEXTVAL
----------
20
SELECT s_test2.nextval
FROM dual;
NEXTVAL
----------
10
1he s_test3 sequence sturts ut l0 und counts down to l:
SELECT s_test3.nextval
FROM dual;
NEXTVAL
----------
10
SELECT s_test3.nextval
FROM dual;
NEXTVAL
----------
9
SELECT s_test3.nextval
FROM dual;
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews
319
NEXTVAL
----------
8
PupuIating a Primary kcy Using a Scqucncc
Sequences ure uselu lor popuutng nteger prmury key coumn vuues. Let's tuke u ook ut un
exumpe. 1he loowng stutement re-creutes the order_status2 tube:
CREATE TABLE order_status2 (
id INTEGER CONSTRAINT order_status2_pk PRIMARY KEY,
status VARCHAR2(10),
last_modified DATE DEFAULT SYSDATE
);
Next, the loowng stutement creutes u sequence numed s_order_status2 (ths sequence
w be used to popuute the order_status2.id coumn shorty):
CREATE SEQUENCE s_order_status2 NOCACHE;
TlP
Vhcn ung a cqucncc |o popua|c a prmar, |c, coumn, ,ou
houd |,pca, uc NOCACHE |o avod gap n |hc cqucncc
o| numbcr (gap occur bccauc cachcd vauc arc o| vhcn
|hc da|abac hu| dovn). Hovcvcr, ung NOCACHE rcducc
pcr|ormancc. | ,ou arc ubsoutey sure ,ou can vc v|h gap n |hc
prmar, |c, vauc, |hcn condcr ung CACHE.
1he loowng INSERT stutements udd rows to order_status2, notce thut the vuue lor the
id coumn s set usng s_order_status2.nextval (returns l lor the lrst INSERT und 2 lor
the second INSERT):
INSERT INTO order_status2 (
id, status, last_modified
) VALUES (
s_order_status2.nextval, 'PLACED', '01-JAN-2006'
);
INSERT INTO order_status2 (
id, status, last_modified
) VALUES (
s_order_status2.nextval, 'PENDING', '01-FEB-2006'
);
1he loowng query retreves the rows lrom order_status2, notce thut the id coumn s
set to the lrst two vuues (l und 2) lrom the s_order_status2 sequence:
SELECT *
FROM order_status2;
ID STATUS LAST_MODI
---------- ---------- ---------
1 PLACED 01-JAN-06
2 PENDING 01-FEB-06
320
Cruce Dutubuse llg SQL
Mudifying a Scqucncc
You modly u sequence usng the ALTER SEQUENCE stutement. 1here ure some mtutons on
whut you cun modly n u sequence:
You cunnot chunge the sturt vuue ol u sequence.
1he mnmum vuue cunnot be more thun the current vuue ol the sequence.
1he muxmum vuue cunnot be ess thun the current vuue ol the sequence.
1he loowng exumpe modles s_test to ncrement the sequence ol numbers by 2:
ALTER SEQUENCE s_test
INCREMENT BY 2;
\hen ths s done, the new vuues generuted by s_test w be ncremented by 2. lor exumpe,
l s_test.currval s 2, then s_test.nextval s 4. 1hs s shown n the loowng exumpe:
SELECT s_test.currval
FROM dual;
CURRVAL
----------
2
SELECT s_test.nextval
FROM dual;
NEXTVAL
----------
4
Drupping a Scqucncc
You drop u sequence usng DROP SEQUENCE. 1he loowng exumpe drops s_test3:
DROP SEQUENCE s_test3;
1hs concudes the dscusson ol sequences. ln the next secton, you' eurn ubout ndexes.
lndcxcs
\hen ookng lor u purtcuur topc n u book, you cun ether scun the whoe book, or you cun
use the ndex to lnd the ocuton. An ndex lor u dutubuse tube s smur n concept to u book
ndex, except thut dutubuse ndexes ure used to lnd speclc rows n u tube. 1he downsde ol
ndexes s thut when u row s udded to the tube, uddtonu tme s requred to updute the ndex
lor the new row.
Ceneruy, you shoud creute un ndex on u coumn when you ure retrevng u smu number
ol rows lrom u tube contunng muny rows. A good rue ol thumb s
Crca|c an ndcx vhcn a qucr, rc|rcvc <= 10 pcrccn| o| |hc |o|a rov n a |abc.
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews
321
1hs meuns the coumn lor the ndex shoud contun u wde runge ol vuues. 1hese types
ol ndexes ure cued -tree ndexes, u nume whch comes lrom u tree dutu structure used n
computer scence. A good cunddute lor -tree ndexng woud be u coumn contunng u unque
vuue lor euch row (lor exumpe, u socu securty number). A poor cunddute lor -tree ndexng
woud be u coumn thut contuns ony u smu runge ol vuues (lor exumpe, N, S, L, \ or l, 2, 3,
4, 5, 6). An Cruce dutubuse uutomutcuy creutes u -tree ndex lor the prmury key ol u tube
und lor coumns ncuded n u unque construnt. lor coumns thut contun u smu runge ol
vuues, you cun use u btmup ndex.
ln ths secton, you' eurn how to
Creute u -tree ndex.
Creute u luncton-bused ndex.
Retreve nlormuton on un ndex lrom the dutu dctonury.
Modly un ndex.
Drop un ndex.
Creute u btmup ndex.
Crcating a B-trcc lndcx
You creute u -tree ndex usng CREATE INDEX, whch hus the loowng smpled syntux:
CREATE [UNIQUE] INDEX index_name ON
table_name(column_name[, column_name ...])
TABLESPACE tab_space;
where
UNIQUE meuns thut the vuues n the ndexed coumns must be unque.
index_name s the nume ol the ndex.
table_name s u dutubuse tube.
column_name s the ndexed coumn. You cun creute un ndex on mutpe coumns
(such un ndex s known us u compo|c ndcx).
tab_space s the tubespuce lor the ndex. ll you don't provde u tubespuce, the ndex
s stored n the user's deluut tubespuce.
TlP
or pcr|ormancc rcaon, ,ou houd |,pca, |orc ndcxc n a
d||crcn| |abcpacc |rom |abc. or mpc|,, |hc cxampc n |h
chap|cr uc |hc dc|au| |abcpacc. n a produc|on da|abac, |hc
da|abac admn|ra|or houd crca|c cpara|c |abcpacc |or |hc
|abc and ndcxc.
322
Cruce Dutubuse ll SQL
l' now gude you through the thought processes you shoud loow when creutng u -tree
ndex lor the customers.last_name coumn. Assume thut the customers tube contuns u
urge number ol rows und thut you reguury retreve rows usng the loowng type ol query:
SELECT customer_id, first_name, last_name
FROM customers
WHERE last_name = 'Brown';
Aso ussume thut the last_name coumn contuns somewhut unque vuues, so thut uny
query usng the last_name coumn n u WHERE cuuse w return ess thun l0 percent ol the
totu number ol rows n the tube. 1hs meuns the last_name coumn s therelore u good
cunddute lor ndexng.
1he loowng CREATE INDEX stutement creutes un ndex numed i_customers_last_
name on the last_name coumn ol the customers tube (l uwuys put i_ ut the sturt ol ndex
numes):
CREATE INDEX i_customers_last_name ON customers(last_name);
Cnce the ndex hus been creuted, the prevous query w tuke ess tme to compete.
You cun enlorce unqueness ol coumn vuues usng u unque ndex. lor exumpe, the
loowng stutement creutes u unque ndex numed i_customers_phone on the customers
.phone coumn:
CREATE UNIQUE INDEX i_customers_phone ON customers(phone);
You cun uso creute u composte ndex on mutpe coumns. lor exumpe, the loowng
stutement creutes u composte ndex numed i_employees_first_last_name on the first_
name und last_name coumns ol the employees tube:
CREATE INDEX i_employees_first_last_name ON
employees(first_name, last_name);
Crcating a functiun-Bascd lndcx
ln the prevous secton you suw the ndex i_customers_last_name. Let's suy you run the
loowng query:
SELECT first_name, last_name
FROM customers
WHERE last_name = UPPER('BROWN');
ecuuse ths query uses u lunctonUPPER(), n ths cusethe i_customers_last_
name ndex sn't used. ll you wunt un ndex to be bused on the resuts ol u luncton, you must
creute u luncton-bused ndex, such us:
CREATE INDEX i_func_customers_last_name
ON customers(UPPER(last_name));
ln uddton, the dutubuse udmnstrutor must set the ntuzuton purumeter QUERY_REWRITE_
ENABLED to true (the deluut s false) n order to tuke udvuntuge ol luncton-bused ndexes.
1he loowng exumpe sets QUERY_REWRITE_ENABLED to true:
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews
323
CONNECT system/manager
ALTER SYSTEM SET QUERY_REWRITE_ENABLED=TRUE;
Rctricving lnfurmatiun un lndcxcs
You cun retreve nlormuton on your ndexes lrom the user_indexes vew. 1ube l0-7
descrbes some ol the coumns n user_indexes.
NOTf
You can rc|rcvc n|orma|on on a |hc ndcxc ,ou havc accc |o b,
qucr,ng |hc all_indexes vcv.
1he loowng exumpe connects us the store user und retreves some ol the coumns lrom
user_indexes lor the customers und employees tubes, notce thut the st ol ndexes
ncudes customers_pk, whch s u unque ndex uutomutcuy creuted by the dutubuse lor
the customer_id prmury key coumn ol the customers tube:
CONNECT store/store_password
SELECT index_name, table_name, uniqueness, status
FROM user_indexes
WHERE table_name IN ('CUSTOMERS', 'EMPLOYEES')
ORDER BY index_name;
INDEX_NAME TABLE_NAME UNIQUENES STATUS
------------------------------ -------------------- --------- ------
CUSTOMERS_PK CUSTOMERS UNIQUE VALID
EMPLOYEES_PK EMPLOYEES UNIQUE VALID
I_CUSTOMERS_LAST_NAME CUSTOMERS NONUNIQUE VALID
I_CUSTOMERS_PHONE CUSTOMERS UNIQUE VALID
I_EMPLOYEES_FIRST_LAST_NAME EMPLOYEES NONUNIQUE VALID
I_FUNC_CUSTOMERS_LAST_NAME CUSTOMERS NONUNIQUE VALID
Rctricving lnfurmatiun un thc lndcxcs un a CuIumn
You cun retreve nlormuton on the ndexes on u coumn by queryng the user_ind_columns
vew. 1ube l0-8 descrbes some ol the coumns n user_ind_columns.
CuIumn Typc Dcscriptiun
index_name VARCHAR2(30)
Nume ol the ndex
table_owner VARCHAR2(30)
1he user who owns the tube
table_name VARCHAR2(30)
1he nume ol the tube on whch the ndex wus creuted
uniqueness VARCHAR2(9)
lndcutes whether the ndex s unque (UNIQUE or
NONUNIQUE)
status VARCHAR2(8)
lndcutes whether the ndex s vud (VALID or
INVALID)
TABlf 10-7 Somc Coumn n |hc user_indexes Vcv
324
Cruce Dutubuse llg SQL
NOTf
You can rc|rcvc n|orma|on on a |hc ndcxc ,ou havc accc |o b,
qucr,ng |hc all_ind_columns vcv.
1he loowng query retreves some ol the coumns lrom user_ind_columns lor the
customers und employees tubes:
COLUMN table_name FORMAT a15
COLUMN column_name FORMAT a15
SELECT index_name, table_name, column_name
FROM user_ind_columns
WHERE table_name IN ('CUSTOMERS', 'EMPLOYEES')
ORDER BY index_name;
INDEX_NAME TABLE_NAME COLUMN_NAME
------------------------------ --------------- ------------
CUSTOMERS_PK CUSTOMERS CUSTOMER_ID
EMPLOYEES_PK EMPLOYEES EMPLOYEE_ID
I_CUSTOMERS_LAST_NAME CUSTOMERS LAST_NAME
I_CUSTOMERS_PHONE CUSTOMERS PHONE
I_EMPLOYEES_FIRST_LAST_NAME EMPLOYEES LAST_NAME
I_EMPLOYEES_FIRST_LAST_NAME EMPLOYEES FIRST_NAME
I_FUNC_CUSTOMERS_LAST_NAME CUSTOMERS SYS_NC00006$
Mudifying an lndcx
You modly un ndex usng ALTER INDEX. 1he loowng exumpe renumes the i_customers_
phone ndex to i_customers_phone_number:
ALTER INDEX i_customers_phone RENAME TO i_customers_phone_number;
Drupping an lndcx
You drop un ndex usng the DROP INDEX stutement. 1he loowng exumpe drops the
i_customers_phone_number ndex:
DROP INDEX i_customers_phone_number;
Crcating a Bitmap lndcx
tmup ndexes ure typcuy used n da|a varchouc, whch ure dutubuses contunng very urge
umounts ol dutu. 1he dutu n u dutu wurehouse s typcuy reud usng muny queres, but the dutu
CuIumn Typc Dcscriptiun
index_name VARCHAR2(30)
Nume ol the ndex
table_name VARCHAR2(30)
Nume ol the tube
column_name VARCHAR2(4000)
Nume ol the ndexed coumn
TABlf 10-8 Somc Coumn n |hc user_ind_columns Vcv
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews
32S
s not modled by muny concurrent trunsuctons. Dutu wurehouses ure typcuy used by orgunzutons
lor busness ntegence unuyss, ke montorng sues trends.
A cunddute lor u btmup ndex s u coumn thut s relerenced n muny queres, but thut
contuns ony u smu runge ol vuues, lor exumpe:
N, S, L, \
l, 2, 3, 4, 5, 6
Crder puced, Crder shpped
An ndex buscuy contuns u ponter to u row n u tube thut contuns u gven ndex key vuue,
the key vuue s used to get the rowd lor the row n the tube. (As dscussed n Chupter 2, u rowd
s used nternuy by the dutubuse to store the physcu ocuton ol the row.) ln u -tree ndex, u st
ol rowds s stored lor euch key correspondng to the rows wth thut key vuue. ln u -tree ndex,
the dutubuse stores u st ol key vuues wth euch rowd, whch enubes the dutubuse to ocute un
uctuu row n u tube.
ln u btmup ndex, however, u btmup s used lor euch key vuue, the btmup enubes the
dutubuse to ocute u row. Luch bt n the btmup corresponds to u possbe rowd. ll the bt s set,
then t meuns thut the row wth the correspondng rowd contuns the key vuue. A muppng
luncton converts the bt poston to un uctuu rowd.
tmup ndexes ure typcuy used n tubes contunng urge umounts ol dutu und whose
contents ure not modled very olten. Aso, u btmup ndex shoud ony be creuted on coumns
thut contun u smu number ol dstnct vuues. ll the number ol dstnct vuues ol u coumn s ess
thun l percent ol the number ol rows n the tube, or l the vuues n u coumn ure repeuted more
thun l00 tmes, then the coumn s u cunddute lor u btmup ndex. lor exumpe, l you hud u
tube wth l mon rows, u coumn wth l0,000 dstnct vuues or ess s u good cunddute lor u
btmup ndex, uso, updutes to the rows n the tube shoud be rure, und the coumn woud need
to be lrequenty used n the WHERE cuuse ol queres.
1he loowng stutement creutes u btmup ndex on the status coumn ol the order_
status tube:
CREATE BITMAP INDEX i_order_status ON order_status(status);
NOTf
C| courc, |h cxampc no| a rca-vord cxampc bccauc |hc
order_status |abc doc no| con|an cnough rov.
You cun lnd more nlormuton on btmup ndexes n Cracc Da|abac cr|ormancc Tunng
Cudc und Cracc Da|abac Conccp|, both books pubshed by Cruce Corporuton. 1hese books
uso contun nlormuton ubout other exotc types ol ndexes you cun use.
1hs concudes the dscusson ol ndexes. ln the next secton, you' eurn ubout vews.
Vicws
A vew s u predelned query on one or more tubes (known us bac |abc). Retrevng nlormuton
lrom u vew s done n the sume munner us retrevng lrom u tube: you smpy ncude the vew n
the FROM cuuse ol u query. \th some vews you cun uso perlorm DML operutons on the buse
tubes.
326
Cruce Dutubuse llg SQL
NOTf
Vcv don'| |orc rov. Rov arc ava, |orcd n |abc.
You've ureudy seen some exumpes ol retrevng nlormuton lrom vews when you seected
rows lrom the dutu dctonury, whch s uccessed through vewslor exumpe, user_tables,
user_sequences, und user_indexes ure u vews.
Vews oller severu benelts, such us the loowng:
You cun put u compex query nto u vew und grunt users uccess to the vew. 1hs uows
you to hde compexty lrom users.
You cun stop users lrom drecty queryng the buse tubes by gruntng them uccess ony
to the vew.
You cun uow u vew to uccess ony certun rows n the buse tubes. 1hs uows you
to hde rows lrom un end user.
ln ths secton, you' eurn how to
Creute und use u vew.
Cet the detus ol u vew lrom the dutu dctonury.
Modly u vew.
Drop u vew.
Crcating and Using a Vicw
You creute u vew usng CREATE VIEW, whch hus the loowng smpled syntux:
CREATE [OR REPLACE] VIEW [{FORCE | NOFORCE}] VIEW view_name
[(alias_name[, alias_name ...])] AS subquery
[WITH {CHECK OPTION | READ ONLY} CONSTRAINT constraint_name];
where
OR REPLACE meuns the vew repuces un exstng vew.
FORCE meuns the vew s to be creuted even l the buse tubes don't exst.
NOFORCE meuns the vew s not creuted l the buse tubes don't exst. NOFORCE s the
deluut.
view_name s the nume ol the vew.
alias_name s the nume ol un uus lor un expresson n the subquery. 1here must be
the sume number ol uuses us there ure expressons n the subquery.
subquery s the subquery thut retreves lrom the buse tubes. ll you've supped uuses,
you cun use those uuses n the st ulter the SELECT.
WITH CHECK OPTION meuns thut ony the rows thut woud be retreved by the
subquery cun be nserted, upduted, or deeted. y deluut, the rows ure not checked.
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews
327
constraint_name s the nume ol the WITH CHECK OPTION or WITH READ ONLY
construnt.
WITH READ ONLY meuns the rows muy ony reud lrom the buse tubes.
1here ure two busc types ol vews:
Smpe vews, whch contun u subquery thut retreves lrom one buse tube
Compex vews, whch contun u subquery thut
Retreves lrom mutpe buse tubes
Croups rows usng u GROUP BY or DISTINCT cuuse
Contuns u luncton cu
You' eurn how to creute und use these types ol vews n the loowng sectons.
PriviIcgc fur Vicws
ln order to creute u vew, the user must huve the CREATE VIEW prvege. 1he loowng exumpe
connects us the system user und grunts the CREATE VIEW prvege to the store user:
CONNECT system/manager
GRANT CREATE VIEW TO store;
Crcating and Using SimpIc Vicws
Smpe vews uccess one buse tube. 1he loowng exumpe connects us the store user und
creutes u vew numed cheap_products_view whose subquery retreves products ony where
the prce s ess thun Sl5:
CONNECT store/store_password
CREATE VIEW cheap_products_view AS
SELECT *
FROM products
WHERE price < 15;
1he next exumpe creutes u vew numed employees_view whose subquery retreves u the
coumns lrom the employees tube except salary:
CREATE VIEW employees_view AS
SELECT employee_id, manager_id, first_name, last_name, title
FROM employees;
Pcrfurming a Qucry un a Vicw
Cnce you've creuted u vew, you cun use t to uccess the buse tube. 1he loowng query retreves
rows lrom cheap_products_view:
SELECT product_id, name, price
FROM cheap_products_view;
PRODUCT_ID NAME PRICE
---------- ------------------------------ ----------
4 Tank War 13.95
6 2412: The Return 14.95
328
Cruce Dutubuse llg SQL
7 Space Force 9 13.49
8 From Another Planet 12.99
9 Classical Music 10.99
11 Creative Yell 14.99
12 My Front Line 13.49
1he next exumpe retreves rows lrom employees_view:
SELECT *
FROM employees_view;
EMPLOYEE_ID MANAGER_ID FIRST_NAME LAST_NAME TITLE
----------- ---------- ---------- ---------- -------------
1 James Smith CEO
2 1 Ron Johnson Sales Manager
3 2 Fred Hobbs Salesperson
4 2 Susan Jones Salesperson
Pcrfurming an lNSfRT Using a Vicw
You cun perlorm DML stutements usng cheap_products_view. 1he loowng exumpe
perlorms un INSERT usng cheap_products_view und then retreves the row:
INSERT INTO cheap_products_view (
product_id, product_type_id, name, price
) VALUES (
13, 1, 'Western Front', 13.50
);
1 row created.
SELECT product_id, name, price
FROM cheap_products_view
WHERE product_id = 13;
PRODUCT_ID NAME PRICE
---------- ------------------------------ ----------
13 Western Front 13.5
NOTf
You can pcr|orm D\ |a|cmcn| on, v|h mpc vcv. Compcx
vcv don'| uppor| D\.
ecuuse cheap_products_view ddn't use WITH CHECK OPTION, you cun nsert, updute,
und deete rows thut uren't retrevube by the vew. 1he loowng exumpe nserts u row whose
prce s Sl6.50 (ths s greuter thun Sl5 und therelore not retrevube by the vew):
INSERT INTO cheap_products_view (
product_id, product_type_id, name, price
) VALUES (
14, 1, 'Eastern Front', 16.50
);
1 row created.
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews
329
SELECT *
FROM cheap_products_view
WHERE product_id = 14;
no rows selected
1he employees_view contuns u subquery thut seects every coumn lrom employees
except salary. \hen you perlorm un INSERT usng employees_view, the salary coumn
n the employees buse tube w be set to nu, lor exumpe:
INSERT INTO employees_view (
employee_id, manager_id, first_name, last_name, title
) VALUES (
5, 1, 'Jeff', 'Jones', 'CTO'
);
1 row created.
SELECT employee_id, first_name, last_name, salary
FROM employees
WHERE employee_id = 5;
EMPLOYEE_ID FIRST_NAME LAST_NAME SALARY
----------- ---------- ---------- ---------
5 Jeff Jones
1he salary coumn s nu.
Crcating a Vicw with a CHfCk OPTlON Cunstraint
You cun specly thut DML stutements on u vew must sutsly the subquery usng u CHECK OPTION
construnt. lor exumpe, the loowng stutement creutes u vew numed cheap_products_view2
thut hus u CHECK OPTION construnt:
CREATE VIEW cheap_products_view2 AS
SELECT *
FROM products
WHERE price < 15
WITH CHECK OPTION CONSTRAINT cheap_products_view2_price;
1he next exumpe uttempts to nsert u row usng cheap_products_view2 wth u prce ol
Sl9.50, notce thut the dutubuse returns un error becuuse the row sn't retrevube by the vew:
INSERT INTO cheap_products_view2 (
product_id, product_type_id, name, price
) VALUES (
15, 1, 'Southern Front', 19.50
);
INSERT INTO cheap_products_view2 (
*
ERROR at line 1:
ORA-01402: view WITH CHECK OPTION where-clause violation
330
Cruce Dutubuse llg SQL
Crcating a Vicw with a RfAD ONlY Cunstraint
You cun muke u vew reud-ony by uddng u READ ONLY construnt to the vew. lor exumpe, the
loowng stutement creutes u vew numed cheap_products_view3 thut hus u READ ONLY
construnt:
CREATE VIEW cheap_products_view3 AS
SELECT *
FROM products
WHERE price < 15
WITH READ ONLY CONSTRAINT cheap_products_view3_read_only;
1he loowng exumpe uttempts to nsert u row usng cheap_products_view3, notce thut
the dutubuse returns un error becuuse the vew s reud-ony und doesn't uow DML stutements:
INSERT INTO cheap_products_view3 (
product_id, product_type_id, name, price
) VALUES (
16, 1, 'Northern Front', 19.50
);
product_id, product_type_id, name, price
*
ERROR at line 2:
ORA-42399: cannot perform a DML operation on a read-only view
Gctting lnfurmatiun un Vicw Dcfinitiuns
You cun retreve nlormuton on vew delntons usng the DESCRIBE commund. 1he loowng
exumpe uses DESCRIBE wth cheap_products_view3:
DESCRIBE cheap_products_view3
Name Null? Type
----------------------------------------- -------- ------------
PRODUCT_ID NOT NULL NUMBER(38)
PRODUCT_TYPE_ID NUMBER(38)
NAME NOT NULL VARCHAR2(30)
DESCRIPTION VARCHAR2(50)
PRICE NUMBER(5,2)
You cun uso retreve nlormuton ubout your vews lrom the user_views vew. 1ube l0-9
descrbes some ol the coumns n user_views.
CuIumn Typc Dcscriptiun
view_name VARCHAR2(30)
Nume ol the vew
text_length NUMBER
Number ol churucters n the vew's subquery
text LONG
1ext ol the vew's subquery
TABlf 10-9 Somc Coumn n |hc user_views Vcv
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews
331
NOTf
You can rc|rcvc n|orma|on on a |hc ndcxc ,ou havc accc |o b,
qucr,ng all_views.
1o see the entre vew delnton stored n the text coumn, you use the SQL*lus commund
SET LONG, whch sets the number ol churucters dspuyed by SQL*lus when retrevng LONG
coumns. lor exumpe, the loowng commund sets LONG to 200:
SET LONG 200
1he loowng query retreves the view_name, text_length, und text coumns lrom
user_views:
SELECT view_name, text_length, text
FROM user_views
ORDER BY view_name;
VIEW_NAME TEXT_LENGTH
------------------------------ -----------
TEXT
------------------------------------------------------------------
CHEAP_PRODUCTS_VIEW 97
SELECT "PRODUCT_ID","PRODUCT_TYPE_ID","NAME","DESCRIPTION","PRICE"
FROM products
WHERE price < 15
CHEAP_PRODUCTS_VIEW2 116
SELECT "PRODUCT_ID","PRODUCT_TYPE_ID","NAME","DESCRIPTION","PRICE"
FROM products
WHERE price < 15
WITH CHECK OPTION
CHEAP_PRODUCTS_VIEW3 113
SELECT "PRODUCT_ID","PRODUCT_TYPE_ID","NAME","DESCRIPTION","PRICE"
FROM products
WHERE price < 15
WITH READ ONLY
EMPLOYEES_VIEW 75
SELECT employee_id, manager_id, first_name, last_name, title
FROM employees
Rctricving lnfurmatiun un Vicw Cunstraints
Lurer you suw thut you cun udd CHECK OPTION und READ ONLY construnts to u vew,
cheap_products_view2 contuned u CHECK OPTION construnt to ensure the prce wus
ess thun Sl5, cheap_products_view3 contuned u READ ONLY construnt to prevent
modlcutons to the rows n the buse tube.
You retreve nlormuton on vew construnts lrom the user_constraints vew, lor exumpe:
SELECT constraint_name, constraint_type, status, deferrable, deferred
FROM user_constraints
WHERE table_name IN ('CHEAP_PRODUCTS_VIEW2', 'CHEAP_PRODUCTS_VIEW3')
332
Cruce Dutubuse ll SQL
ORDER BY constraint_name;
CONSTRAINT_NAME C STATUS DEFERRABLE DEFERRED
------------------------------ - -------- -------------- ---------
CHEAP_PRODUCTS_VIEW2_PRICE V ENABLED NOT DEFERRABLE IMMEDIATE
CHEAP_PRODUCTS_VIEW3_READ_ONLY O ENABLED NOT DEFERRABLE IMMEDIATE
1he constraint_type lor CHEAP_PRODUCTS_VIEW2_PRICE s V, whch, us shown
eurer n 1ube l0-3, corresponds to u CHECK OPTION construnt. 1he constraint_type lor
CHEAP_PRODUCTS_VIEW3_READ_ONLY s O, whch corresponds to u READ ONLY construnt.
Crcating and Using CumpIcx Vicws
Compex vews contun subqueres thut
Retreve rows lrom mutpe buse tubes.
Croup rows usng u GROUP BY or DISTINCT cuuse.
Contun u luncton cu.
1he loowng exumpe creutes u vew numed products_and_types_view whose subquery
perlorms u lu outer on on the products und product_types tubes usng the SQL/92 syntux:
CREATE VIEW products_and_types_view AS
SELECT p.product_id, p.name product_name, pt.name product_type_name, p.price
FROM products p FULL OUTER JOIN product_types pt
USING (product_type_id)
ORDER BY p.product_id;
1he loowng exumpe queres products_and_types_view:
SELECT *
FROM products_and_types_view;
PRODUCT_ID PRODUCT_NAME PRODUCT_TY PRICE
---------- ------------------------------ ---------- ----------
1 Modern Science Book 19.95
2 Chemistry Book 30
3 Supernova Video 25.99
4 Tank War Video 13.95
5 Z Files Video 49.99
6 2412: The Return Video 14.95
7 Space Force 9 DVD 13.49
8 From Another Planet DVD 12.99
9 Classical Music CD 10.99
10 Pop 3 CD 15.99
11 Creative Yell CD 14.99
12 My Front Line 13.49
13 Western Front Book 13.5
14 Eastern Front Book 16.5
Magazine
1he next exumpe creutes u vew numed employee_salary_grades_view whose
subquery uses un nner on to retreve the suury grudes lor the empoyees:
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews
333
CREATE VIEW employee_salary_grades_view AS
SELECT e.first_name, e.last_name, e.title, e.salary, sg.salary_grade_id
FROM employees e INNER JOIN salary_grades sg
ON e.salary BETWEEN sg.low_salary AND sg.high_salary
ORDER BY sg.salary_grade_id;
1he loowng exumpe queres employee_salary_grades_view:
SELECT *
FROM employee_salary_grades_view;
FIRST_NAME LAST_NAME TITLE SALARY SALARY_GRADE_ID
---------- ---------- -------------------- ---------- ---------------
Fred Hobbs Salesperson 150000 1
Susan Jones Salesperson 500000 2
Ron Johnson Sales Manager 600000 3
James Smith CEO 800000 4
1he next exumpe creutes u vew numed product_average_view whose subquery uses
A WHERE cuuse to lter the rows lrom the products tube to those whose price s ess
thun Sl5.
A GROUP BY cuuse to group the remunng rows by the product_type_id coumn.
A HAVING cuuse to lter the row groups to those whose uveruge prce s greuter thun Sl3.
CREATE VIEW product_average_view AS
SELECT product_type_id, AVG(price) average_price
FROM products
WHERE price < 15
GROUP BY product_type_id
HAVING AVG(price) > 13
ORDER BY product_type_id;
1he loowng exumpe queres product_average_view:
SELECT *
FROM product_average_view;
PRODUCT_TYPE_ID AVERAGE_PRICE
--------------- -------------
1 13.5
2 14.45
3 13.24
13.49
Mudifying a Vicw
You cun competey repuce u vew usng CREATE OR REPLACE VIEW. 1he loowng exumpe
uses CREATE OR REPLACE VIEW to repuce product_average_view:
CREATE OR REPLACE VIEW product_average_view AS
SELECT product_type_id, AVG(price) average_price
FROM products
334
Cruce Dutubuse ll SQL
WHERE price < 12
GROUP BY product_type_id
HAVING AVG(price) > 11
ORDER BY product_type_id;
You cun uter the construnts on u vew usng ALTER VIEW. 1he loowng exumpe uses ALTER
VIEW to drop the cheap_products_view2_price construnt lrom cheap_products_view2:
ALTER VIEW cheap_products_view2
DROP CONSTRAINT cheap_products_view2_price;
Drupping a Vicw
You drop u vew usng DROP VIEW. 1he loowng exumpe drops cheap_products_view2:
DROP VIEW cheap_products_view2;
1hs concudes the dscusson ol vews. ln the next secton, you' eurn ubout lushbuck dutu
urchves.
fIashback Data Archivcs
lushbuck dutu urchves, whch ure new lor Cruce Dutubuse ll store chunges mude to u tube
over u perod ol tme und provde you wth u lu uudt tru. Cnce you've creuted u lushbuck
urchve und udded u tube to t you cun do the loowng:
Vew rows us they were ut u speclc tmestump
Vew rows us they were between two tmestumps
You creute u lushbuck urchve usng the CREATE FLASHBACK ARCHIVE stutement. 1he
loowng exumpe connects us the system user und creutes u lushbuck urchve numed test_
archive:
CONNECT system/manager
CREATE FLASHBACK ARCHIVE test_archive
TABLESPACE example
QUOTA 1 M
RETENTION 1 DAY;
Notce the loowng:
1he urchve s creuted n the example tubespuce, you cun see the lu st ol tubespuces
by runnng the query SELECT tablespace_name FROM dba_tablespaces.
1he test_archive hus u quotu ol l megubyte, whch meuns t cun store up to
l megubyte ol dutu n the example tubespuce.
1he dutu n test_archive s retuned lor l duy, ulter whch tme the dutu s purged.
You muy uter un exstng tube to store dutu n the urchve, lor exumpe:
ALTER TABLE store.products FLASHBACK ARCHIVE test_archive;
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews

Any subsequent chunges mude to the store.products tube ure now recorded n the urchve.
1he loowng INSERT stutement udds u row to the store.products tube:
INSERT INTO store.products (
product_id, product_type_id, name, description, price
) VALUES (
15, 1, 'Using Linux', 'How to Use Linux', 39.99
);
1he loowng query retreves ths row:
SELECT product_id, name, price
FROM store.products
WHERE product_id = 15;
PRODUCT_ID NAME PRICE
---------- ------------------------------ ----------
15 Using Linux 39.99
You cun vew the rows us they were 5 mnutes ugo usng the loowng query:
SELECT product_id, name, price
FROM store.products
AS OF TIMESTAMP
(SYSTIMESTAMP - INTERVAL '5' MINUTE);
PRODUCT_ID NAME PRICE
---------- ------------------------------ ----------
1 Modern Science 19.95
2 Chemistry 30
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
12 My Front Line 13.49
13 Western Front 13.5
14 Eastern Front 16.5
Notce thut the new row s mssng. 1hs s becuuse t wus udded to the tube ulter the dute
und tme specled n the query (ussumng the prevous INSERT wus run ess thun 5 mnutes ugo).
You cun uso vew the rows us they were ut u speclc tmestump usng the loowng query (l
you run ths query, you need to chunge the tmestump to u dute und tme belore you run the INSERT
stutement eurer):
SELECT product_id, name, price
FROM store.products
AS OF TIMESTAMP
TO_TIMESTAMP('2007-08-12 13:05:00', 'YYYY-MM-DD HH24:MI:SS');

Cruce Dutubuse ll SQL
1he new row w be mssng lrom the resuts ugun, becuuse t wus udded to the tube ulter
the dute und tme specled n the query.
You cun vew the rows us they were between two tmestumps usng the loowng query (you
need to chunge the tmestumps):
SELECT product_id, name, price
FROM store.products VERSIONS BETWEEN TIMESTAMP
TO_TIMESTAMP('2007-08-12 12:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND TO_TIMESTAMP('2007-08-12 12:59:59', 'YYYY-MM-DD HH24:MI:SS');
You cun vew the rows us they were between one tmestump und the present tme usng the
loowng query (you need to chunge the tmestump):
SELECT product_id, name, price
FROM store.products VERSIONS BETWEEN TIMESTAMP
TO_TIMESTAMP('2007-08-12 13:45:52', 'YYYY-MM-DD HH24:MI:SS')
AND MAXVALUE;
You cun stop urchvng ol dutu lor u tube usng ALTER TABLE, lor exumpe:
ALTER TABLE store.products NO FLASHBACK ARCHIVE;
\hen you creute u tube, you cun specly u lushbuck urchve lor thut tube, lor exumpe:
CREATE TABLE store.test_table (
id INTEGER,
name VARCHAR2(10)
) FLASHBACK ARCHIVE test_archive;
You cun vew the detus lor un urchve usng the loowng vews:
user_flashback_archive und dba_flashback_archive, whch dspuy generu
nlormuton ubout the lushbuck urchves
user_flashback_archive_ts und dba_flashback_archive_ts, whch dspuy
nlormuton ubout the tubespuces contunng the lushbuck urchves
user_flashback_archive_tables und dba_flashback_archive_tables,
whch dspuy nlormuton ubout the tubes thut ure enubed lor lushbuck urchvng
You cun uter u lushbuck urchve, lor exumpe, the loowng stutement chunges the dutu
retenton perod to 2 yeurs:
ALTER FLASHBACK ARCHIVE test_archive
MODIFY RETENTION 2 YEAR;
You cun purge the dutu lrom u lushbuck urchve belore u gven tmestump, lor exumpe, the
loowng stutement purges dutu oder thun l duy:
ALTER FLASHBACK ARCHIVE test_archive
PURGE BEFORE TIMESTAMP(SYSTIMESTAMP INTERVAL '1' DAY);
Chupter l0: Creutng 1ubes, Sequences, lndexes, und Vews
337
You cun purge u the dutu n u lushbuck urchve, lor exumpe:
ALTER FLASHBACK ARCHIVE test_archive PURGE ALL;
You cun drop u lushbuck urchve, lor exumpe:
DROP FLASHBACK ARCHIVE test_archive;
NOTf
Co ahcad and rcrun store_schema.sql |o rc-crca|c |hc |orc
|abc o |ha| ,our qucrc ma|ch mnc n |hc rc| o| |h boo|.
Summary
ln ths chupter, you huve eurned the loowng:
A tube s creuted usng the CREATE TABLE stutement.
A sequence generutes u sequence ol ntegers.
A dutubuse ndex cun speed up uccess to rows.
A vew s u predelned query on one or more buse tubes.
A lushbuck dutu urchve stores chunges mude to u tube over u perod ol tme.
ln the next chupter, you' eurn ubout lL/SQL progrummng.
This page intentionally left blank

lntroducng lL/SQL
lrogrummng
339
340
Cruce Dutubuse llg SQL
ruce udded u proceduru progrummng unguuge known us lL/SQL (lroceduru
Lunguuge/SQL) to Cruce Dutubuse 6. lL/SQL enubes you to wrte progrums thut
contun SQL stutements. ln ths chupter, you' eurn ubout the loowng lL/SQL
topcs:
ock structure
Vurubes und types
Condtonu ogc
Loops
Cursors, whch uow lL/SQL to reud the resuts returned by u query
lrocedures
lunctons
luckuges, whch ure used to group procedures und lunctons together n one unt
1rggers, whch ure bocks ol code thut ure run when u certun event occurs n the
dutubuse
Cruce Dutubuse llg enhuncements to lL/SQL
You cun use lL/SQL to udd busness ogc to u dutubuse uppcuton. 1hs centruzed busness
ogc cun be run by uny progrum thut cun uccess the dutubuse, ncudng SQL*lus, }uvu progrums,
Cr progrums, und more.
NOTf
or |u dc|a on hov |o accc a da|abac |hrough }ava, cc m, boo|
Cruce9 }DC lrogrummng (Cracc rc, 2002). or dc|a on hov
|o accc a da|abac |hrough C~, cc m, boo| Musterng Cr Dutubuse
lrogrummng (S,bcx, 200J).
BIuck Structurc
lL/SQL progrums ure dvded up nto structures known us boc|, wth euch bock contunng lL/
SQL und SQL stutements. A lL/SQL bock hus the loowng structure:
[DECLARE
declaration_statements
]
BEGIN
executable_statements
[EXCEPTION
exception_handling_statements
]
END;
/

Chupter ll: lntroducng lL/SQL lrogrummng

where
declaration_statements decure the vurubes used n the rest ol the lL/SQL bock.
DECLARE bocks ure optonu.
executable_statements ure the uctuu executube stutements, whch muy ncude
oops, condtonu ogc, und so on.
exception_handling_statements ure stutements thut hunde uny executon errors
thut mght occur when the bock s run. EXCEPTION bocks ure optonu.
Lvery stutement s termnuted by u semcoon (,), und u lL/SQL bock s termnuted usng the
lorwurd sush (/) churucter. elore l get nto the detus ol lL/SQL, you' see u smpe exumpe to
get u lee lor the unguuge. 1he loowng exumpe (contuned n the area_example.sql scrpt
n the SQL drectory) cucuutes the wdth ol u rectunge gven ts ureu und heght:
SET SERVEROUTPUT ON
DECLARE
v_width INTEGER;
v_height INTEGER := 2;
v_area INTEGER := 6;
BEGIN
-- set the width equal to the area divided by the height
v_width := v_area / v_height;
DBMS_OUTPUT.PUT_LINE('v_width = ' || v_width);
EXCEPTION
WHEN ZERO_DIVIDE THEN
DBMS_OUTPUT.PUT_LINE('Division by zero');
END;
/
1he SET SERVEROUTPUT ON commund turns the server output on so you cun see the nes
produced by DBMS_OUTPUT.PUT_LINE() on the screen when you run the scrpt n SQL*lus.
Alter ths ntu commund comes the lL/SQL bock tsel, whch s dvded nto the DECLARE,
BEGIN, und EXCEPTION bocks.
1he DECLARE bock contuns decurutons lor three INTEGER vurubes numed v_width, v_
height, und v_area (l uwuys put v_ ut the sturt ol vurube numes). 1he v_height und v_
area vurubes ure ntuzed to 2 und 6 respectvey.
Next comes the BEGIN bock, whch contuns three nes. 1he lrst ne s u comment thut
contuns the text set the wdth equu to the ureu dvded by the heght. 1he second ne sets v_
width to v_area dvded by v_height, ths meuns v_width s set to 3 (= 6 / 2). 1he thrd ne
cus DBMS_OUTPUT.PUT_LINE() to dspuy the vuue ol v_width on the screen. DBMS_OUTPUT
s u but-n puckuge ol code thut comes wth the Cruce dutubuse, umong other tems, DBMS_
OUTPUT contuns procedures thut uow you to output vuues to the screen.
Next, the EXCEPTION bock hundes uny uttempts to dvde u number by zero. lt does ths by
cutchng the ZERO_DIVIDE excepton, n the exumpe, no uttempt s uctuuy mude to dvde
by zero, but l you chunge v_height to 0 und run the scrpt you' see the excepton.
At the very end ol the scrpt, the lorwurd sush churucter (/) murks the end ol the lL/SQL bock.
342
Cruce Dutubuse llg SQL
1he loowng stng shows the executon ol the area_example.sql scrpt n SQL*lus:
SQL> @ C:\SQL\area_example.sql
v_width = 3
NOTf
| ,our area_example.sql crp| n a drcc|or, o|hcr |han
C:\SQL, uc ,our ovn drcc|or, n |hc prcvou command.
VariabIcs and Typcs
Vurubes ure decured wthn u DECLARE bock. As you suw n the prevous exumpe, u vurube
decuruton hus both u nume und u type. lor exumpe, the v_width vurube wus decured us
v_width INTEGER;
NOTf
Thc /S |,pc arc mar |o |hc da|abac coumn |,pc. You can
cc a |hc |,pc n |hc appcndx.
1he loowng exumpe shows more vurube decurutons (these vurubes coud be used to
store the coumn vuues lrom the products tube):
v_product_id INTEGER;
v_product_type_id INTEGER;
v_name VARCHAR2(30);
v_description VARCHAR2(50);
v_price NUMBER(5, 2);
You muy uso specly u vurube's type usng the %TYPE keyword, whch tes lL/SQL to use
the sume type us u specled coumn n u tube. 1he loowng exumpe uses %TYPE to decure u
vurube ol the sume type us the price coumn ol the products tube, whch s NUMBER(5, 2):
v_product_price products.price%TYPE;
CunditiunaI lugic
You use the IF, THEN, ELSE, ELSIF, und END IF keywords to perlorm condtonu ogc:
IF condition1 THEN
statements1
ELSIF condition2 THEN
statements2
ELSE
statements3
END IF;
where
condition1 und condition2 ure ooeun expressons thut evuuute to true or luse.
statements1, statements2, und statements3 ure lL/SQL stutements.
Chupter ll: lntroducng lL/SQL lrogrummng
343
1he condtonu ogc lows us loows:
ll condition1 s true, then statements1 ure executed.
ll condition1 s luse but condition2 s true, then statements2 ure executed.
ll nether condition1 nor condition2 s true, then statements3 ure executed.
You cun uso embed un IF stutement wthn unother IF stutement, us shown n the loowng
exumpe:
IF v_count > 0 THEN
v_message := 'v_count is positive';
IF v_area > 0 THEN
v_message := 'v_count and v_area are positive';
END IF
ELSIF v_count = 0 THEN
v_message := 'v_count is zero';
ELSE
v_message := 'v_count is negative';
END IF;
ln ths exumpe, l v_count s greuter thun 0, then v_message s set to 'v_count is
positive'. ll v_count und v_area ure greuter thun 0, then v_message s set to 'v_count
and v_area are positive'. 1he rest ol the ogc s strughtlorwurd.
luups
You use u oop to run stutements zero or more tmes. 1here ure three types ol oops n lL/SQL:
SimpIc Iuups run unt you expcty end the oop.
WHILE Iuups run unt u specled condton occurs.
FOR Iuups run u predetermned number ol tmes.
You' eurn ubout these oops n the loowng sectons.
SimpIc luups
A smpe oop runs unt you expcty end the oop. 1he syntux lor u smpe oop s us loows:
LOOP
statements
END LOOP;
1o end the oop, you use ether un EXIT or un EXIT WHEN stutement. 1he EXIT stutement ends
u oop mmedutey, the EXIT WHEN stutement ends u oop when u specled condton occurs.
1he loowng exumpe shows u smpe oop. A vurube numed v_counter s ntuzed to 0
pror to the begnnng ol the oop. 1he oop udds l to v_counter und exts when v_counter s
equu to 5 usng un EXIT WHEN stutement.
v_counter := 0;
LOOP
v_counter := v_counter + 1;
EXIT WHEN v_counter = 5;
END LOOP;
344
Cruce Dutubuse llg SQL
NOTf
Thc EXIT WHEN |a|cmcn| can appcar an,vhcrc n |hc oop codc.
ln Cruce Dutubuse llg you cun uso end the current teruton ol u oop usng the CONTINUE
or CONTINUE WHEN stutement. 1he CONTINUE stutement ends the current teruton ol the oop
uncondtonuy und contnues wth the next teruton, the CONTINUE WHEN stutement ends the
current teruton ol the oop when u specled condton occurs und then contnues wth the next
teruton. 1he loowng exumpe shows the use ol the CONTINUE stutement:
v_counter := 0;
LOOP
-- after the CONTINUE statement is executed, control returns here
v_counter := v_counter + 1;
IF v_counter = 3 THEN
CONTINUE; -- end current iteration unconditionally
END IF;
EXIT WHEN v_counter = 5;
END LOOP;
1he next exumpe shows the use ol the CONTINUE WHEN stutement:
v_counter := 0;
LOOP
-- after the CONTINUE WHEN statement is executed, control returns here
v_counter := v_counter + 1;
CONTINUE WHEN v_counter = 3; -- end current iteration when v_counter = 3
EXIT WHEN v_counter = 5;
END LOOP;
NOTf
A CONTINUE or CONTINUE WHEN |a|cmcn| canno| cro a
proccdurc, |unc|on, or mc|hod boundar,.
WHllf luups
A WHILE oop runs unt u specled condton occurs. 1he syntux lor u WHILE oop s us loows:
WHILE condition LOOP
statements
END LOOP;
1he loowng exumpe shows u WHILE oop thut executes whe the v_counter vurube s
ess thun 6:
v_counter := 0;
WHILE v_counter < 6 LOOP
v_counter := v_counter + 1;
END LOOP;
fOR luups
A FOR oop runs u predetermned number ol tmes, you determne the number ol tmes the oop
runs by speclyng the ovcr und uppcr bound lor u oop vurube. 1he oop vurube s then
ncremented (or decremented) euch tme uround the oop. 1he syntux lor u FOR oop s us loows:
Chupter ll: lntroducng lL/SQL lrogrummng
34S
FOR loop_variable IN [REVERSE] lower_bound..upper_bound LOOP
statements
END LOOP;
where
loop_variable s the oop vurube. You cun use u vurube thut ureudy exsts us the
oop vurube, or you cun ust huve the oop creute u new vurube lor you (ths occurs l
the vurube you specly doesn't exst). 1he oop vurube vuue s ncreused (or decreused
l you use the REVERSE keyword) by l euch tme through the oop.
REVERSE meuns thut the oop vurube vuue s to be decremented euch tme through
the oop. 1he oop vurube s ntuzed to the upper boundury, und s decremented by l
unt the oop vurube reuches the ower boundury. You must specly the ower boundury
belore the upper boundury.
lower_bound s the oop's ower boundury. 1he oop vurube s ntuzed to ths ower
boundury provded REVERSE s not used.
upper_bound s the oop's upper boundury. ll REVERSE s used, the oop vurube s
ntuzed to ths upper boundury.
1he loowng exumpe shows u FOR oop. Notce thut the vurube v_counter2 sn't expcty
decuredso the FOR oop uutomutcuy creutes u new INTEGER vurube numed v_counter2:
FOR v_counter2 IN 1..5 LOOP
DBMS_OUTPUT.PUT_LINE(v_counter2);
END LOOP;
1he loowng exumpe uses REVERSE:
FOR v_counter2 IN REVERSE 1..5 LOOP
DBMS_OUTPUT.PUT_LINE(v_counter2);
END LOOP;
ln ths exumpe, v_counter2 sturts ut 5, s decremented by l euch tme through the oop,
und ends ut l.
Cursurs
You use u to letch rows returned by u query. You retreve the rows nto the cursor usng u
query und then letch the rows one ut u tme lrom the cursor. You typcuy use the loowng lve
steps when usng u cursor:
1. Decure vurubes to store the coumn vuues lor u row.
2. Decure the cursor, whch contuns u query.
3. Cpen the cursor.
4. letch the rows lrom the cursor one ut u tme und store the coumn vuues n the vurubes
decured n Step l. You woud then do somethng wth those vurubes, such us dspuy
them on the screen, use them n u cucuuton, und so on.
S. Cose the cursor.
346
Cruce Dutubuse llg SQL
You' eurn the detus ol these lve steps n the loowng sectons, und you' see u smpe
exumpe thut gets the product_id, name, und price coumns lrom the products tube.
Stcp 1: DccIarc thc VariabIcs tu Sturc thc CuIumn VaIucs
1he lrst step s to decure the vurubes thut w be used to store the coumn vuues. 1hese
vurubes must be computbe wth the coumn types.
TlP
arcr ,ou av |ha| %TYPE ma, bc ucd |o gc| |hc |,pc o| a coumn.
| ,ou uc %TYPE vhcn dccarng ,our varabc, ,our varabc v
au|oma|ca, bc o| |hc corrcc| |,pc.
1he loowng exumpe decures three vurubes to store the product_id, name, und price
coumns lrom the products tube, notce thut %TYPE s used to uutomutcuy set the type ol the
vurubes to the sume type us the coumns:
DECLARE
v_product_id products.product_id%TYPE;
v_name products.name%TYPE;
v_price products.price%TYPE;
Stcp 2: DccIarc thc Cursur
Step 2 s to decure the cursor. A cursor decuruton conssts ol u nume thut you ussgn to the cursor
und the query you wunt to execute. 1he cursor decuruton, ke u other decurutons, s puced n
the decuruton secton. 1he syntux lor decurng u cursor s us loows:
CURSOR cursor_name IS
SELECT_statement;
where
cursor_name s the nume ol the cursor.
SELECT_statement s the query.
1he loowng exumpe decures u cursor numed v_product_cursor whose query retreves
the product_id, name, und price coumns lrom the products tube:
CURSOR v_product_cursor IS
SELECT product_id, name, price
FROM products
ORDER BY product_id;
1he query sn't executed unt you open the cursor.
Stcp 3: Opcn thc Cursur
Step 3 s to open the cursor. You open u cursor usng the OPEN stutement, whch must be puced
n the executube secton ol the bock.
1he loowng exumpe opens v_product_cursor, whch executes the query:
OPEN v_product_cursor;
Chupter ll: lntroducng lL/SQL lrogrummng
347
Stcp 4: fctch thc Ruws frum thc Cursur
Step 4 s to letch the rows lrom the cursor, whch you do usng the FETCH stutement. 1he FETCH
stutement reuds the coumn vuues nto the vurubes decured n Step l. FETCH uses the loowng
syntux:
FETCH cursor_name
INTO variable[, variable ...];
where
cursor_name s the nume ol the cursor.
variable s the vurube nto whch u coumn vuue lrom the cursor s stored. You need
to provde mutchng vurubes lor euch coumn vuue.
1he loowng FETCH exumpe retreves u row lrom v_product_cursor und stores the
coumn vuues n the v_product_id, v_name, und v_price vurubes creuted eurer n Step l:
FETCH v_product_cursor
INTO v_product_id, v_name, v_price;
ecuuse u cursor muy contun muny rows, you need u oop to reud them. 1o lgure out when
to end the oop, you cun use the ooeun vurube v_product_cursor%NOTFOUND. 1hs
vurube s true when there ure no more rows to reud n v_product_cursor. 1he loowng
exumpe shows u oop:
LOOP
-- fetch the rows from the cursor
FETCH v_product_cursor
INTO v_product_id, v_name, v_price;
-- exit the loop when there are no more rows, as indicated by
-- the Boolean variable v_product_cursor%NOTFOUND (= true when
-- there are no more rows)
EXIT WHEN v_product_cursor%NOTFOUND;
-- use DBMS_OUTPUT.PUT_LINE() to display the variables
DBMS_OUTPUT.PUT_LINE(
'v_product_id = ' || v_product_id || ', v_name = ' || v_name ||
', v_price = ' || v_price
);
END LOOP;
Notce thut l've used DBMS_OUTPUT.PUT_LINE() to dspuy the v_product_id, v_name,
und v_price vurubes thut were reud lor euch row. ln u reu uppcuton, you mght use v_price
n u compex cucuuton.
Stcp S: CIusc thc Cursur
Step 5 s to cose the cursor usng the CLOSE stutement. Cosng u cursor lrees up system
resources. 1he loowng exumpe coses v_product_cursor:
CLOSE v_product_cursor;
348
Cruce Dutubuse ll SQL
1he loowng secton shows u compete scrpt thut contuns u lve steps.
CumpIctc fxampIc: pruduct_cursur.sqI
1he loowng product_cursor.sql scrpt s contuned n the SQL drectory:
-- product_cursor.sql displays the product_id, name,
-- and price columns from the products table using a cursor
SET SERVEROUTPUT ON
DECLARE
-- step 1: declare the variables
v_product_id products.product_id%TYPE;
v_name products.name%TYPE;
v_price products.price%TYPE;
-- step 2: declare the cursor
CURSOR v_product_cursor IS
SELECT product_id, name, price
FROM products
ORDER BY product_id;
BEGIN
-- step 3: open the cursor
OPEN v_product_cursor;
LOOP
-- step 4: fetch the rows from the cursor
FETCH v_product_cursor
INTO v_product_id, v_name, v_price;
-- exit the loop when there are no more rows, as indicated by
-- the Boolean variable v_product_cursor%NOTFOUND (= true when
-- there are no more rows)
EXIT WHEN v_product_cursor%NOTFOUND;
-- use DBMS_OUTPUT.PUT_LINE() to display the variables
DBMS_OUTPUT.PUT_LINE(
'v_product_id = ' || v_product_id || ', v_name = ' || v_name ||
', v_price = ' || v_price
);
END LOOP;
-- step 5: close the cursor
CLOSE v_product_cursor;
END;
/
1o run ths scrpt, loow these steps:
1. Connect to the dutubuse us store wth the pussword store_password.
2. Run the product_cursor.sql scrpt usng SQL*lus:
SQL> @ C:\SQL\product_cursor.sql
Chupter ll: lntroducng lL/SQL lrogrummng
349
NOTf
| ,our product_cursor.sql crp| n a d||crcn| drcc|or, |rom
C:\SQL, uc ,our ovn drcc|or, n |hc prcvou command.
1he output lrom product_cursor.sql s us loows:
v_product_id = 1, v_name = Modern Science, v_price = 19.95
v_product_id = 2, v_name = Chemistry, v_price = 30
v_product_id = 3, v_name = Supernova, v_price = 25.99
v_product_id = 4, v_name = Tank War, v_price = 13.95
v_product_id = 5, v_name = Z Files, v_price = 49.99
v_product_id = 6, v_name = 2412: The Return, v_price = 14.95
v_product_id = 7, v_name = Space Force 9, v_price = 13.49
v_product_id = 8, v_name = From Another Planet, v_price = 12.99
v_product_id = 9, v_name = Classical Music, v_price = 10.99
v_product_id = 10, v_name = Pop 3, v_price = 15.99
v_product_id = 11, v_name = Creative Yell, v_price = 14.99
v_product_id = 12, v_name = My Front Line, v_price = 13.49
Cursurs and fOR luups
You cun use u FOR oop to uccess the rows n u cursor. \hen you do ths, you don't huve to
expcty open und cose the cursorthe FOR oop does ths uutomutcuy lor you. 1he loowng
product_cursor2.sql scrpt uses u FOR oop to uccess the rows n v_product_cursor,
notce thut ths scrpt contuns ess code thun product_cursor.sql:
-- product_cursor2.sql displays the product_id, name,
-- and price columns from the products table using a cursor
-- and a FOR loop
SET SERVEROUTPUT ON
DECLARE
CURSOR v_product_cursor IS
SELECT product_id, name, price
FROM products
ORDER BY product_id;
BEGIN
FOR v_product IN v_product_cursor LOOP
DBMS_OUTPUT.PUT_LINE(
'product_id = ' || v_product.product_id ||
', name = ' || v_product.name ||
', price = ' || v_product.price
);
END LOOP;
END;
/
1o run the product_cursor2.sql scrpt, you ssue u commund smur to the loowng:
SQL> @ "C:\SQL\product_cursor2.sql"
3S0
Cruce Dutubuse ll SQL
1he output lrom ths scrpt s us loows:
product_id = 1, name = Modern Science, price = 19.95
product_id = 2, name = Chemistry, price = 30
product_id = 3, name = Supernova, price = 25.99
product_id = 4, name = Tank War, price = 13.95
product_id = 5, name = Z Files, price = 49.99
product_id = 6, name = 2412: The Return, price = 14.95
product_id = 7, name = Space Force 9, price = 13.49
product_id = 8, name = From Another Planet, price = 12.99
product_id = 9, name = Classical Music, price = 10.99
product_id = 10, name = Pop 3, price = 15.99
product_id = 11, name = Creative Yell, price = 14.99
product_id = 12, name = My Front Line, price = 13.49
OPfN-fOR Statcmcnt
You muy uso use the OPEN-FOR stutement wth u cursor, whch udds even more lexbty when
processng cursors becuuse you cun ussgn the cursor to u dllerent query. 1hs s shown n the
loowng product_cursor3.sql scrpt:
-- product_cursor3.sql displays the product_id, name,
-- and price columns from the products table using a cursor
-- variable and the OPEN-FOR statement
SET SERVEROUTPUT ON
DECLARE
-- declare a REF CURSOR type named t_product_cursor
TYPE t_product_cursor IS
REF CURSOR RETURN products%ROWTYPE;
-- declare a t_product_cursor object named v_product_cursor
v_product_cursor t_product_cursor;
-- declare an object to store columns from the products table
-- named v_product (of type products%ROWTYPE)
v_product products%ROWTYPE;
BEGIN
-- assign a query to v_product_cursor and open it using OPEN-FOR
OPEN v_product_cursor FOR
SELECT * FROM products WHERE product_id < 5;
-- use a loop to fetch the rows from v_product_cursor into v_product
LOOP
FETCH v_product_cursor INTO v_product;
EXIT WHEN v_product_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(
'product_id = ' || v_product.product_id ||
', name = ' || v_product.name ||
', price = ' || v_product.price
);
Chupter ll: lntroducng lL/SQL lrogrummng

END LOOP;
-- close v_product_cursor
CLOSE v_product_cursor;
END;
/
ln the DECLARE bock, the loowng stutement decures u REF CURSOR type numed
t_product_cursor (l uwuys put t_ ut the sturt ol type numes):
TYPE t_product_cursor IS
REF CURSOR RETURN products%ROWTYPE;
A REF CURSOR s u ponter to u cursor, und s smur to u ponter n the C++ progrummng
unguuge. 1he prevous stutement decures u user-delned type numed t_product_cursor,
und returns u row contunng the vurous coumns ol the products tube (ths s ndcuted usng
%ROWTYPE). 1hs user-delned type muy be used to decure un uctuu obect, us shown n the
loowng stutement, whch decures un obect numed v_product_cursor:
v_product_cursor t_product_cursor;
1he loowng stutement decures un obect to store coumns lrom the products tube numed
v_product (ol type products%ROWTYPE):
v_product products%ROWTYPE;
ln the BEGIN bock, v_product_cursor s ussgned u query und opened by the loowng
OPEN-FOR stutement:
OPEN v_product_cursor FOR
SELECT * FROM products WHERE product_id < 5;
Alter ths stutement s executed, v_product_cursor w be ouded wth the lrst lour rows
n the products tube. 1he query ussgned to v_product_cursor cun be uny vud SELECT
stutement, ths meuns you cun re-use the cursor und ussgn unother query to the cursor uter n the
lL/SQL code.
Next, the loowng oop letches the rows lrom v_product_cursor nto v_product und
dspuys the row detus:
LOOP
FETCH v_product_cursor INTO v_product;
EXIT WHEN v_product_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(
'product_id = ' || v_product.product_id ||
', name = ' || v_product.name ||
', price = ' || v_product.price
);
END LOOP;
Alter the oop, v_product_cursor s cosed usng the loowng stutement:
CLOSE v_product_cursor;
1he output lrom ths scrpt s the sume us the output lrom product_cursor2.sql.
3S2
Cruce Dutubuse ll SQL
Uncunstraincd Cursurs
1he cursors n the prevous secton u huve u speclc return type, these cursors ure known us
construned cursors. 1he return type lor u construned cursor must mutch the coumns n the
query thut s run by the cursor. An unconstruned cursor hus no return type, und cun therelore
run uny query.
1he use ol un unconstruned cursor s shown n the loowng unconstrained_cursor
.sql scrpt, notce v_cursor n the code s used to run two dllerent queres:
-- This script shows the use of unconstrained cursors
SET SERVEROUTPUT ON
DECLARE
-- declare a REF CURSOR type named t_cursor (this has no return
-- type and can therefore run any query)
TYPE t_cursor IS REF CURSOR;
-- declare a t_cursor object named v_cursor
v_cursor t_cursor;
-- declare an object to store columns from the products table
-- named v_product (of type products%ROWTYPE)
v_product products%ROWTYPE;
-- declare an object to store columns from the customers table
-- named v_customer (of type customers%ROWTYPE)
v_customer customers%ROWTYPE;
BEGIN
-- assign a query to v_cursor and open it using OPEN-FOR
OPEN v_cursor FOR
SELECT * FROM products WHERE product_id < 5;
-- use a loop to fetch the rows from v_cursor into v_product
LOOP
FETCH v_cursor INTO v_product;
EXIT WHEN v_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(
'product_id = ' || v_product.product_id ||
', name = ' || v_product.name ||
', price = ' || v_product.price
);
END LOOP;
-- assign a new query to v_cursor and open it using OPEN-FOR
OPEN v_cursor FOR
SELECT * FROM customers WHERE customer_id < 3;
-- use a loop to fetch the rows from v_cursor into v_product
LOOP
FETCH v_cursor INTO v_customer;
EXIT WHEN v_cursor%NOTFOUND;
Chupter ll: lntroducng lL/SQL lrogrummng
3S3
DBMS_OUTPUT.PUT_LINE(
'customer_id = ' || v_customer.customer_id ||
', first_name = ' || v_customer.first_name ||
', last_name = ' || v_customer.last_name
);
END LOOP;
-- close v_cursor
CLOSE v_cursor;
END;
/
1o run the unconstrained_cursor.sql scrpt, you ssue u commund smur to the
loowng:
SQL> @ "C:\SQL\unconstrained_cursor.sql"
1he output lrom ths scrpt s us loows:
product_id = 1, name = Modern Science, price = 19.95
product_id = 2, name = Chemistry, price = 30
product_id = 3, name = Supernova, price = 25.99
product_id = 4, name = Tank War, price = 13.95
customer_id = 1, first_name = John, last_name = Brown
customer_id = 2, first_name = Cynthia, last_name = Green
You' eurn more ubout REF CURSOR vurubes uter n ths chupter und more ubout user-
delned types n the next chupter.
fxccptiuns
Lxceptons ure used to hunde run-tme errors n your lL/SQL code. Lurer, you suw the loowng
lL/SQL exumpe thut contuns un EXCEPTION bock:
DECLARE
v_width INTEGER;
v_height INTEGER := 2;
v_area INTEGER := 6;
BEGIN
-- set the width equal to the area divided by the height
v_width := v_area / v_height;
DBMS_OUTPUT.PUT_LINE('v_width = ' || v_width);
EXCEPTION
WHEN ZERO_DIVIDE THEN
DBMS_OUTPUT.PUT_LINE('Division by zero');
END;
/
1he EXCEPTION bock n ths exumpe hundes un uttempt to dvde u number by zero. ln lL/
SQL termnoogy, the EXCEPTION bock ca|chc u ZERO_DIVIDE excepton thut s racd n the
BEGIN bock (uthough n the exumpe code, ZERO_DIVIDE s never uctuuy rused). 1he ZERO_
DIVIDE excepton und the other common exceptons ure shown n 1ube ll-l.
3S4
Cruce Dutubuse llg SQL
fxccptiun frrur Dcscriptiun
ACCESS_INTO_NULL ORA-06530
An uttempt wus mude to ussgn vuues to the
uttrbutes ol un unntuzed obect. (You' eurn
ubout obects n Chupter l2.)
CASE_NOT_FOUND ORA-06592
None ol the WHEN cuuses ol u CASE stutement
wus seected, und there s no deluut ELSE cuuse.
COLLECTION_IS_NULL ORA-06531
An uttempt wus mude to cu u coecton method
(other thun EXISTS) on un unntuzed nested
tube or vurruy, or un uttempt wus mude to ussgn
vuues to the eements ol un unntuzed nested
tube or vurruy. (You' eurn ubout coectons n
Chupter l3.)
CURSOR_ALREADY_OPEN ORA-06511
An uttempt wus mude to open un ureudy open
cursor. 1he cursor must be cosed belore t cun
be reopened.
DUP_VAL_ON_INDEX ORA-00001
An uttempt wus mude to store dupcute vuues n
u coumn thut s construned by u unque ndex.
INVALID_CURSOR ORA-01001
An uttempt wus mude to perlorm un egu cursor
operuton, such us cosng un unopened cursor.
INVALID_NUMBER ORA-01722
An uttempt to convert u churucter strng nto
u number lued becuuse the strng does not
represent u vud number. Note: ln lL/SQL
stutements, VALUE_ERROR s rused nsteud ol
INVALID_NUMBER.
LOGIN_DENIED ORA-01017
An uttempt wus mude to connect to u dutubuse
usng un nvud user nume or pussword.
NO_DATA_FOUND ORA-01403
A SELECT INTO stutement returned no rows,
or un uttempt wus mude to uccess u deeted
eement n u nested tube or un unntuzed
eement n un ndex by tube.
NOT_LOGGED_ON ORA-01012
An uttempt wus mude to uccess u dutubuse tem
wthout beng connected to the dutubuse.
PROGRAM_ERROR ORA-06501
lL/SQL hud un nternu probem.
ROWTYPE_MISMATCH ORA-06504
1he host cursor vurube und the lL/SQL cursor
vurube nvoved n un ussgnment huve
ncomputbe return types. lor exumpe, when
un open host cursor vurube s pussed to u stored
procedure or luncton, the return types ol the
uctuu und lormu purumeters must be computbe.
TABlf 11-1 rcdc|ncd xccp|on
Chupter ll: lntroducng lL/SQL lrogrummng
3SS
1he loowng sectons show exumpes thut ruse some ol the exceptons shown n 1ube ll-l.
ZfRO_DlVlDf fxccptiun
1he ZERO_DIVIDE excepton s rused when un uttempt s mude to dvde u number by zero. 1he
loowng exumpe uttempts to dvde l by 0 n the BEGIN bock und therelore ruses the ZERO_
DIVIDE excepton:
BEGIN
DBMS_OUTPUT.PUT_LINE(1 / 0);
EXCEPTION
WHEN ZERO_DIVIDE THEN
fxccptiun frrur Dcscriptiun
SELF_IS_NULL ORA-30625
An uttempt wus mude to cu u MEMBER method
on u nu obect. 1hut s, the but-n purumeter
SELF (whch s uwuys the lrst purumeter pussed
to u MEMBER method) s nu.
STORAGE_ERROR ORA-06500
1he lL/SQL modue run out ol memory or the
memory hus been corrupted.
SUBSCRIPT_BEYOND_COUNT ORA-06533
An uttempt wus mude to relerence u nested tube
or vurruy eement usng un ndex number urger
thun the number ol eements n the coecton.
SUBSCRIPT_OUTSIDE_LIMIT ORA-06532
An uttempt wus mude to relerence u nested tube
or vurruy eement usng un ndex number thut s
outsde the egu runge (l lor exumpe).
SYS_INVALID_ROWID ORA-01410
1he converson ol u churucter strng to u
unversu rowd lued becuuse the churucter
strng does not represent u vud rowd.
TIMEOUT_ON_RESOURCE ORA-00051
A tmeout occurred whe the dutubuse wus
wutng lor u resource.
TOO_MANY_ROWS ORA-01422
A SELECT INTO stutement returned more thun
one row.
VALUE_ERROR ORA-06502
An urthmetc, converson, truncuton, or sze-
construnt error occurred. lor exumpe, when
seectng u coumn vuue nto u churucter vurube,
l the vuue s onger thun the decured ength ol
the vurube, lL/SQL uborts the ussgnment und
ruses VALUE_ERROR.
Note: ln lL/SQL stutements, VALUE_ERROR s
rused l the converson ol u churucter strng nto
u number lus. ln SQL stutements, INVALID_
NUMBER s rused nsteud ol VALUE_ERROR.
ZERO_DIVIDE ORA-01476
An uttempt wus mude to dvde u number by zero.
TABlf 11-1 rcdc|ncd xccp|on (contnued)
3S6
Cruce Dutubuse ll SQL
DBMS_OUTPUT.PUT_LINE('Division by zero');
END;
/
Division by zero
\hen un excepton s rused, progrum contro pusses to the EXCEPTION bock und the WHEN
cuuse s exumned lor u mutchng excepton, the code nsde the mutchng cuuse s then executed.
ln the prevous exumpe, the ZERO_DIVIDE excepton s rused n the BEGIN bock, und progrum
contro then pusses to the EXCEPTION bock, u mutchng excepton s lound n the WHEN cuuse,
und the code nsde the cuuse s executed.
ll no mutchng excepton s lound, the excepton s propuguted to the encosng bock. lor
exumpe, l the EXCEPTION bock wus omtted lrom the prevous code, the excepton s propuguted
up to SQL*lus:
BEGIN
DBMS_OUTPUT.PUT_LINE(1 / 0);
END;
BEGIN
*
ERROR at line 1:
ORA-01476: divisor is equal to zero
ORA-06512: at line 2
As you cun see, SQL*lus dspuys u deluut error thut shows the ne numbers, the Cruce
error codes, und u smpe descrpton.
DUP_VAl_ON_lNDfX fxccptiun
1he DUP_VAL_ON_INDEX excepton s rused when un uttempt s mude to store dupcute vuues
n u coumn thut s construned by u unque ndex. 1he loowng exumpe uttempts to nsert u row
n the customers tube wth u customer_id ol l, ths cuuses DUP_VAL_ON_INDEX to be
rused, becuuse the customers tube ureudy contuns u row wth u customer_id ol l:
BEGIN
INSERT INTO customers (
customer_id, first_name, last_name
) VALUES (
1, 'Greg', 'Green'
);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
DBMS_OUTPUT.PUT_LINE('Duplicate value on an index');
END;
/
Duplicate value on an index
lNVAllD_NUMBfR fxccptiun
1he INVALID_NUMBER excepton s rused when un uttempt s mude to convert un nvud
churucter strng nto u number. 1he loowng exumpe uttempts to convert the strng 123X to
Chupter ll: lntroducng lL/SQL lrogrummng
3S7
u number thut s used n un INSERT, whch cuuses INVALID_NUMBER to
be rused becuuse 123X s not u vud number:
BEGIN
INSERT INTO customers (
customer_id, first_name, last_name
) VALUES (
'123X', 'Greg', 'Green'
);
EXCEPTION
WHEN INVALID_NUMBER THEN
DBMS_OUTPUT.PUT_LINE('Conversion of string to number failed');
END;
/
Conversion of string to number failed
OTHfRS fxccptiun
You cun use the OTHERS excepton to hunde u exceptons, us shown here:
BEGIN
DBMS_OUTPUT.PUT_LINE(1 / 0);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('An exception occurred');
END;
/
An exception occurred
ecuuse OTHERS mutches u exceptons, you must st t ulter uny speclc exceptons n your
EXCEPTION bock. ll you uttempt to st OTHERS esewhere, the dutubuse returns the error PLS-
00370, lor exumpe:
SQL> BEGIN
2 DBMS_OUTPUT.PUT_LINE(1 / 0);
3 EXCEPTION
4 WHEN OTHERS THEN
5 DBMS_OUTPUT.PUT_LINE('An exception occurred');
6 WHEN ZERO_DIVIDE THEN
7 DBMS_OUTPUT.PUT_LINE('Division by zero');
8 END;
9 /
WHEN OTHERS THEN
*
ERROR at line 4:
ORA-06550: line 4, column 3:
PLS-00370: OTHERS handler must be last among the exception
handlers of a block
ORA-06550: line 0, column 0:
PL/SQL: Compilation unit analysis terminated
3S8
Cruce Dutubuse ll SQL
Pruccdurcs
A procedure contuns u group ol SQL und lL/SQL stutements. lrocedures uow you to centruze
your busness ogc n the dutubuse und muy be used by uny progrum thut uccesses the dutubuse.
ln ths secton, you' eurn how to
Creute u procedure.
Cu u procedure.
Cet nlormuton on procedures.
Drop u procedure.
Vew errors n u procedure.
Crcating a Pruccdurc
You creute u procedure usng the CREATE PROCEDURE stutement. 1he smpled syntux lor the
CREATE PROCEDURE stutement s us loows:
CREATE [OR REPLACE] PROCEDURE procedure_name
[(parameter_name [IN | OUT | IN OUT] type [, ...])]
{IS | AS}
BEGIN
procedure_body
END procedure_name;
where
OR REPLACE meuns the procedure s to repuce un exstng procedure.
procedure_name s the nume ol the procedure.
parameter_name s the nume ol u purumeter thut s pussed to the procedure. You muy
puss mutpe purumeters to u procedure.
IN | OUT | IN OUT s the ol the purumeter. You muy pck one ol the loowng
modes lor euch purumeter:
IN, whch s the deluut mode lor u purumeter. An IN purumeter must be set to u
vuue when the procedure s run. 1he vuue ol un IN purumeter cunnot be chunged
n the procedure body.
OUT, whch meuns the purumeter s set to u vuue n the procedure body.
IN OUT, whch meuns the purumeter cun huve u vuue when the procedure s run,
und the vuue cun be chunged n the body.
type s the type ol the purumeter.
procedure_body contuns the uctuu code lor the procedure.
1he loowng exumpe creutes u procedure numed update_product_price()ths
procedure, und the other lL/SQL code shown n the rest ol ths chupter, wus creuted when you
Chupter ll: lntroducng lL/SQL lrogrummng

run the store_schema.sql scrpt. 1he update_product_price() procedure mutpes


the prce ol u product by u luctor, the product lD und the luctor ure pussed us purumeters to the
procedure. ll the product exsts, the procedure mutpes the product prce by the luctor und
commts the chunge.
CREATE PROCEDURE update_product_price(
p_product_id IN products.product_id%TYPE,
p_factor IN NUMBER
) AS
v_product_count INTEGER;
BEGIN
-- count the number of products with the
-- supplied product_id (will be 1 if the product exists)
SELECT COUNT(*)
INTO v_product_count
FROM products
WHERE product_id = p_product_id;
-- if the product exists (v_product_count = 1) then
-- update that product's price
IF v_product_count = 1 THEN
UPDATE products
SET price = price * p_factor
WHERE product_id = p_product_id;
COMMIT;
END IF;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END update_product_price;
/
1he procedure uccepts two purumeters numed p_product_id und p_factor (l uwuys put
p_ ut the sturt ol purumeter numes). oth ol these purumeters use the IN mode, whch meuns thut
ther vuues must be set when the procedure s run und thut the purumeter vuues cunnot be
chunged n the procedure body.
1he decuruton secton contuns un INTEGER vurube numed v_product_count:
v_product_count INTEGER;
1he body ol the procedure sturts ulter BEGIN. 1he SELECT stutement n the body gets the
number ol rows lrom the products tube whose product_id s equu to p_product_id:
SELECT COUNT(*)
INTO v_product_count
FROM products
WHERE product_id = p_product_id;

COUNT(*) rc|urn numbcr o| rov |ound.


360
Cruce Dutubuse llg SQL
ll the product s lound, v_product_count w be set to l, otherwse, v_product_count
w be set to 0. ll v_product_count s l, the price coumn s mutped by p_factor
usng the UPDATE stutement, und the chunge s commtted:
IF v_product_count = 1 THEN
UPDATE products
SET price = price * p_factor
WHERE product_id = p_product_id;
COMMIT;
END IF;
1he EXCEPTION bock perlorms u ROLLBACK l un excepton s rused:
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
lnuy, the END keyword s used to murk the end ol the procedure:
END update_product_price;
/
NOTf
Thc rcpc||on o| |hc proccdurc namc a||cr |hc END |c,vord no|
rcqurcd, bu| | good programmng prac|cc |o pu| | n.
CaIIing a Pruccdurc
You run (or ca ) u procedure usng the CALL stutement. 1he exumpe you' see n ths secton w
mutpy the prce ol product rl by l.5 usng the procedure shown n the prevous secton. lrst,
the loowng query retreves the prce ol product rl so you cun compure t wth the modled prce
uter:
SELECT price
FROM products
WHERE product_id = 1;
PRICE
----------
19.95
1he loowng stutement cus update_product_price(), pussng the purumeter vuues l
(the product_id) und l.5 (the luctor by whch the product prce s mutped):
CALL update_product_price(1, 1.5);
Call completed.
1hs stutement shows the use ol po|ona no|a|on to ndcute the vuues to be pussed to the
procedure or luncton. ln postonu notuton, the poston ol purumeters s used to ussgn the vuues
pussed to the procedure. ln the exumpe, the lrst vuue n the cu s l, und ths s pussed to the
lrst purumeter n the procedure (p_product_id), the second vuue n the cu s l.5, und ths
s pussed to the second purumeter (p_factor). ln Cruce Dutubuse llg, you cun uso use numed
und mxed notuton n uddton to postonu notuton, und you' eurn ubout these types ol
notuton shorty.
Chupter ll: lntroducng lL/SQL lrogrummng
361
1he next query retreves the detus lor product rl ugun, notce the prce hus been mutped
by l.5:
SELECT price
FROM products
WHERE product_id = 1;
PRICE
----------
29.93
ln Cruce Dutubuse llg you cun puss purumeters usng numed und mxed notuton. ln namcd
no|a|on, you ncude the nume ol the purumeter when cung u procedure. lor exumpe, the
loowng stutement cus update_product_price() usng numed notuton, notce thut the
vuues lor the p_factor und p_product_id purumeters ure ndcuted usng =>:
CALL update_product_price(p_factor => 1.3, p_product_id => 2);
TlP
^amcd no|a|on ma|c ,our codc cacr |o rcad and man|an bccauc
|hc paramc|cr arc cxpc|, hovn.
ln mxcd no|a|on, you use both postonu und numed notuton, you use postonu notuton
lor the lrst set ol purumeters und numed notuton lor the ust set ol purumeters. Mxed notuton s
uselu when you huve procedures und lunctons thut huve both requred und optonu purumeters,
you use postonu notuton lor the requred purumeters, und numed notuton lor the optonu
purumeters. 1he loowng exumpe uses mxed notuton, notce thut postonu notuton comes
belore numed notuton when speclyng the purumeter vuues:
CALL update_product_price(3, p_factor => 1.7);
Gctting lnfurmatiun un Pruccdurcs
You cun get nlormuton on your procedures lrom the user_procedures vew. 1ube ll-2
descrbes some ol the coumns n user_procedures.
CuIumn Typc Dcscriptiun
OBJECT_NAME VARCHAR2(30)
1he obect nume, whch muy be u procedure,
luncton, or puckuge nume
PROCEDURE_NAME VARCHAR2(30)
1he procedure nume
AGGREGATE VARCHAR2(3)
\hether the procedure s un uggregute luncton
(YES or NO)
IMPLTYPEOWNER VARCHAR2(30)
1he owner ol the type (l uny)
IMPLTYPENAME VARCHAR2(30)
1he nume ol the type (l uny)
PARALLEL VARCHAR2(3)
\hether the procedure s enubed lor purue
queres (YES or NO)
TABlf 11-2 Somc Coumn n |hc user_procedures Vcv
362
Cruce Dutubuse llg SQL
NOTf
You can gc| n|orma|on on a |hc proccdurc ,ou havc accc |o
ung all_procedures.
1he loowng exumpe retreves the object_name, aggregate, und parallel coumns
lrom user_procedures lor update_product_price():
SELECT object_name, aggregate, parallel
FROM user_procedures
WHERE object_name = 'UPDATE_PRODUCT_PRICE';
OBJECT_NAME AGG PAR
------------------------------ --- ---
UPDATE_PRODUCT_PRICE NO NO
Drupping a Pruccdurc
You drop u procedure usng DROP PROCEDURE. lor exumpe, the loowng stutement drops
update_product_price():
DROP PROCEDURE update_product_price;
Vicwing frrurs in a Pruccdurc
ll the dutubuse reports un error when you creute u procedure, you cun vew the errors usng the
SHOW ERRORS commund. lor exumpe, the loowng CREATE PROCEDURE stutement uttempts to
creute u procedure thut hus u syntux error ut ne 6 (the purumeter shoud be p_dob, not p_dobs):
SQL> CREATE PROCEDURE update_customer_dob (
2 p_customer_id INTEGER, p_dob DATE
3 ) AS
4 BEGIN
5 UPDATE customers
6 SET dob = p_dobs
7 WHERE customer_id = p_customer_id;
8 END update_customer_dob;
9 /
Warning: Procedure created with compilation errors.
As you cun see, there s u computon error. 1o vew the errors, you use SHOW ERRORS:
SQL> SHOW ERRORS
Errors for PROCEDURE UPDATE_CUSTOMER_DOB:
LINE/COL ERROR
-------- ---------------------------------------------
5/3 PL/SQL: SQL Statement ignored
6/13 PL/SQL: ORA-00904: invalid column name
Lne 5 wus gnored becuuse un nvud coumn nume wus relerenced n ne 6. You cun lx the
error by ssung un EDIT commund to edt the CREATE PROCEDURE stutement, chungng p_dobs
to p_dob, und rerunnng the stutement by enterng /.
Chupter ll: lntroducng lL/SQL lrogrummng
363
functiuns
A |unc|on s smur to u procedure, except thut u luncton must return u vuue. 1ogether, stored
procedures und lunctons ure sometmes relerred to us |orcd ubprogram becuuse they ure smu
progrums.
ln ths secton, you' eurn how to
Creute u luncton.
Cu u luncton.
Cet nlormuton on lunctons.
Drop u luncton.
Crcating a functiun
You creute u luncton usng the CREATE FUNCTION stutement. 1he smpled syntux lor the
CREATE FUNCTION stutement s us loows:
CREATE [OR REPLACE] FUNCTION function_name
[(parameter_name [IN | OUT | IN OUT] type [, ...])]
RETURN type
{IS | AS}
BEGIN
function_body
END function_name;
where
OR REPLACE meuns the procedure s to repuce un exstng luncton.
function_name s the nume ol the luncton.
parameter_name s the nume ol u purumeter thut s pussed to the luncton. You muy
puss mutpe purumeters to u luncton.
IN |OUT | IN OUT s the mode ol the purumeter.
type s the type ol the purumeter.
function_body contuns uctuu code lor the luncton. Lnke u procedure, the body ol
u luncton must return u vuue ol the type specled n the RETURN cuuse.
1he loowng exumpe creutes u luncton numed circle_area(), whch returns the ureu ol
u crce. 1he rudus ol the crce s pussed us u purumeter numed p_radius to circle_area(),
notce thut circle_area() returns u NUMBER:
CREATE FUNCTION circle_area (
p_radius IN NUMBER
) RETURN NUMBER AS
v_pi NUMBER := 3.1415926;
v_area NUMBER;
BEGIN
-- circle area is pi multiplied by the radius squared
364
Cruce Dutubuse ll SQL
v_area := v_pi * POWER(p_radius, 2);
RETURN v_area;
END circle_area;
/
1he next exumpe creutes u luncton numed average_product_price(), whch returns
the uveruge prce ol products whose product_type_id equus the purumeter vuue:
CREATE FUNCTION average_product_price (
p_product_type_id IN INTEGER
) RETURN NUMBER AS
v_average_product_price NUMBER;
BEGIN
SELECT AVG(price)
INTO v_average_product_price
FROM products
WHERE product_type_id = p_product_type_id;
RETURN v_average_product_price;
END average_product_price;
/
CaIIing a functiun
You cu your own lunctons us you woud cu uny ol the but-n dutubuse lunctons, you suw
how to cu but-n lunctons n Chupter 4. (}ust to relresh your memory, you cun cu u luncton
usng u SELECT stutement thut uses the dual tube n the FROM cuuse.) 1he loowng exumpe
cus circle_area(), pussng u rudus ol 2 meters to the luncton usng postonu notuton:
SELECT circle_area(2)
FROM dual;
CIRCLE_AREA(2)
--------------
12.5663704
ln Cruce Dutubuse ll, you cun uso use numed und mxed notuton when cung lunctons.
lor exumpe, the loowng query uses numed notuton when cung circle_area():
SELECT circle_area(p_radius => 4)
FROM dual;
CIRCLE_AREA(P_RADIUS=>4)
------------------------
50.2654816
1he next exumpe cus average_product_price(), pussng the purumeter vuue l to the
luncton to get the uveruge prce ol products whose product_type_id s l:
SELECT average_product_price(1)
FROM dual;
AVERAGE_PRODUCT_PRICE(1)
------------------------
29.965
Chupter ll: lntroducng lL/SQL lrogrummng
36S
Gctting lnfurmatiun un functiuns
You cun get nlormuton on your lunctons lrom the user_procedures vew, ths vew wus
covered eurer n the secton Cettng lnlormuton on lrocedures. 1he loowng exumpe
retreves the object_name, aggregate, und parallel coumns lrom user_procedures
lor circle_area() und average_product_price():
SELECT object_name, aggregate, parallel
FROM user_procedures
WHERE object_name IN ('CIRCLE_AREA', 'AVERAGE_PRODUCT_PRICE');
OBJECT_NAME AGG PAR
------------------------------ --- ---
AVERAGE_PRODUCT_PRICE NO NO
CIRCLE_AREA NO NO
Drupping a functiun
You drop u luncton usng DROP FUNCTION. lor exumpe, the loowng stutement drops
circle_area():
DROP FUNCTION circle_area;
Packagcs
ln ths secton, you' eurn how to group procedures und lunctons together nto pac|agc. luckuges
uow you to encupsuute reuted lunctonuty nto one sel-contuned unt. y moduurzng your
lL/SQL code through the use ol puckuges, you bud up your own brures ol code thut other
progrummers cun reuse. ln luct, the Cruce dutubuse comes wth u brury ol puckuges, whch uow
you to uccess externu les, munuge the dutubuse, generute H1ML, und much more, to see u the
puckuges, you shoud consut the Cracc Da|abac /S ac|agc and T,pc Rc|crcncc munuu
lrom Cruce Corporuton.
luckuges ure typcuy mude up ol two components: u pcc|ca|on und u bod,. 1he puckuge
speclcuton sts the uvuube procedures, lunctons, types, und obects. You cun muke the tems
sted n the speclcuton uvuube to u dutubuse users, und l reler to these tems us beng pubc
(uthough ony users you huve grunted prveges to uccess your puckuge cun use t). 1he speclcuton
doesn't contun the code thut mukes up the procedures und lunctons, the code s contuned n the
puckuge body.
Any tems n the body thut ure not sted n the speclcuton ure prva|c to the puckuge. lrvute
tems cun be used ony nsde the puckuge body. y usng u combnuton ol pubc und prvute tems,
you cun bud up u puckuge whose compexty s hdden lrom the outsde word. 1hs s one ol
the prmury gous ol u progrummng: hde compexty lrom your users.
Crcating a Packagc Spccificatiun
You creute u puckuge speclcuton usng the CREATE PACKAGE stutement. 1he smpled syntux
lor the CREATE PACKAGE stutement s us loows:
CREATE [OR REPLACE] PACKAGE package_name
{IS | AS}
package_specification
END package_name;
366
Cruce Dutubuse ll SQL
where
package_name s the nume ol the puckuge.
package_specification sts the pubc procedures, lunctons, types, und obects
uvuube to your puckuge's users.
1he loowng exumpe creutes u speclcuton lor u puckuge numed product_package:
CREATE PACKAGE product_package AS
TYPE t_ref_cursor IS REF CURSOR;
FUNCTION get_products_ref_cursor RETURN t_ref_cursor;
PROCEDURE update_product_price (
p_product_id IN products.product_id%TYPE,
p_factor IN NUMBER
);
END product_package;
/
1he t_ref_cursor type s u lL/SQL REF CURSOR type. A REF CURSOR s smur to u
ponter n the C++ progrummng unguuge, und t ponts to u cursor, us you suw eurer, u cursor
uows you to reud the rows returned by u query. 1he get_products_ref_cursor() luncton
returns u t_ref_cursor, und, us you' see n the next secton, t ponts to u cursor thut contuns
the rows retreved lrom the products tube.
1he update_product_price() procedure mutpes the prce ol u product und commts
the chunge.
Crcating a Packagc Budy
You creute u puckuge body usng the CREATE PACKAGE BODY stutement. 1he smpled syntux
lor the CREATE PACKAGE BODY stutement s us loows:
CREATE [OR REPLACE] PACKAGE BODY package_name
{IS | AS}
package_body
END package_name;
where
package_name s the nume ol the puckuge, whch must mutch the puckuge nume n the
speclcuton.
package_body contuns the code lor the procedures und lunctons.
1he loowng exumpe creutes the puckuge body lor product_package:
CREATE PACKAGE BODY product_package AS
FUNCTION get_products_ref_cursor
RETURN t_ref_cursor IS
v_products_ref_cursor t_ref_cursor;
BEGIN
-- get the REF CURSOR
OPEN v_products_ref_cursor FOR
SELECT product_id, name, price
FROM products;
Chupter ll: lntroducng lL/SQL lrogrummng
367
-- return the REF CURSOR
RETURN v_products_ref_cursor;
END get_products_ref_cursor;
PROCEDURE update_product_price (
p_product_id IN products.product_id%TYPE,
p_factor IN NUMBER
) AS
v_product_count INTEGER;
BEGIN
-- count the number of products with the
-- supplied product_id (will be 1 if the product exists)
SELECT COUNT(*)
INTO v_product_count
FROM products
WHERE product_id = p_product_id;
-- if the product exists (v_product_count = 1) then
-- update that product's price
IF v_product_count = 1 THEN
UPDATE products
SET price = price * p_factor
WHERE product_id = p_product_id;
COMMIT;
END IF;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END update_product_price;
END product_package;
/
1he get_products_ref_cursor() luncton opens the cursor und retreves the product_
id, name, und price coumns lrom the products tube 1he relerence to ths cursor (the REF
CURSOR) s stored n v_products_ref_cursor und returned by the luncton.
1he update_product_price() procedure mutpes the prce ol u product und commts
the chunge. 1hs procedure s dentcu to the one shown eurer n the secton Creutng u lrocedure,
so l won't go nto the detus on how t works ugun.
CaIIing functiuns and Pruccdurcs in a Packagc
\hen cung lunctons und procedures n u puckuge, you must ncude the puckuge nume n the
cu. 1he loowng exumpe cus product_package.get_products_ref_cursor(), whch
returns u relerence to u cursor contunng the product_id, name und price lor the products:
SELECT product_package.get_products_ref_cursor
FROM dual;
GET_PRODUCTS_REF_CUR
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
368
Cruce Dutubuse ll SQL
PRODUCT_ID NAME PRICE
---------- ------------------------------ ----------
1 Modern Science 19.95
2 Chemistry 30
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
12 My Front Line 13.49
1he next exumpe cus product_package.update_product_price() to mutpy
product r3's prce by l.25:
CALL product_package.update_product_price(3, 1.25);
1he next query retreves the detus lor product r3, notce thut the prce hus ncreused:
SELECT price
FROM products
WHERE product_id = 3;
PRICE
----------
32.49
Gctting lnfurmatiun un functiuns and Pruccdurcs
in a Packagc
You cun get nlormuton on your lunctons und procedures n u puckuge lrom the user_
procedures vew, ths vew wus covered eurer n the secton Cettng lnlormuton on
lrocedures. 1he loowng exumpe retreves the object_name und procedure_name
coumns lrom user_procedures lor product_package:
SELECT object_name, procedure_name
FROM user_procedures
WHERE object_name = 'PRODUCT_PACKAGE';
OBJECT_NAME PROCEDURE_NAME
------------------------------ ------------------------------
PRODUCT_PACKAGE GET_PRODUCTS_REF_CURSOR
PRODUCT_PACKAGE UPDATE_PRODUCT_PRICE
Drupping a Packagc
You drop u puckuge usng DROP PACKAGE. lor exumpe, the loowng stutement drops
product_package:
DROP PACKAGE product_package;
Chupter ll: lntroducng lL/SQL lrogrummng
369
Triggcrs
A |rggcr s u procedure thut s run (or |rcd ) uutomutcuy by the dutubuse when u specled DML
stutement (INSERT, UPDATE, or DELETE) s run ugunst u certun dutubuse tube. 1rggers ure
uselu lor dong thngs ke udvunced uudtng ol chunges mude to coumn vuues n u tube.
Whcn a Triggcr fircs
A trgger muy lre belore or ulter u DML stutement runs. Aso, becuuse u DML stutement cun ullect
more thun one row, the code lor the trgger muy be run once lor every row ullected (u rov-cvc
|rggcr), or ust once lor u the rows (u |a|cmcn|-cvc |rggcr). lor exumpe, l you creute u row-
eve trgger thut lres lor un UPDATE on u tube, und you run un UPDATE stutement thut modled
ten rows ol thut tube, then thut trgger woud run ten tmes. ll, however, your trgger wus u
stutement-eve trgger, the trgger woud lre once lor the whoe UPDATE stutement, regurdess
ol the number ol rows ullected.
1here s unother dllerence between u row-eve trgger und u stutement-eve trgger: A row-
eve trgger hus uccess to the od und new coumn vuues when the trgger lres us u resut ol un
UPDATE stutement on thut coumn. 1he lrng ol u row-eve trgger muy uso be mted usng u
trgger cond|on, lor exumpe, you coud set u condton thut mts the trgger to lre ony when
u coumn vuue s ess thun u specled vuue.
Sct Up fur thc fxampIc Triggcr
As mentoned, trggers ure uselu lor dong udvunced uudtng ol chunges mude to coumn vuues.
ln the next secton, you' see u trgger thut records when u product's prce s owered by more
thun 25 percent, when ths occurs, the trgger w udd u row to the product_price_audit
tube. 1he product_price_audit tube s creuted by the loowng stutement n the store_
schema.sql scrpt:
CREATE TABLE product_price_audit (
product_id INTEGER
CONSTRAINT price_audit_fk_products
REFERENCES products(product_id),
old_price NUMBER(5, 2),
new_price NUMBER(5, 2)
);
As you cun see, the product_id coumn ol the product_price_audit tube s u loregn
key to the product_id coumn ol the products tube. 1he old_price coumn w be used
to store the od prce ol u product pror to the chunge, und the new_price coumn w be used to
store the new prce ulter the chunge.
Crcating a Triggcr
You creute u trgger usng the CREATE TRIGGER stutement. 1he smpled syntux lor the CREATE
TRIGGER stutement s us loows:
CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER | INSTEAD OF | FOR} trigger_event
ON table_name
[FOR EACH ROW]
[{FORWARD | REVERSE} CROSSEDITION]

Cruce Dutubuse llg SQL
[{FOLLOWS | PRECEDES} schema.other_trigger}
[{ENABLE | DISABLE}]
[WHEN trigger_condition]]
BEGIN
trigger_body
END trigger_name;
where
OR REPLACE meuns the trgger s to repuce un exstng trgger, l present.
trigger_name s the nume ol the trgger.
BEFORE meuns the trgger lres belore the trggerng event s perlormed. AFTER meuns
the trgger lres ulter the trggerng event s perlormed. INSTEAD OF meuns the trgger
lres nsteud ol perlormng the trggerng event. FOR, whch s new lor Cruce Dutubuse
llg, uows you to creute u compound trgger consstng ol up to lour sectons n the
trgger body.
trigger_event s the event thut cuuses the trgger to lre.
table_name s the tube thut the trgger relerences.
FOR EACH ROW meuns the trgger s u row-eve trgger, thut s, the code contuned wthn
trigger_body s run lor euch row when the trgger lres. ll you omt FOR EACH ROW,
the trgger s u stutement-eve trgger, whch meuns the code wthn trigger_body s
run once when the trgger lres.
{FORWARD | REVERSE} CROSSEDITION s new lor Cruce Dutubuse llg und w
typcuy be used by dutubuse udmnstrutors or uppcuton udmnstrutors. A FORWARD
cross edton trgger s ntended to lre when u DML stutement mukes u chunge n the
dutubuse whe un onne uppcuton currenty uccessng the dutubuse bcng pa|chcd
or upgradcd (FORWARD s the deluut), the code n the trgger body must be desgned
to hunde the DML chunges when the uppcuton putchng or upgrude s compete. A
REVERSE cross edton trgger s smur, except t s ntended to lre und hunde DML
chunges mude a||cr |hc onnc appca|on ha bccn pa|chcd or upgradcd.
{FOLLOWS | PRECEDES} schema.other_trigger s new lor Cruce Dutubuse llg
und specles whether the lrng ol the trgger loows or precedes the lrng ol unother
trgger specled n schema.other_trigger. You cun creute u seres ol trggers thut
lre n u speclc order.
{ENABLE | DISABLE} s new lor Cruce Dutubuse llg und ndcutes whether the
trgger s ntuy enubed or dsubed when t s creuted (the deluut s ENABLE). You
enube u dsubed trgger by usng the ALTER TRIGGER trigger_name ENABLE
stutement or by enubng u trggers lor u tube usng ALTER TABLE table_name
ENABLE ALL TRIGGERS.
trigger_condition s u ooeun condton thut mts when u trgger uctuuy runs
ts code.
trigger_body contuns the code lor the trgger.

You might also like