You are on page 1of 32

Oracle9i Differences for Developers: Solutions to Workshops 1

Table of Contents

-- Lesson 2 FlashBack Query – Workshop ..........................................................2


-- Lesson 3 External Tables – Workshop ..............................................................4
-- Lesson 4 New SQL Features – Workshops.......................................................6
1. Merge .......................................................................................................6
2. Join ...........................................................................................................7
3. SubQuery With .........................................................................................8
4. Connect BY - Parts Report .......................................................................9
5. Case .......................................................................................................10
-- Lesson 5 New PL/SQL Features – Workshops ...............................................11
1. Associative Arrays ...................................................................................11
2. Pipelined Table Functions........................................................................11
3. UTL_FILE ................................................................................................13
-- Lesson 6 New Data Types – DateTime Workshop ..........................................14
-- Lesson 7 XML DB – Workshop........................................................................16
-- Lesson 8 Resumable Space Management – Workshop.................................19
-- Lesson 9 Security – Triple DES Encryption Workshop...................................21
-- Lesson 10 Indexes – Workshops....................................................................23
1. Bitmap Join ..............................................................................................23
2. Skip Scan................................................................................................23
-- Lesson 11 Indexes – Workshops....................................................................26
1. V$SQL_PLAN..........................................................................................26
2. DBMS_STATS.........................................................................................26
3. Dynamic Sampling...................................................................................27
4. Bind Variable Peeking .............................................................................28
4. Table Compression..................................................................................29
-- Appendix A Analytic Functions – Workshop ...................................................31

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 2

-- Lesson 2 FlashBack Query – Workshop


-- SkillBuilders, 2004

-- SkillBuilders Oracle9i Flashback Query Workshop

-- 1. If you have access to a DBA-level userid, login to it and


execute the
-- following queries to determine if flashback query is
enabled on your system:

connect system/dave@angela
/* Is UNDO management active? */
select value from v$parameter where name = 'undo_management';

/* Obtain retention parm */


select value from v$parameter where name = 'undo_retention';

-- 2. Connect to your usual class userid. Update the first name


of a row in the
-- Customer table, after having made a note of its current
value:

connect dave/dave@angela

/* Obtain current name */


select firstname from customer where cust_no = 9;

/* Change name and commit */

update customer set firstname='John' where cust_no = 9;

-- 3. Commit the change to make it permanent. Select the updated


record to make
-- sure it was updated.
commit;
select firstname from customer where cust_no = 9;

-- 4. Enter flashback mode, going back 10 minutes. This step can


be skipped IF
-- you use Release 2 statement level flashback.
exec dbms_flashback.enable_at_time(sysdate - 10/(24*60));

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 3

-- 5. Select the row you changed previously and verify that it


shows the old firstname value
select firstname from customer where cust_no = 9;

-- 6. Leave Flashback mode by executing:


exec dbms_flashback.disable;

-- 7. Re-select the row to insure you’ve gone back to the current


value.
select firstname from customer where cust_no = 9;

-- 8. Perform steps 4 and 5 using statement-level flashback.


select firstname
from customer AS OF TIMESTAMP sysdate - 10/(24*60)
where cust_no = 9;

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 4

-- Lesson 3 External Tables – Workshop


-- SkillBuilders, 2004
--
-- SkillBuilders Oracle9i New Features Workshop: External Tables
--

-- Create a directory:
create or replace directory davedirectory as 'c:\oraclass';

-- Grant read and write privileges on the directory to PUBLIC:

grant read, write on directory davedirectory to public;

-- drop table gold_cust_ext;

CREATE TABLE gold_cust_ext (


CUST_NO
NUMBER(38),
LASTNAME
VARCHAR2(20),
FIRSTNAME
VARCHAR2(15),
MIDINIT
VARCHAR2(1),
STREET
VARCHAR2(30),
CITY
VARCHAR2(20),
STATE
VARCHAR2(2),
ZIP
VARCHAR2(5),
ZIP_4
VARCHAR2(4),
AREA_CODE
VARCHAR2(3),
PHONE
VARCHAR2(8),
COMPANY_NAME
VARCHAR2(50)
)
ORGANIZATION EXTERNAL
(
TYPE oracle_loader
DEFAULT DIRECTORY davedirectory
ACCESS PARAMETERS

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 5

(
RECORDS FIXED 231
FIELDS (
CUST_NO INTEGER
EXTERNAL(10),
LASTNAME
CHAR(20),
FIRSTNAME
CHAR(15),
MIDINIT CHAR(1),
STREET
CHAR(30),
CITY
CHAR(20),
STATE CHAR(2),
ZIP CHAR(5),
ZIP_4 CHAR(4),
AREA_CODE CHAR(3),
PHONE CHAR(8),
COMPANY_NAME CHAR(50)
)
)
LOCATION ('gold_cust.txt')
)
PARALLEL 1
REJECT LIMIT UNLIMITED;

-- 2. Query the table with a SELECT statement.


select cust_no, lastname from gold_cust_ext;

-- 3. Insure that other users can query your new external table.
grant select on gold_cust_ext to public;
connect scott/tiger@class2
select cust_no, lastname from system.gold_cust_ext;

-- 4. Create a permanent Oracle table with the contents of the


external table.
create table gold_customers as select * from gold_cust_ext;

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 6

-- Lesson 4 New SQL Features – Workshops

1. Merge
-- SkillBuilders
-- Oracle9i SQL MERGE Workshop

-- Merge the contents of the CUSTOMER_LOAD table into the


CUSTOMER table.
-- If the customer exists (test CUST_NO), update the address and
phone number
-- fields.

MERGE INTO customer c


USING
(SELECT * FROM customer_load) cl
ON
(c.cust_no = cl.cust_no)
WHEN MATCHED THEN
UPDATE SET
c.street = cl.street,
c.city = cl.city,
c.state = cl.state,
c.zip = cl.zip,
c.zip_4 = cl.zip_4,
c.area_code = cl.area_code,
c.phone = cl.phone
WHEN NOT MATCHED THEN
INSERT (C.CUST_NO
,C.LASTNAME
,C.FIRSTNAME
,C.MIDINIT
,C.STREET
,C.CITY
,C.STATE
,C.ZIP
,C.ZIP_4
,C.AREA_CODE
,C.PHONE
,C.COMPANY_NAME )
VALUES( CL.CUST_NO
,CL.LASTNAME
,CL.FIRSTNAME
,CL.MIDINIT

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 7

,CL.STREET
,CL.CITY
,CL.STATE
,CL.ZIP
,CL.ZIP_4
,CL.AREA_CODE
,CL.PHONE
,CL.COMPANY_NAME );

-- You should receive this message:


-- 3 rows merged.

-- The merge should affect customers 1, 2 and 23424.


-- The following query shows the result:
-- SQL>
-- SQL> SELECT lastname, street, phone
-- 2 FROM customer
-- 3 WHERE cust_no IN (1, 2, 23424)
-- 4 /
--
-- LASTNAME STREET PHONE
-- -------------------- ------------------------------ --------
-- Jones 24 Salt Pond Road 783-6172
-- Smith 20 Rise Ave 444-4444
-- Bush 100 Pennsylvania Ave 999-9999

2. Join
-- SkillBuilders, 2004

-- SkillBuilders Workshop: ANSI JOINS


--
-- 1. Use an ANSI outer join to
-- create the following report of suppliers and products. Use
the NVL function
-- to convert nulls returned by the outer join to the string
"N/A".

-- SUPPLIER_NAME DESCRIPTION
-- ------------------------------ ------------------
-- Sharps Gift Supply Co. Long stem red rose
-- ACME Gift Supply Co. Long stem red rose
-- ABC Gift Supply Co. Long stem red rose
-- Sharps Gift Supply Co. 1 dozen roses
-- ACME Gift Supply Co. 1 dozen roses

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 8

-- ABC Gift Supply Co. 1 dozen roses


-- Brown Gift Supply Co. N/A
-- R and R Gift Supply Co. N/A
-- Pickax Gift Supply Co. N/A
-- Williamson Gift Supply Co. N/A
-- Real Cool Gift Supply Co. N/A
-- Dulls Gift Supply Co. N/A
-- XYZ Gift Supply Co. N/A

col supplier_name format a25


col description format a40

select supplier_name, nvl(description, 'N/A') AS description


from supplier left outer join product_supplier using
(supplier_no)
left outer join product using (product_id);

3. SubQuery With

-- SkillBuilders Oracle9i New Features Workshop: Subquery


Factoring (WITH)
--

-- Find all customers (display customer number and lastname) from


the CUSTOMER
-- and CUST_HISTORY tables that have spent $100 or more with our
company.
-- Use subquery factoring (ie the WITH clause) on the following
subquery:
-- select cust_no
-- from ord
-- group by cust_no
-- having sum(total_order_price) >= 100)
--

with
level_1_customer AS (select cust_no
from ord
group by cust_no
having sum(total_order_price) >= 100)

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 9

select cust_no, lastname


from customer
where cust_no in (Select * from level_1_customer)
UNION
select cust_no, lastname
from cust_history
where cust_no in (select * from level_1_customer)
/

4. Connect BY - Parts Report

--
-- SkillBuilders Oracle9i New Features: CONNECT BY Workshop
--
-- Use the PARTS table to create the following report. (If you
do not have a
-- PARTS table, run the supplied script PARTS.SQL.)
-- Note the sort on the PART_NAME column.

/*

PARTS
-----------------------
**10 widgets
****3 wodgets
******5 weebles
******4 weedgets
******6 woobles
********7 werbless
****2 wudgets

7 rows selected.

*/

--
-- Solution:
--

select lpad('*', 2*level, '*')


|| part_no || ' '
|| part_name AS parts
from parts

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 10

start with part_no = 10


connect by prior part_no = parent
order siblings by part_name
/

5. Case
-- SkillBuilders, 2004

-- SkillBuilders Oracel9i New Features Workshop: SQL CASE (8i)

-- Create the following histogram that displays the distribution


of
-- sales by total sales amount:
--
-- TOP_1_50 TOP_51_100 TOP_101_150 TOP_151_200 TOP_GT_200
-- ---------- ---------- ----------- ----------- ----------
-- 9 1 1 0 1

select
sum ( case when total_order_price between 1 and 50 then 1 else 0
end )
as top_1_50,
sum ( case when total_order_price between 51 and 100 then 1 else
0 end )
as top_51_100,
sum ( case when total_order_price between 101 and 150 then 1
else 0 end )
as top_101_150,
sum ( case when total_order_price between 151 and 200 then 1
else 0 end )
as top_151_200,
sum ( case when total_order_price > 200 then 1 else 0 end )
as top_GT_200
from ord
/

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 11

-- Lesson 5 New PL/SQL Features – Workshops

1. Associative Arrays
--
-- SkillBuilders Associative Array Workshop
-- Solutiuon:

DECLARE
TYPE product_count_type IS TABLE OF NUMBER(20) INDEX
BY VARCHAR2(75);
product_count product_count_type;
v_product_name product.description%TYPE;
v_product_count NUMBER(20);
v_index VARCHAR2(75);
CURSOR read_counts IS
SELECT description, count(ord_item.product_id)
FROM product, ord_item
WHERE product.product_id = ord_item.product_id (+)
GROUP BY description;
BEGIN
OPEN read_counts;
LOOP
FETCH read_counts INTO v_product_name,
v_product_count;
EXIT WHEN read_counts%NOTFOUND;
product_count(v_product_name) := v_product_count;
END LOOP;
CLOSE read_counts;
DBMS_OUTPUT.PUT_LINE (product_count.COUNT);
DBMS_OUTPUT.PUT_LINE (product_count.FIRST);
DBMS_OUTPUT.PUT_LINE (product_count.LAST);
v_index := product_count.FIRST; -- get subscript of first
element
WHILE v_index IS NOT NULL LOOP
DBMS_OUTPUT.PUT_LINE (v_index||'
'||product_count(v_index));
v_index := product_count.NEXT(v_index); -- get subscript
of next element
END LOOP;
END;
/

2. Pipelined Table Functions


-- SkillBuilders, 2004

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 12

-- Table Functions, Lab Solution

-- 1. Convert the supplied table function tablefunc1.sql


-- to a pipelined function. Test by running the queries
-- supplied at the end of tablefunc1.sql. Note that most
-- months will have zero sales; this is not an error.

create or replace type sqlMONTH_TABLEtype as table of date;


/

create or replace function month_generator


(p_num_months in number)
RETURN sqlMONTH_TABLEtype
PIPELINED
AS
month_table sqlMONTH_TABLEtype := sqlMONTH_TABLEtype();
BEGIN

for i in 1..p_num_months loop


pipe row( ADD_MONTHS(sysdate, -i) );
end loop;

return;

END;
/

show errors

select * from TABLE( CAST (month_generator(12) AS


sqlMONTH_TABLEtype) );

select to_Char(x.column_value, 'mm/yyyy')


from TABLE( month_generator(12) ) x
group by to_Char(x.column_value, 'mm/yyyy') ;

select to_Char(x.column_value, 'mm/yyyy') ,


nvl(avg(total_order_price),0) as avg_Sales
from TABLE( month_generator(12) ) x, ord
where to_Char(x.column_value, 'mm/yyyy') = to_Char(order_date(+),
'mm/yyyy')
group by to_Char(x.column_value, 'mm/yyyy') ;

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 13

select to_Char(x.column_value, 'mm/yyyy') ,


nvl(avg(total_order_price),0) as avg_Sales
from TABLE( month_generator(12) ) x LEFT OUTER JOIN ord
ON to_Char(x.column_value, 'mm/yyyy') = to_Char(order_date,
'mm/yyyy')
group by to_Char(x.column_value, 'mm/yyyy') ;

3. UTL_FILE
-- SkillBuilders, 2004

-- 9i Differences for Developers - UTL_FILE workshop solution

-- 1. Write a PL/SQL block to read an operating system file


called BLOB.JPG that contains 1 row of binary data.
-- Load the data into table blob_table. You may use any valid
number for column c1's data.

DECLARE
v_raw RAW(32767);
v_file_id UTL_FILE.FILE_TYPE;
BEGIN
/* Open the file for reading */
v_file_id:=
UTL_FILE.FOPEN('c:\','blob.jpg','r',32767);
/* Execute GET_RAW to retrieve the blob data */
UTL_FILE.GET_RAW (v_file_id,v_raw);
/* Load the data into the blob_table */
INSERT INTO blob_table VALUES (1,v_raw);
/* Close the file */
UTL_FILE.FCLOSE( v_file_id);
END;
/

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 14

-- Lesson 6 New Data Types – DateTime Workshop


--
-- SkillBuilders datetime data workshop
--

REM 1. Determine your session time zone:


select sessiontimezone from dual;

REM 2. If your session time zone is not US/Central Standard Time


(-06:00), alter
REM your session to Central Standard time:
alter session set time_zone = '-06:00';

REM 3. select current_timestamp from dual to see the session


time:
select current_timestamp from dual;

REM 4. Determine the database time zone:


select dbtimezone from dual;

REM 5. Create a table with two columns.


rem Use Datatypes: TIMESTAMP WITH TIME ZONE and TIMESTAMP WITH
LOCAL TIME ZONE

drop table t;

create table t
(c1 timestamp with time zone,
c2 timestamp with local time zone)
/

REM 6. Insert a row using the CURRENT_TIMESTAMP function for both


columns:

insert into t (c1,c2)


values
( current_timestamp,
current_timestamp );

REM 7. Display the contents of your table.


REM Write down the time (hour/minute) contained in each
column:
select * from t;
-- 18-APR-03 02.05.41.114000 PM -06:00

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 15

-- 18-APR-03 02.05.41.114000 PM

REM 8. Let's do some time travel!


REM Enter your time machine and travel to California!
REM Adjust your session time zone to -08:00
alter session set time_zone = '-08:00';

REM 9. Now display the contents of your time table.


REM What time does the TIMESTAMP WITH LOCAL TIME ZONE column
contain?
REM Why? Discuss your reasoning with your instructor.
select * from t;
REM
-- 18-APR-03 02.05.41.114000 PM -06:00
-- 18-APR-03 12.05.41.114000 PM
-- The first value is stored in a TIMESTAMP WITH TIME ZONE column
and shows the time
-- in the time zone that the data was inserted.
-- The second value is stored in a TIMESTAMP WITH LOCAL TIME ZONE
column and shows
-- the time in the sessions time zone, which we have set
-- to California , two hours earlier than -6:00 (Chicago).

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 16

-- Lesson 7 XML DB – Workshop


-- SkillBuilders, 2004

-- Introduction to XML DB Workshop solution

-- 1. Create a table called STUDENT_TRANSCRIPTS


-- containing two columns, ID (number primary key)
-- and transcript (xmltype not null).

CREATE TABLE student_transcript


(id NUMBER PRIMARY KEY,
transcript XMLType NOT NULL);

-- 2. Insert the XML document found in file xml_transcript.txt


into
-- your new table.
INSERT INTO student_transcript
VALUES
(1, xmltype('<?xml version="1.0" standalone="no" ?>
<transcript>
<student id="STU12345" name="Humpty Dumpty"
status="active">
<home_address>35 Wall Street, Wonderland, NJ
</home_address>
<interests>
<interest>French cooking (especially omelettes)
</interest>
<interest>Football (full contact)</interest>
<interest>The works of Charles
Dodgson</interest>
</interests>
</student>
<term>
<heading name="Winter 1999"/>
<course>
<course-name>Underwater Basket-Weaving</course-
name>
<grade>A-</grade>
<credits>4</credits>
</course>
<course>
<course-name>Sky Diving for Fun and
Profit</course-name>
<grade>B+</grade>
<credits>3</credits>

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 17

</course>
</term>
<term>
<heading name="Spring 1999"/>
<course>
<course-name>Physics for Poets</course-name>
<grade>A</grade>
<credits>7</credits>
</course>
<course>
<course-name>Poetry for Physicists</course-
name>
<grade>C+</grade>
<credits>5</credits>
</course>
</term>
<summary>Student has earned 19 credits so far</summary>
<comments>
Student seems well-rounded. He occasionally withdraws into his
shell
but is usually a good egg.
</comments>
</transcript>')
);

COMMIT;

-- 3. Set long 32000 for the remainder of this lab.


-- Use the EXTRACT function to display the home address
-- of the student inserted.
set long 32000

select extract(transcript,
'/transcript/student/home_address/text()' )
from student_transcript
/

-- 4. Use the EXTRACT function to display the name of the


student.
-- ("name" is an attribute of /transcript/student.)
select extract(transcript, '/transcript/student@name' )
from student_transcript;

-- 5. Display the interests of this student. Use the EXTRACT


function

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 18

-- and the following XPath:


-- /transcript/student/interests/interest/

select
extract(transcript,'/transcript/student/interests/interest/text()
')
from student_transcript;

-- 6. Use the UPDATEXML function to change the home_address to:


-- "1 Park Ave, New York, NY
update student_transcript
set transcript = updatexml(transcript,
'/transcript/student/home_address/text()',
'1 Park Ave, New York, NY')
where id = 1;
commit;

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 19

-- Lesson 8 Resumable Space Management – Workshop


-- SkillBuilders, 2004

-- Resumable Space Management workshop solution

-- 1. Modify the rsm_prep.sql script to supply a unique


tablespace name.
-- Execute the script to create the tablespace.
connect system/dave@class2
create tablespace dave datafile size 1m autoextend off;
alter user dave quota unlimited on dave;
disc

-- 2. Modify the rsm_load.sql script to enter the tablespace name


and enable resumable mode.
-- Execute the rsm_load.sql script. This script is loading
data into the ORDER_SUMMARY table.
create table order_summary
(order_no number(5),
order_total number(11,2))
tablespace dave;

-- Enter resumable mode:

alter session enable resumable timeout 600 name 'dave';

declare
v_order_total order_summary.order_total%type;
begin
for i in 1..90000 loop
v_order_total := i * 1.10;
insert into order_summary values (i, v_order_total);
end loop;
end;
/

-- 3. Create a second session and diagnose the problem. Once you


have the problem identified,
-- attempt to correct the problem and make sure the
ORDER_USER's process completes successfully.
-- (If you have not added space to a tablespace before, ask
your instructor for assistance.)

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 20

connect dave/dave@class2
select u1.username, r1.name, status, timeout
from dba_resumable r1, dba_users u1
where u1.user_id = r1.user_id;
disc

connect system/dave@class2
alter tablespace dave add datafile size 5m;
select u1.username, r1.name, status, timeout
from dba_resumable r1, dba_users u1
where u1.user_id = r1.user_id;
disc

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 21

-- Lesson 9 Security – Triple DES Encryption Workshop

-- SkillBuilders, 2004

-- Oracle9i Differences for Developers

-- DES3 Workshop

-- 1. Execute the supplied script DES3_1.SQL. This script


prepares the environment
-- for this workshop.
@DES3_1.SQL

-- 2. Complete the code for the trigger ccn_encrypt_trig. Add


code
-- where noted to get an encryption key and to encrypt a
credit
-- card number when a record is added or updated in the
customer
-- table. The code for the ccn_encrypt_trig trigger can be
found
-- in the supplied script CCN_ENCRYPT_TRIG.SQL.

CREATE or REPLACE TRIGGER ccn_encrypt_trig


BEFORE INSERT or UPDATE of ccn on customer
FOR EACH ROW
DECLARE
v_key VARCHAR2(80);
v_seed VARCHAR2(80) :=
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'||
'abcdefghijklmnopqrstuvwxyz=-
+)(*^%$#@!";:<>?';
v_encrypted_string VARCHAR2(2048);
BEGIN
IF INSERTING THEN
dbms_obfuscation_toolkit.DES3GETKEY(which=>1,
seed_string=>v_seed,
key=>v_key);
dbms_obfuscation_toolkit.DES3ENCRYPT(input_string =>
RPAD(:NEW.ccn,16,' '),
key_string => v_key, encrypted_string => v_encrypted_string
);
:NEW.ccn := v_encrypted_string;
INSERT INTO cust_no_Key_table
VALUES (:NEW.cust_no, v_key);
END IF;

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 22

IF UPDATING THEN
dbms_obfuscation_toolkit.DES3GETKEY(which=>1,
seed_string=>v_seed,
key=>v_key);

dbms_obfuscation_toolkit.DES3ENCRYPT(input_string =>
RPAD(:NEW.ccn,16,' '),
key_string => v_key, encrypted_string => v_encrypted_string
);
:NEW.ccn := v_encrypted_string;

UPDATE cust_no_Key_table
SET key_value = v_key
WHERE cust_no = :OLD.cust_no;

END IF;
END;
/

-- 3. Execute the supplied script INSERT_UPDATE_CUSTOMER.SQL to


add a couple
-- of new customer records to the customer table and to update
1 record
-- of the customer table.
@INSERT_UPDATE_CUSTOMER.SQL

-- 4. Query the customer and cust_no_key_table tables to verify


that records
-- were added and updated.

SELECT cust_no, ccn FROM CUSTOMER;

SELECT * FROM cust_no_key_table;

-- 5. Execute the supplied script CCN_DECRYPT.SQL to create a


function that will
-- decrypt the credit card values that are stored in the
customer table.
@CCN_DECRYPT.SQL

-- 6. Test the decryption function ccn_decrypt by executing the


supplied
-- query SELECT_CCN.SQL to display the decrypted ccns for all
customers
-- that have ccns.
@SELECT_CCN.SQL

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 23

-- Lesson 10 Indexes – Workshops

1. Bitmap Join
-- SkillBuilders, 2004
-- Lesson 10 - Bitmap Join Index Solution

-- 1. Create a bitmap join index called cust_ord_bjix on


-- the ord table. The key of this index should be the
-- city column in the customer table.
CREATE BITMAP INDEX cust_ord_bjix
ON ord (c.city)
FROM ord o, customer c
WHERE c.cust_no = o.cust_no;

-- 2. Query the USER_INDEXES, USER_IND_COLUMNS, and the


-- USER_JOIN_IND_COLUMNS views to display information
-- related to the bitmap index that you created in question 1.
-- create or replace type sqlMONTH_TABLEtype as table of date;
SELECT table_name, index_name, join_index
FROM user_indexes
WHERE index_name = 'CUST_ORD_BJIX';

SELECT table_name, index_name, column_name


FROM dba_ind_columns
WHERE index_name = 'CUST_ORD_BJIX';

SELECT * FROM dba_join_ind_columns


WHERE index_name = 'CUST_ORD_BJIX';

2. Skip Scan
-- SkillBuilders, 2004
-- Lesson 10 - Index Skip Scan Solution

-- 1. Execute the following SQL*Plus command to turn the


AUTOTRACE feature on.
SET AUTOTRACE ON;

-- This feature will display explain plan and other statistical


results after
-- each SQL statement is executed.

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 24

-- 2. Create a non-unique, composite, b-tree index on the region


and division
-- columns of the employee table.
CREATE INDEX ix1 ON employee (region, division);

-- 3. Execute the following query:


SELECT lastname FROM employee WHERE division = 10;

-- What path did the optimizer choose?

-- Execution Plan
-- --------------------------------------------------------------
--------
-- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1
Bytes=9)
-- 1 0 TABLE ACCESS (FULL) OF 'EMPLOYEE' (Cost=2 Card=1
Bytes=9)

-- 4. Execute the following query:


SELECT lastname FROM employee WHERE division = 10 AND region =
100;

-- What path did the optimizer choose?


-- Execution Plan
-- ----------------------------------------------------------
-- 0 SELECT STATEMENT Optimizer=CHOOSE
-- 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMPLOYEE'
-- 2 1 INDEX (RANGE SCAN) OF 'IX1' (NON-UNIQUE)

-- 5. Execute the following statement:


exec dbms_stats.gather_table_stats(ownname=> 'DAVE', tabname=>
'EMPLOYEE', cascade=>TRUE , -
method_opt=>'FOR ALL INDEXED COLUMNS');

-- This statement computes and stores statistics for the employee


-- table and its indexes that can be used by the optimizer when
it
-- is choosing an access path.

-- 6. Redo question 3. Did the optimizer choose the same path as


it
-- did in question 3?
SELECT lastname FROM employee WHERE division = 10;

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 25

-- No. A different plan was chosen.


-- Execution Plan

-- --------------------------------------------------------------
----------
-- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1
Bytes=9)
-- 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMPLOYEE'
(Cost=2 Card=1
-- Bytes=9)
--
-- 2 1 INDEX (SKIP SCAN) OF 'IX1' (NON-UNIQUE) (Cost=1
Card=1)

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 26

-- Lesson 11 Indexes – Workshops

1. V$SQL_PLAN
see supplid v$sql_plan_query.SQL

2. DBMS_STATS
-- SkillBuilders, 2004
-- DBMS_STATS Workshop

-- 1. Run the following command to delete all table and


-- index statistics in your schema:
EXECUTE DBMS_STATS.DELETE_SCHEMA_STATS ('DAVE');

-- 2. Run the following command:


EXECUTE DBMS_STATS.GATHER_SCHEMA_STATS ('DAVE');

-- 3. Did the command in question 2 create index statistics?


-- Run this command to found out:
SELECT index_name
FROM user_indexes
WHERE last_analyzed IS NULL;

-- No, many rows were returned revealing that index stats where
not collected.

-- 4. Run DBMS_STATS.GATHER_SCHEMA_STATS to collect stats for all


of your
-- tables and indexes. Limit histograms to just the indexed
columns.
-- Hint: Use the CASCADE=>TRUE and METHOD_OPT=> parameters as
shown
-- in the example in this chapter.

exec dbms_stats.gather_schema_stats(ownname=> USER, -


cascade=>TRUE , method_opt=>'FOR ALL INDEXED COLUMNS')

5. Verify the creation of the statistics by running the following


queries:

SELECT table_name
FROM user_tables
WHERE last_analyzed IS NULL;

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 27

SELECT index_name
FROM user_indexes
WHERE last_analyzed IS NULL;

-- There are a few LOB indexes w/o statistics, but this is


normal.
-- All objects have current statistics.

3. Dynamic Sampling
-- SkillBuilders, 2004

-- Lesson 11 - Dynamic Sampling Solution

-- 1. Execute the following provided script:


@dynamic_sampling_prep.sql

-- 2. Execute the following query with and without a dynamic


-- sampling hint. Note the differences in the execution plans.

select /*+ DYNAMIC_SAMPLING (t1 10) */


t2.object_name, t2.object_application, t1.created
from t1, t2
where t1.object_id = t2.object_id;

-- Execution Plan
-- --------------------------------------------------------------
----------
-- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=603
Card=11239 Bytes
-- =674340)
--
-- 1 0 MERGE JOIN (Cost=603 Card=11239 Bytes=674340)
-- 2 1 SORT (JOIN) (Cost=201 Card=11239 Bytes=427082)
-- 3 2 TABLE ACCESS (FULL) OF 'T2' (Cost=44
Card=11239 Bytes=
-- 427082)
--
-- 4 1 SORT (JOIN) (Cost=403 Card=29424 Bytes=647328)
-- 5 4 TABLE ACCESS (FULL) OF 'T1' (Cost=127
Card=29424 Bytes
-- =647328)

select

t2.object_name, t2.object_application, t1.created

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 28

from t1, t2
where t1.object_id = t2.object_id;

-- Execution Plan
-- --------------------------------------------------------
-- 0 SELECT STATEMENT Optimizer=CHOOSE
-- 1 0 MERGE JOIN
-- 2 1 SORT (JOIN)
-- 3 2 TABLE ACCESS (FULL) OF 'T2'
-- 4 1 SORT (JOIN)
-- 5 4 TABLE ACCESS (FULL) OF 'T1'

-- 3. Execute the following provided script:


@dynamic_sampling_reset.sql

4. Bind Variable Peeking


-- SkillBuidlers, 2004

-- 1. Run the supplied script PEEK.SQL.


-- This script demonstrates the effect of bind variable peeking.
@peek

-- 2. Analyze the two execution plans displayed:


-- ID OPERATION OPTIONS OBJECT_NAME
COST
--- -- -------------------- -------------------- ----------------
-------------- -----
-- 0 SELECT STATEMENT
2
-- 1 TABLE ACCESS BY INDEX ROWID T
2
-- 2 INDEX RANGE SCAN T_LASTNAME
1

-- ID OPERATION OPTIONS OBJECT_NAME


COST
-- --- -------------------- -------------------- ----------------
-------------- -----
-- 0 SELECT STATEMENT
13
-- 1 TABLE ACCESS FULL T
13

-- 3. Why are they different?


-- A. The first query bind variable value was very selective.
The second query was not.

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 29

-- 4. If this represents the possible values used in the query’s


bind variable,
-- is it best to use bind variables or literals in this case?
-- A. Literals.

4. Table Compression
-- SkillBuilders, 2004

-- Table Compression Solution

-- 1. Run the supplied script TABLE_COMPRESSION_PREP.SQL. This


script creates 2 tables,
-- T1 and T2. Both tables are identical except that T2 was
created with the COMPRESS option.

@TABLE_COMPRESSION_PREP.SQL

-- 2. Query the data dictionary to view the difference in space


used between tables T1 and T2.

SELECT bytes, blocks FROM user_segments


WHERE segment_name = 'T1';

-- BYTES BLOCKS
-- ---------- ----------
-- 4194304 1024

SELECT bytes, blocks FROM user_segments


WHERE segment_name = 'T2';

-- BYTES BLOCKS
-- ---------- ----------
-- 2097152 512

-- 3. Execute the following SQL*Plus command to turn on automatic


tracing.
SET AUTOTRACE TRACEONLY;

-- 4. Execute the following queries and note the differences in


I/O counts for the two queries.

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 30

SELECT object_name FROM t1


WHERE owner = 'DAVE';

-- Statistics
-- ----------------------------------------------------------
-- 0 recursive calls
-- 0 db block gets
-- 831 consistent gets
-- 818 physical reads
-- 0 redo size
-- 1451 bytes sent via SQL*Net to client
-- 532 bytes received via SQL*Net from client
-- 5 SQL*Net roundtrips to/from client
-- 0 sorts (memory)
-- 0 sorts (disk)
-- 48 rows processed

SELECT object_name FROM t2


WHERE owner = 'DAVE';

-- Statistics
-- ----------------------------------------------------------
-- 0 recursive calls
-- 0 db block gets
-- 434 consistent gets
-- 426 physical reads
-- 0 redo size
-- 1451 bytes sent via SQL*Net to client
-- 532 bytes received via SQL*Net from client
-- 5 SQL*Net roundtrips to/from client
-- 0 sorts (memory)
-- 0 sorts (disk)
-- 48 rows processed

-- 5. Execute the supplied script TABLE_COMPRESSION_RESET.SQL.

--@TABLE_COMPRESSION_RESET;

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 31

-- Appendix A Analytic Functions – Workshop


-- SkillBuilders

-- Workshop - Analytic Functions Workshop (source: Advanced SQL


Queries, v1.1)

-- 1. Display order_no, order_date, total_order_price and


cumulative total_order_price
-- for all orders.

select order_no, order_Date, total_order_price,


sum(total_order_price) over (order by order_no) cume_top
from ord
order by order_no
/

-- 2. Display order_no, truncated order_date, total_order_price


and
-- a cumulative total_order_price for all orders. Partition
by the
-- truncated order_date (to remove all time elements). Do not
-- use an analytic order by. What is the result of the
anaytic function?

select order_no, trunc(order_Date), total_order_price,


sum(total_order_price) over (partition by trunc(order_date)
) cume_top
from ord
order by order_date
/

-- 3. Add an analytic order by clause to the previous query.


select order_no, trunc(order_Date), total_order_price,
sum(total_order_price) over (partition by trunc(order_date)
order by order_no ) cume_top
from ord
order by order_date
/

-- 4. Display order_no, cust_no, total_order_price, cumulative


total_order_price

© 2004 SkillBuilders, Inc. V1.3


Oracle9i Differences for Developers: Solutions to Workshops 32

-- and cumulative by customer. The report should look


something like this:

select order_no, cust_no, total_order_price,


sum(total_order_price) over (partition by cust_no order by
order_no) cust_total,
sum(total_order_price) over (order by cust_no, order_no)
cume_total
from ord
order by cust_no
/

-- 5. Is our average total_order_price increasing or decreasing?


-- Show order_no, order_date, total_order_price and average
total_order_price
-- for the 12-month period starting 6 months before the current
order and ending
-- 6 months after the current order.

select order_no, order_date, total_order_price,


avg(total_order_price) over ( order by order_date
range between interval '6' month
preceding
and interval '6' month following )
AS annual_avg
from ord
order by order_Date
/

© 2004 SkillBuilders, Inc. V1.3

You might also like