Vous êtes sur la page 1sur 1304

OracleBlog: February 2006

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I think
data, I think Oracle. I also enjoy writing, so I use this format to organise my thoughts. Please
feel free to discuss any thoughts you may have on the same topics, even old ones (I will see and
respond to such comments). You may want to start with "LIST ALL ARTICLES" under Archives.

Friday, February 24, 2006


About Me
The Oracle Effect Name: Robert
You thought the Tom Kyte Effect was the most Vollman
powerful force in the Oracle Blogging Universe. But Location: Calgary,
we were all mistaken! For today, I got a much higher Alberta, Canada
spike than ever. The source? Oracle itself!
I was born and raised in Ottawa,
and have lived in Calgary since
1991. I like playing sports
(hockey, soccer, ultimate,
basketball, you name it) and
military board games. I also
I am especially grateful that Gary Myers caught my enjoy reading, walking, and
sloppy error before a bunch of people read it. My playing with my 2 cats Lilly and
only regret is that I didn't really have anything Brutus. I'm a database
particular intelligent to say, and even if I did, it was application specialist, whatever
said so much better by (among other people) that is.
Howard Rogers.
View my complete profile
Since the link will change soon, here is a JPG to
mark my 15 minutes of nerd fame.
Best Links
● Ask Tom Kyte
● Oracle Docs
● Dan Morgan and PSOUG
● Steven Feuerstein
● Jonathan Lewis
● FAQ
● Connor McDonald

http://thinkoracle.blogspot.com/2006_02_01_archive.html (1 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

The Oak Table


● Cary Millsap and Hotsos


● Steve Adams and Ixora
● Anjo Kolk and OraPerf
● Dizwell Oracle Wiki
● My Personal Blog

Aggregators
Brian Duff's OraBlogs

❍ Eddie Awad's OracleNA


❍ Pete Finnigan's Aggregator
❍ Oracle's Bloglist
// posted by Robert Vollman @ Friday, February 24, 2006 3 ❍ Oracle Base Aggregator

comments Top Blogs


❍ Oracle's Ask Tom Kyte
❍ Oracle Guru Jonathan Lewis
Wednesday, February 22, 2006
Blogger of the Year Eddie Awad
Never noticed this before

Data Warehouser David Aldridge


So I was searching through the latest Oracle 10g

Oracle Geek Lewis Cunningham


SQL Reference,

❍ Database Expert James Koopmann


check out what I found on page 5-175: ❍ Dizwell's Howard Rogers
SELECT manager_id, last_name, salary, SUM(salary) ❍ Oracle Master Laurent Schneider
OVER (PARTITION BY manager_id ORDER BY salary ❍ Security Expert Pete Finnigan
RANGE UNBOUNDED PRECEDING) l_csum ❍ Oracle Award Winner Mark
FROM employees; Rittman
❍ Doug Burns
MANAGER_ID LAST_NAME SALARY L_CSUM ❍ Oracle ACE of the Year Dr. Tim
---------- --------- ------ ------ Hall
100 Mourgos 5800 5800 ❍ UKOUG's Andrew (Arfur C.) Clarke
100 Vollman 6500 12300 ❍ Newbie DBA Lisa Dobson
...
❍ Coffee-Drinking DBA Jon Emmons
I'm in the Oracle default HR schema! I'm employee ❍ Chris Foot
123 and I report directly to KING, the President! Of ❍ The Pythian DBA Team Blog
course, I'm one of the lowest paid managers, but ❍ DBA Don Seiler
still. ❍ DBA Coskan Gundogar
❍ Oracle WTF
Of course, the first name is Shonta. But I can dream,
right? I can pretend that I'm one of Lex de Haan's
fictional colleagues, right?
ARCHIVES
❍ LIST ALL ARTICLES
I also saw this in the latest version of Oracle 9i ❍ May 2005

http://thinkoracle.blogspot.com/2006_02_01_archive.html (2 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

documentation: ❍ June 2005


SQL Reference: ❍ July 2005
Page 365, 6-155 for the example of SUM. ❍ August 2005
Page 1532, 18-42 on using LEVEL Pseudo-Column. ❍ September 2005
❍ October 2005
and Sample Schemas: ❍ November 2005
Page 68, section 4-28 on Oracle's sample HR ❍ December 2005
Schema ❍ January 2006
So it must have been around for awhile. I think ❍ February 2006
that's so cool! I'm going to write Oracle and ask ❍ March 2006
them to fix my first name. I urge you to do the ❍ April 2006
same in your implementations: ❍ May 2006
❍ June 2006
UPDATE employees SET first_name = 'Robert' where ❍ July 2006
last_name = 'Vollman'; ❍ August 2006
❍ September 2006
// posted by Robert Vollman @ Wednesday, February 22, 2006 1
❍ October 2006
comments ❍ November 2006
❍ December 2006
❍ January 2007
Oracle Sequences ❍ February 2007
Proactively maintaining your database ... something ❍ March 2007
some people do only AFTER a problem of some kind. ❍ April 2007
❍ May 2007
Case in point, a customer recently asked us what
June 2007
sequences are being used as primary keys, what are

October 2007
their maximum values, and are any in danger of

running out. Guess what motivated that


Current Posts
investigation?

Most of this is rather trivial using only the


ALL_SEQUENCES table.

1. What sequences are being used, and do they roll


over or run out?

SELECT cycle_flag, sequence_name FROM


ALL_SEQUENCES;

2. Which sequences are being used as primary keys?

That's trickier. See, even if you're using a sequence


as a primary key, there's no way to tell by just
looking at a table somewhere. The INSERT
commands could be calling that sequence directly.
Edit Or, it could be inserted by a trigger. I'm not

http://thinkoracle.blogspot.com/2006_02_01_archive.html (3 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

aware of any easy, reliable way to determine if


sequences are being used as primary keys without
looking table by table.

However, generally that is what people like to use


sequences for, so there's a good chance that all the
sequences are being used as keys somewhere.

3. Which sequences are in danger of running out?

SELECT sequence_name, (max_value - last_number)/


increment_by sequences_left
FROM ALL_SEQUENCES
ORDER BY sequences_left;

4. What happens when a sequence runs out?

Well that depends if its a roll-over or not.

CREATE SEQUENCE rollover_seq MINVALUE 1 START


WITH 1 INCREMENT BY 1 MAXVALUE 3 CYCLE
NOCACHE;
CREATE SEQUENCE runout_seq MINVALUE 1 START
WITH 1 INCREMENT BY 1 MAXVALUE 3 NOCYCLE
NOCACHE;

CREATE TABLE sequence_table (roll NUMBER(1),


runout NUMBER(1));

Run this three times:


INSERT INTO sequence_table (roll, runout) VALUES
(rollover_seq.NEXTVAL, runout_seq.NEXTVAL);

On the fourth time:


ORA-08004: sequence RUNOUT_SEQ.NEXTVAL
exceeds MAXVALUE and cannot be instantiated

But the other one rolls over:


INSERT INTO sequence_table (roll, runout) VALUES
(rollover_seq.NEXTVAL, 4);

scott@Robert> SELECT * FROM sequence_table;


ROLL RUNOUT
---------- ----------
1 1
2 2
3 3
2 4

http://thinkoracle.blogspot.com/2006_02_01_archive.html (4 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

Why is it 2,4 instead of 1,4? Well we "used up" the 1


on the misfire, so now we have a "gap." Every time
NEXTVAL is "called", the sequence increments.
CURRVAL doesn't. Of course, CURRVAL gives you
last_number, which is one that's presumably already
in use.

By the way, as usual, you can get some better


examples, and a better reference, from Dan
Morgan's library.

Those looking for an equivalent to AUTONUMBER in


other RDBMS may find that using an Oracle
sequence is close to the same functionality. Edit Just
use the sequence's NEXTVAL as your insert for your
key, or in a trigger, like so:

-- Won't work:
CREATE TABLE MyTable (seq_id NUMBER(1) DEFAULT
rollover_seq.NEXTVAL);
ORA-00984: column not allowed here

-- Will work:
CREATE TABLE MyTable (seq_id NUMBER(1));

CREATE OR REPLACE TRIGGER trig_seq BEFORE


INSERT ON MyTable
FOR EACH ROW
BEGIN
SELECT rollover_seq.NEXTVAL into :new.seq_id
FROM dual;
END;

To prevent this post from getting longer than it


needs to be, I'll just send you to AskTom to read a
discussion about the performance of using Oracle
sequences as primary keys.

One final word, about the NOCACHE command I


used up there. The default CACHE value is 20, so I
had to use NOCACHE because it would try to CACHE
more values than the sequence had. CACHE actually
CACHEs the next few values for quicker access. But
if ever there is a system failure, those previously-
retrieved sequence numbers are gone. You'll be left

http://thinkoracle.blogspot.com/2006_02_01_archive.html (5 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

with a "gap."

Of course, gaps may not be the end of the world for


you. If they are, you'll need to use ALTER SEQUENCE
to fix them. I've already mentioned two ways to get
gaps with sequences, here's one more. If you do a
transaction with NEXTVAL and then rollback, the
sequence doesn't roll back to where you started.
That'll create a gap, too.

// posted by Robert Vollman @ Wednesday, February 22,

2006 17 comments

Tuesday, February 21, 2006


Oracle Interview Questions
"We're interviewing an Oracle guy tomorrow, can
you give me a few questions to ask him?"

Not an uncommon request. The problem is, there


are literally thousands of potential Oracle questions,
but it all depends on what are you trying to achieve.
So I pushed back:

"What kind of Oracle-related skills would the


candidate need that you want to ask for?"
"You tell us. We just want to know if he knows
Oracle. Whatever an Oracle guy would need to
know."

Pretty soon thereafter I figured out that it was a


pointless conversation to continue, although I did
love the way he summarized dozens of very
different positions into that one term: "Oracle Guy."

Nevertheless, it got me thinking. What makes for a


good technical question? I have conducted, or been
invited to, several interviews, so it got me to
thinking about which questions were most effective
at getting to the heart of the matter: "Will this
candidate succeed technically in this role?"

Elements of a Good Technical Interview Question.

1. Must require knowledge of the area, including


domain and philosophy, to solve.

http://thinkoracle.blogspot.com/2006_02_01_archive.html (6 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

I don't think it's enough that a candidate


demonstrates proficiency with the technology. I like
to see if they understand the overall philosophy of
the product (Oracle, in this case): What needs was it
meant to provide, what kind of problems was it
designed to solve, how does it accomplish those
tasks.

2. Must require overall technical skill/experience/


understanding to solve.

I mean to say that a good question shows if the


candidate understands (for example) relational
databases themselves, not just a particular
relational database. Carrying this example, does
your C++ developer understand algorithms and
software design?

3. Does not require knowledge of precise syntax

In my mind, anyone can look something up in a


manual. You don't need to walk into an empty
boardroom and know exactly how something is
called. I don't think knowledge of syntax is a
reliable indicator of the suitability of a candidate.

For example, you could have a good candidate


"blank out" on the syntactic details, and you could
also have a bad candidate who swallowed a
reference manual the night before the interview.

Now, I would be worried if the candidate didn't


know BASIC syntax. But I don't want to waste
precious time asking basic questions, and if he is
truly is that inexperienced, I should be able to
figure it out in other ways.

4. Can be answered quickly.

Time is precious in an interview, and you shouldn't


need long, convoluted questions to determine
whether or not a candidate "gets it." A good
question demonstrates quickly if the candidate is on
the right path, or wouldn't get it regardless of how
much time he had.

5. Is not a "gotcha"

http://thinkoracle.blogspot.com/2006_02_01_archive.html (7 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

I've met some interviewers that seem to use the


opportunity not to evaluate the candidate, but to
prove how clever they are (either to the candidate or
the manager). They do this by asking really obscure
tricks, sometimes referred to as "gotchas."

The problem with asking questions in the obscure


corners is that even very experienced candidates
may not have worked in that area and, if they have,
may not have stumbled across that particular gem.

Just remember, the purpose of the interview isn't to


make YOU look clever, and asking silly questions
might make a great candidate think "what kind of
clown show am I getting myself into?"

6. Has many possible solutions and approaches

The most effective questions I have ever asked, or


been asked, were the ones that triggered lively
technical discussions between the interviewer and
the candidate. Why? You get to catch a glimpse not
only of the candidates thinking process, but also
how he communicates. I also like the added benefit
of not punishing (in fact, rewarding) those that
approach problems differently than the interviewer.

7. Requires asking for more information (or make


assumptions).

Personally, I believe one of the keys to success in IT


is to define a problem before approaching it. That's
why I lean towards these types of questions. Did the
candidate come back, or just try to solve it? If he
came back, what kind of questions did he ask? In
the face of an incompletely-defined problem, did he
get stuck, or did he make some assumptions and
continue? If so, what assumptions did he make?

8. Is relevant to the business/job being considered

Would you hire a cleaning service with award-


winning carpet cleaning if you had hardwood floors?
Would you hire a running back who excels in bad
weather if you played in a dome? Would you hire an
accomplished science-fiction writer to author your
biography? No? Then why probe for technical skills
that don't directly apply to the position you're

http://thinkoracle.blogspot.com/2006_02_01_archive.html (8 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

attempting to fill?

Closing Thoughts

Incidentally, in the end I referred the manager in


question to a couple of links which have hundreds
of Oracle-interview questions. You can pick your
favourites but, more likely, you can read them until
you come up with good ideas that suit your needs.

http://www.orafaq.com/forum/t/9760/2/
http://www.databasejournal.com/features/oracle/
article.php/3085171

As an aside, that last article was written by one of


my preferred columnists, James Koopmann. He
hasn't written much recently, but check out his
archives, he's got some great articles there. For
instance, check out his series on Oracle Session
Tracing.

// posted by Robert Vollman @ Tuesday, February 21, 2006 3

comments

Tuesday, February 14, 2006


BPEL
BPEL (Business Process Execution Language) is an
xml-based language for use with the Service-
Oriented Architecture (SOA) to software
development.

Simply put, BPEL is an XML-based standard used to


define business processes, generally by
demonstrating how relevant Web Services connect
and communicate. You would use BPEL to layout the
general business flow and how the Web Services are
used. In the end, you have a particularly-formatted
XML file running on a BPEL Server.

To do this, Oracle provides the BPEL Process


Manager. This is a BPEL IDE that will generate your
BPEL XML file, and then run it on a BPEL Engine
running on top of the Oracle Application Server.
There are lots of other engines out there, BPEL and

http://thinkoracle.blogspot.com/2006_02_01_archive.html (9 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

SOA is by no means unique to Oracle. In fact, here


is an Open Source BPEL Server, ActiveBPEL.

BPEL has its roots in IBM and Microsoft's WSFL and


XLANG. It was originally called BPEL4WS (BPEL for
Web Services), but was renamed WS-BPEL. BPEL was
meant to replace WSCI ("Whiskey"), which Oracle put
forward with Sun and SAP a few years ago for the
same purpose (designing the coordination of Web
Services). And if that is not enough acronyms for
you, I'll just note that BPEL uses WSDL to determine
the format of the messages to be sent among the
various Web Services.

For those wanting a quick hands-on "taste" of BPEL,


here is what I did.

1. Start BPEL Server


2. Start the BPEL Designer, which is part of
JDeveloper
3. Connected to the BPEL Console through a web
browser
4. Create a new "BPEL Process Project" in JDeveloper
5. Made a few minor changes to the default project
6. Toggled to Source and saw my changes in the
XML
7. Validated the changes using the "BPEL Validation
Browser."
8. Generated a nice JPG of my BPEL business process

9. Deployed the project to the default BPEL Server I

http://thinkoracle.blogspot.com/2006_02_01_archive.html (10 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

had started
10. Found the deployed service in the BPEL Console
11. From the BPEL Console, entered a parameter
and initiated my BPEL process
12. Still from the BPEL Console, audited the flow
and examined the XML messages that went back
and forth

Thus concludes my introductory post on BPEL. Next


I'm going to find some Web Services out there and
build a more significant business process. When I
do, I'll be sure to post an article with my JPG and
what I thought of some of the bells and whistles.

// posted by Robert Vollman @ Tuesday, February 14, 2006 1

comments

Tuesday, February 07, 2006


TRANSLATE
TRANSLATE is a useful little function that can
replace given characters in the first string with
other given characters. TRANSLATE will go through
the provided string looking for any instance of
characters in the first list and, when found, replace
them with the corresponding character in the
second list. Any characters in the given string that
don't show up in the first list are left alone.

If the first list is longer than the second list, that


means that some characters have no corresponding
character. In that case, such characters are simply
replaced with nothing (ie. deleted). So if you want to
remove a character, put them at the end of your
first list. It clearly doesn't make sense for the
second list to be longer than the first list, nor does
it make sense to have duplicates in the first list
(although it certainly makes sense in the second
list). If you do have inconsistent duplicates in your
first list, Oracle seems to choose the character in
the second list corresponding to its first occurence
in the first list.

By the way, the two lists are actually passed as


strings, but it makes more sense to picture them as
lists. C programmers will be most comfortable,

http://thinkoracle.blogspot.com/2006_02_01_archive.html (11 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

because they are used to interpreting strings as


arrays of characters, and that's what we're dealing
with here.

TRANSLATE is under chapter 6 (Functions) of


Oracle's SQL Reference.

Let's look at a first, simple example to remove the


dashes in a phone number and replace them with
dots to form some kind of standard syntax.

scott@Robert> SELECT TRANSLATE


('(619)455-1998', ')-(', '..') PHONE_NO
FROM DUAL;

PHONE_NO
------------
619.455.1998

Complex constraints are a particularly good use for


TRANSLATE. Let's presume you have a column that
represents a special code in your company where
the 4th character must be a digit, and the first digit.
Well, you may know that INSTR can tell you where
the first occurence of a particular character is, but
you're looking for 10 characters, how can that be
done? Quite easily, because with TRANSLATE you
can change all characters to a single one.

CREATE TABLE MyTable (special_code


VARCHAR2(32) CHECK (INSTR
(TRANSLATE(special_code, '123456789',
'000000000'), '0') = 4));

scott@Robert> INSERT INTO MyTable


(special_code) VALUES ('abc123');

1 row created.

scott@Robert> INSERT INTO MyTable


(special_code) VALUES ('abcd1234');
INSERT INTO MyTable (special_code)
VALUES ('abcd1234')
*
ERROR at line 1:

http://thinkoracle.blogspot.com/2006_02_01_archive.html (12 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

ORA-02290: check constraint (SCOTT.


SYS_C008454) violated

That is an excellent technique of how TRANSLATE


can be applied to a problem. As a side note, we can
use RPAD to generate that second list for us if it is
very long.

CREATE TABLE MyTable (special_code


VARCHAR2(32) CHECK (INSTR
(TRANSLATE(special_code, '123456789',
RPAD('0', 9, '0')), '0') = 4));

Let's say you have a special column that should


ONLY have numbers. How can you do that? Well
how about you delete them all, and then see if you
have an empty string? That would look something
like this:

CREATE TABLE MyTable (numeric_only


VARCHAR2(32) CHECK (TRANSLATE
(numeric_only, '0123456789', '') IS
NULL));

scott@Robert> INSERT INTO MyTable


(numeric_only) VALUES ('abc123');

1 row created.

Oops? What happened? I'll show you this little


feature of TRANSLATE:

scott@Robert> SELECT TRANSLATE


('abc123', '0123456789', '') FROM DUAL;

T
-

The truth is, if the second list is empty, it seems to

http://thinkoracle.blogspot.com/2006_02_01_archive.html (13 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

wipe out the entire string. Fortunately there is a


pretty easy way around this. Just make sure the
second string isn't empty. Map some non-important
character to the same character, like so:

scott@Robert> SELECT TRANSLATE


('abc123', '$0123456789', '$') FROM
DUAL;

TRA
---
abc

Let's try this new constraint:

CREATE TABLE MyTable (numeric_only


VARCHAR2(32) CHECK (TRANSLATE
(numeric_only, '$0123456789', '$') IS
NULL));

scott@Robert> INSERT INTO MyTable


(numeric_only) VALUES ('1234');

1 row created.

scott@Robert> INSERT INTO MyTable


(numeric_only) VALUES ('abc123');
INSERT INTO MyTable (numeric_only)
VALUES ('abc123')
*
ERROR at line 1:
ORA-02290: check constraint (SCOTT.
SYS_C008456) violated

Much better! You know, if we wanted to allow some


non-numeric characters, but no more than 2, we
could use LENGTH to do that.

CREATE TABLE MyTable (max_2


VARCHAR2(32) CHECK (LENGTH
(TRANSLATE(max_2, '$0123456789',
'$')) <= 2));

http://thinkoracle.blogspot.com/2006_02_01_archive.html (14 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

scott@Robert> INSERT INTO MyTable


(max_2) VALUES ('abc123');
INSERT INTO MyTable (max_2) VALUES
('abc123')
*
ERROR at line 1:
ORA-02290: check constraint (SCOTT.
SYS_C008459) violated

scott@Robert> INSERT INTO MyTable


(max_2) VALUES ('ab123');

1 row created.

As a quick aside, you'll notice that I specify my


column names when I'm doing an insert. Why, you
may ask, do I do that? Well don't you think what I'm
doing is clearer to you, the reader, when I specify
which values I'm inserting? Furthermore, if the
schema of a table changes, my INSERT command
will still work, assuming the schema change doesn't
affect the columns I'm using, and that there are no
new parameters that require a value.

You can do so much with TRANSLATE when


combined with other functions, such as (to name
just a few):

INSTR: gets the position of the first matching


character
TRIM: take away spaces, or specific, single
characters (also see LTRIM, RTRIM)
UPPER: converts all characters to upper case (also
see LOWER)
RPAD: creates a string of the same character (also
see LPAD)
LENGTH: calculates the length of a string

Despite the simplicity of the function, it comes in


useful in complex constraints and transformations,
both by itself and in concert with other Oracle
functions.

As a final note, for those of you needing something


other than the 1-to-1 switch that TRANSLATE
allows, and instead needing to replace one

http://thinkoracle.blogspot.com/2006_02_01_archive.html (15 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

substring with another, you want to use REPLACE.


Doubtlessly that will be the topic of a later post.

Dan Morgan's Reference on TRANSLATE:


http://www.psoug.org/reference/translate_replace.
html

// posted by Robert Vollman @ Tuesday, February 07, 2006 5

comments

Thursday, February 02, 2006


Oracle and SOA
I went to a seminar yesterday in downtown Calgary
where Oracle was unveiling its SOA Solution to all
the big Canadian oil and gas giants. SOA is the
latest buzz-acronym for "Service-Oriented
Architecture."

What is SOA?

SOA is not a technology or something you install. It


is a concept, or rather an approach to modelling
your system, and one that is different from the
standard client/server model you may be used to.
As opposed to large, proprietary applications that
do everything, SOA is a design meant to try to
integrate numerous and diverse software
applications with common interfaces, in the name
of code reuse/maintainability, and adaptibility. The
notion of using a group of independent applications
to accomplish a shared task is also sometimes
referred to as grid computing.

Everyone knows that "Web Services" are one of the


hottest things lately. An SOA is essentially a
collection of such services, communicating with one
another, generally through XML. (Of course I am
over-simplifying things: SOA can involve any kind
of self-contained service communicating in any
way.)

SOA is not specific to any technology, indeed every


"family" of technologies has its own SOA solution,
and usually you can mix-and-match your own.
However, open-source XML-based technologies

http://thinkoracle.blogspot.com/2006_02_01_archive.html (16 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

such as BPEL, SOAP and WSDL are very commonly


used.

For more information about SOA in general, visit


OASIS's web site:
OASIS Open Standard for SOA

What is Oracle's SOA Solution?

It was inevitable that Oracle would join in the fray


and devise SOA-based solutions. At the very least
as part of its "Oracle Fusion" project to integrate
PeopleSoft and JD Edwards. Notice the recent
acquisitions of Kurian, Collaxa and Oblix were all
steps along the SOA path.

Oracle's SOA solution leans heavily towards J2EE,


their preferred language in which to develop your
Web Services. They want you to use the perhaps
poorly-named JDeveloper as your IDE for
developing your Web Services with Oracle
Containers (OC4J). JDeveloper includes the toolset
Oracle Application Development Framework (ADF)
which also includes Oracle TopLink for object-
relational mapping. Of course they suggest you use
the Oracle Application Server for these Web
Services. Get more information on this from Oracle's
whitepaper:
Oracle's JDeveloper White Paper

One of the new components is the BPEL Process


Manager, acquired with Collaxa, which is an
application that includes several tools to develop
BPEL models and the underlying Web Services. This
is where you define which services are called, and
when. Grab this whitepaper for more on that:
Oracle's BPEL White Paper

For those who want more details, I am preparing a


future post on BPEL, followed by some of these
other acronyms I've mentioned. Note to Eddie: Half
the presenters pronounced it "bipple" and the other
half pronounced it "b-pull."

That summarizes my introductory post on Oracle


and SOA. I will be writing articles with more meat
and technical details over the next couple of weeks,

http://thinkoracle.blogspot.com/2006_02_01_archive.html (17 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

but for those who are intrigued and just can't wait,
here are some Oracle white papers on SOA:
Oracle E-Business and SOA
IDC: Oracle's SOA Platform

For more information about Oracle's SOA Solution,


visit their web site:
Oracle's Main SOA Site

// posted by Robert Vollman @ Thursday, February 02, 2006 3

comments

SourceForge
Have you been overlooking the wealth of handy
tools and code on SourceForge?

SourceForge.net is a web site that hosts literally


hundreds of thousands of projects. Its an excellent
source of open source development projects. You
can download software and source code and
collaborate with others on projects.

Having trouble designing your software? Search


SourceForge for similar projects and see what they
did.

Want to avoid re-inventing a wheel? Find something


suitable to your purposes at SourceForge.

Let's look at a quick example. The simplest example


I could find is a little PL/SQL script that generates a
package based on a table. I'm not promoting this
particular script, I'm just using it as an example.

You can fetch the simple example here:


http://sourceforge.net/projects/plsqlgenpkg/

Download it, and inside the zip file you'll find some
PL/SQL. Go ahead and run it: it will ask for a table
name, and a package name. It will then generate
some PL/SQL that you can use to generate a
package for your table. Easy as that.

That is pretty typical of SourceForge. Hunt around


and find some useful applications. There are PL/SQL

http://thinkoracle.blogspot.com/2006_02_01_archive.html (18 of 19)1/9/2008 2:49:06 AM


OracleBlog: February 2006

Editors and PL/SQL Plug-Ins to various IDEs (like


Eclipse). I've seen Java programs that can monitor
your database. All sorts of things.

Might be a good place to share your open source


tools, no? Especially the ones on which you're
looking for feedback.

I recommend rooting through SourceForge from


time to time if you don't already.

// posted by Robert Vollman @ Thursday, February 02, 2006 1

comments

http://thinkoracle.blogspot.com/2006_02_01_archive.html (19 of 19)1/9/2008 2:49:06 AM


OracleBlog: The Thomas Kyte Effect

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Tuesday, December 20, 2005


About Me
The Thomas Kyte Name: Robert Vollman
Effect Location: Calgary, Alberta,
Good grief! Canada

I saw a spike in my statcounter and I was born and raised in


I checked it out to see if I got Ottawa, and have lived in Calgary since
spammed. Instead I am the newest 1991. I like playing sports (hockey, soccer,
beneficiary of the "Thomas Kyte ultimate, basketball, you name it) and
Effect." military board games. I also enjoy reading,
walking, and playing with my 2 cats Lilly
Well, strictly speaking, the Thomas and Brutus. I'm a database application
Kyte Effect is when your blog is specialist, whatever that is.
referenced in a blog article of his,
but in my case I was simply added
View my complete profile
to his list of links. And then bam -
several hundred hits today.

With all due respect to Doug, Lisa


and Eddie, in one day I've got more
Best Links
● Ask Tom Kyte
referrals from his blog than Oracle Docs
everyone else put together.

● Dan Morgan and PSOUG


I told Tom we could "cash in" on the ● Steven Feuerstein
"Thomas Kyte Effect" with a few ● Jonathan Lewis
well-chosen ads, but sadly he ● FAQ
wouldn't go for it. ● Connor McDonald

http://thinkoracle.blogspot.com/2005/12/thomas-kyte-effect.html (1 of 3)1/9/2008 2:49:10 AM


OracleBlog: The Thomas Kyte Effect

The Oak Table


Well, as long as you're all here, I ● Cary Millsap and Hotsos


would like to say two things: ● Steve Adams and Ixora
1. Welcome to my blog! ● Anjo Kolk and OraPerf
2. Please look through my archives,
Dizwell Oracle Wiki
some of my more interesting reads

My Personal Blog
are in July/August.

Comments are very welcome, even


on older posts (I get auto-emailed
when someone posts something). Aggregators
Brian Duff's OraBlogs

Also, I like to provide something Eddie Awad's OracleNA
useful in every post, so here it is: a

Pete Finnigan's Aggregator


link to an article by Steven

Oracle's Bloglist
Feuerstein about how to hide your

Oracle Base Aggregator


code: ❍

http://htmldb.oracle.com/pls/otn/
f? Top Blogs
p=2853:4:6669219410898182474:: ❍ Oracle's Ask Tom Kyte
NO::P4_QA_ID:4102 ❍ Oracle Guru Jonathan Lewis
❍ Blogger of the Year Eddie Awad
// posted by Robert Vollman @ Tuesday, ❍ Data Warehouser David Aldridge
❍ Oracle Geek Lewis Cunningham
December 20, 2005 ❍ Database Expert James Koopmann
❍ Dizwell's Howard Rogers
Oracle Master Laurent Schneider
Comments: ❍

i feel that too, being listed on tom ❍ Security Expert Pete Finnigan
kyte blog generates much more ❍ Oracle Award Winner Mark Rittman
traffic than orablogs and google ❍ Doug Burns
together ;-) ❍ Oracle ACE of the Year Dr. Tim Hall
# posted by Laurent Schneider : ❍ UKOUG's Andrew (Arfur C.) Clarke
Wednesday, 21 December, 2005 ❍ Newbie DBA Lisa Dobson
❍ Coffee-Drinking DBA Jon Emmons
❍ Chris Foot
Post a Comment ❍ The Pythian DBA Team Blog
❍ DBA Don Seiler
<< Home ❍ DBA Coskan Gundogar
❍ Oracle WTF

ARCHIVES
❍ LIST ALL ARTICLES

http://thinkoracle.blogspot.com/2005/12/thomas-kyte-effect.html (2 of 3)1/9/2008 2:49:10 AM


OracleBlog: The Thomas Kyte Effect

❍ May 2005
❍ June 2005
❍ July 2005
❍ August 2005
❍ September 2005
❍ October 2005
❍ November 2005
❍ December 2005
❍ January 2006
❍ February 2006
❍ March 2006
❍ April 2006
❍ May 2006
❍ June 2006
❍ July 2006
❍ August 2006
❍ September 2006
❍ October 2006
❍ November 2006
❍ December 2006
❍ January 2007
❍ February 2007
❍ March 2007
❍ April 2007
❍ May 2007
❍ June 2007
❍ October 2007

http://thinkoracle.blogspot.com/2005/12/thomas-kyte-effect.html (3 of 3)1/9/2008 2:49:10 AM


OracleBlog: The Oracle Effect

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Friday, February 24, 2006


About Me
The Oracle Effect Name: Robert
You thought the Tom Kyte Effect was the Vollman
most powerful force in the Oracle Blogging Location: Calgary,
Universe. But we were all mistaken! For today, Alberta, Canada
I got a much higher spike than ever. The
source? Oracle itself! I was born and raised in Ottawa,
and have lived in Calgary since
1991. I like playing sports
(hockey, soccer, ultimate,
basketball, you name it) and
military board games. I also
enjoy reading, walking, and
I am especially grateful that Gary Myers playing with my 2 cats Lilly and
caught my sloppy error before a bunch of Brutus. I'm a database
people read it. My only regret is that I didn't application specialist, whatever
really have anything particular intelligent to that is.
say, and even if I did, it was said so much
better by (among other people) Howard View my complete profile
Rogers.

Since the link will change soon, here is a JPG


to mark my 15 minutes of nerd fame.
Best Links
● Ask Tom Kyte
● Oracle Docs
● Dan Morgan and PSOUG

http://thinkoracle.blogspot.com/2006/02/oracle-effect.html (1 of 3)1/9/2008 2:49:14 AM


OracleBlog: The Oracle Effect

● Steven Feuerstein
● Jonathan Lewis
● FAQ
● Connor McDonald
● The Oak Table
● Cary Millsap and Hotsos
● Steve Adams and Ixora
● Anjo Kolk and OraPerf
● Dizwell Oracle Wiki
● My Personal Blog

Aggregators
// posted by Robert Vollman @ Friday, February 24, 2006 Brian Duff's OraBlogs

❍ Eddie Awad's OracleNA


❍ Pete Finnigan's Aggregator
❍ Oracle's Bloglist
Comments: ❍ Oracle Base Aggregator
> got a much higher spike than ever
Nice to read, i'd be interested about how Top Blogs
many accesses you are talking in more ❍ Oracle's Ask Tom Kyte
concrete numbers. ❍ Oracle Guru Jonathan Lewis
Blogger of the Year Eddie Awad
BR,

Data Warehouser David Aldridge


Martin

❍ Oracle Geek Lewis Cunningham


# posted by Anonymous : Friday, 24 February, 2006
❍ Database Expert James Koopmann
❍ Dizwell's Howard Rogers
Martin, ❍ Oracle Master Laurent Schneider
❍ Security Expert Pete Finnigan
Very roughly speaking, it looks like I've gotten ❍ Oracle Award Winner Mark
about 300 unique visitors in the last 2 days Rittman
from Oracle's web site. ❍ Doug Burns
❍ Oracle ACE of the Year Dr. Tim
Robert Hall
# posted by Robert Vollman : Friday, 24 February, ❍ UKOUG's Andrew (Arfur C.) Clarke
2006 ❍ Newbie DBA Lisa Dobson
❍ Coffee-Drinking DBA Jon Emmons
Chris Foot
FYI, your link remains to be on the http://

❍ The Pythian DBA Team Blog

http://thinkoracle.blogspot.com/2006/02/oracle-effect.html (2 of 3)1/9/2008 2:49:14 AM


OracleBlog: The Oracle Effect

www.oracle.com/technology/index.html site, DBA Don Seiler


as of 2:09 P.M. EST on 20060226. ❍ DBA Coskan Gundogar


# posted by Hae-Kwang : Sunday, 26 February, 2006 ❍ Oracle WTF

ARCHIVES
❍ LIST ALL ARTICLES
Post a Comment ❍ May 2005
June 2005
<< Home

❍ July 2005
❍ August 2005
❍ September 2005
❍ October 2005
❍ November 2005
❍ December 2005
❍ January 2006
❍ February 2006
❍ March 2006
❍ April 2006
❍ May 2006
❍ June 2006
❍ July 2006
❍ August 2006
❍ September 2006
❍ October 2006
❍ November 2006
❍ December 2006
❍ January 2007
❍ February 2007
❍ March 2007
❍ April 2007
❍ May 2007
❍ June 2007
❍ October 2007

http://thinkoracle.blogspot.com/2006/02/oracle-effect.html (3 of 3)1/9/2008 2:49:14 AM


OracleBlog: Bookmark This Page

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Tuesday,
About Me
March 28, 2006
Name: Robert Vollman
Bookmark Location: Calgary, Alberta, Canada
This Page
To ease the I was born and raised in Ottawa, and have lived in
task of Calgary since 1991. I like playing sports (hockey,
browsing my soccer, ultimate, basketball, you name it) and military board games.
archives, I've I also enjoy reading, walking, and playing with my 2 cats Lilly and
put together Brutus. I'm a database application specialist, whatever that is.
an organised
list of my View my complete profile
previous posts.
Bookmark this,
because I will
keep it up to
Best Links
date. I will also ● Ask Tom Kyte
include a link ● Oracle Docs
to this post ● Dan Morgan and PSOUG
under Archives. ● Steven Feuerstein
● Jonathan Lewis
Note: If you FAQ
comment on

Connor McDonald
an older

The Oak Table


article, I will

Cary Millsap and Hotsos


get an ●

automatic ● Steve Adams and Ixora


email. So I will ● Anjo Kolk and OraPerf

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (1 of 21)1/9/2008 2:49:16 AM


OracleBlog: Bookmark This Page

see it and I will ● Dizwell Oracle Wiki


respond to it, ● My Personal Blog
so please feel
free to do so!

For Newbies: Aggregators


Tuesday, Brian Duff's OraBlogs

December 20, ❍ Eddie Awad's OracleNA


2005 ❍ Pete Finnigan's Aggregator
20 Beginner ❍ Oracle's Bloglist
Oracle ❍ Oracle Base Aggregator
Questions
Top Blogs
Friday, June ❍ Oracle's Ask Tom Kyte
17, 2005 Oracle Guru Jonathan Lewis
Asking For

❍ Blogger of the Year Eddie Awad


Help - Tips on ❍ Data Warehouser David Aldridge
where to go Oracle Geek Lewis Cunningham
and how to do

Database Expert James Koopmann


it.

❍ Dizwell's Howard Rogers


Wednesday, ❍ Oracle Master Laurent Schneider
July 19, 2006 ❍ Security Expert Pete Finnigan
Finding ❍ Oracle Award Winner Mark Rittman
Information - ❍ Doug Burns
How do you ❍ Oracle ACE of the Year Dr. Tim Hall
find answers to ❍ UKOUG's Andrew (Arfur C.) Clarke
other ❍ Newbie DBA Lisa Dobson
questions? ❍ Coffee-Drinking DBA Jon Emmons
❍ Chris Foot
Thursday, July
The Pythian DBA Team Blog
14, 2005

DBA Don Seiler


Oracle Docs -

DBA Coskan Gundogar


For when

Oracle WTF
people tell you

to RTFM!
ARCHIVES
Best Practises: ❍ LIST ALL ARTICLES
May 2005
Thursday,

June 2005
October 19,

July 2005
2006

❍ August 2005

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (2 of 21)1/9/2008 2:49:16 AM


OracleBlog: Bookmark This Page

3 Easy Ways to ❍ September 2005


Improve Your ❍ October 2005
PL/SQL - ❍ November 2005
Improving your ❍ December 2005
code through ❍ January 2006
instrumentation ❍ February 2006
and bulk ❍ March 2006
processing. ❍ April 2006
May 2006
Friday, March

09, 2007 ❍ June 2006


40 Tips From ❍ July 2006
Tom (Kyte) ❍ August 2006
❍ September 2006
Tuesday, June ❍ October 2006
14, 2005 ❍ November 2006
Bind Variables ❍ December 2006
in PL/SQL - ❍ January 2007
Short answer: ❍ February 2007
PL/SQL binds ❍ March 2007
all variables ❍ April 2007
(with some ❍ May 2007
exceptions like ❍ June 2007
dynamic SQL) ❍ October 2007
Tuesday,
January 24,
2006
Gathering
Requirements

Wednesday,
March 01, 2006
Handling
exceptions - A
how-to guide.

Friday, March
10, 2006
Handling
Performance
Issues

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (3 of 21)1/9/2008 2:49:16 AM


OracleBlog: Bookmark This Page

Wednesday,
August 17,
2005
Keeping Tables
Small - In
terms of
number of
rows, not
columns.
Improve
performance.

Monday,
October 31,
2005
Oracle
Packages -
And why/how
you should use
them.

Monday, July
11, 2005
Specifying
INSERT
Columns - Why
it's a good
habit.

Wednesday,
May 18, 2005
Steven
Feuerstein on
Refactoring

Tuesday, July
26, 2005
Use
Constraints - A
how-to guide
for people to
whom I BEG to

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (4 of 21)1/9/2008 2:49:16 AM


OracleBlog: Bookmark This Page

let the
database
handle the
data's integrity.

Monday, July
25, 2005
Use Views -
Why they're
handy.

Tuesday,
September 12,
2006
Using
Numerical
Fields - Don't
use them for
fields that
aren't real
numbers.

Oracle
Packages:

Wednesday,
October 12,
2005
DBMS_OUTPUT.
PUT_LINE

Thursday,
November 24,
2005
DBMS_PIPE -
For
communication
between
sessions

Sunday,
August 14,
2005

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (5 of 21)1/9/2008 2:49:17 AM


OracleBlog: Bookmark This Page

UTL_HTTP -
Including an
example of
how to get a
stock quote
from the
Internet.

Top 20 Lists:

Sunday,
January 15,
2006
Oracle DO
NOTs - From
AskTom

Tuesday,
December 20,
2005
20 Beginner
Oracle
Questions

Monday,
September 12,
2005
20 Oracle
Lessons - After
my first few
months of
blogging.

Monday,
December 19,
2005
20 PL/SQL
Coding Tips -
Inspired by an
AskTom thread

Tuesday,
October 17,

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (6 of 21)1/9/2008 2:49:17 AM


OracleBlog: Bookmark This Page

2006
Software
Vendor
Customer
Support - How
to improve
your luck when
dealing with
support (ok
there are only
14)

Book Reviews:

Wednesday,
June 22, 2005
Expert One-on-
One - A couple
of mistakes
from my
favourite
Oracle book.

Monday, May
16, 2005
Optimizing
Oracle
Performance
(Millsap, Holt)

Wednesday,
November 02,
2005
Oracle
Insights: Tales
of the Oak
Table

Thursday, June
23, 2005
PL/SQL Books
- A list of my

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (7 of 21)1/9/2008 2:49:17 AM


OracleBlog: Bookmark This Page

three favourite
PL/SQL books

Templates:

Thursday, June
30, 2005
OOP in PL/
SQL? Yep

Wednesday,
July 13, 2005
Stored
Procedure
template

Great Debates:

Tuesday, June
21, 2005
Natural vs
Synthetic keys
- Choosing
primary keys.

Wednesday,
March 29, 2006
Optimizer -
Should we be
overriding it in
our application?

Monday,
September 19,
2005
PL/SQL Code
Storage: Files
vs In-DB
Packages

Wednesday,
January 18,
2006

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (8 of 21)1/9/2008 2:49:17 AM


OracleBlog: Bookmark This Page

PL/SQL vs J2EE
- Where should
you put the
business logic?

NULLs:

Friday,
September 09,
2005
NULLs in
COUNT - Why
counting on a
column might
get you a
different total.

Friday, June
10, 2005
NULLs in Oracle

Tuesday, May
17, 2005
NULL vs
Nothing - ANSI
SQL is unlike
programming
languages
because NULL
is not nothing.

Gotchas!

Monday, June
13, 2005
Blank Lines
and SQLPlus

Friday, May 20,


2005
Multiple
Foreign Keys
on the Same ID

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (9 of 21)1/9/2008 2:49:17 AM


OracleBlog: Bookmark This Page

Monday, July
04, 2005
SQLCODE and
SQLERRM in
INSERTs

How-To
Guides:

Wednesday,
September 14,
2005
Analyzing
Query
Performance -
using
SQLTRACE and
TKPROF

Friday, May 04,


2007
ANSI Joins - Or
do you want to
stick with the
old school
style?

Tuesday,
February 14,
2006
BPEL - For SOA

Tuesday,
January 17,
2006
Bulk Binding:
FORALL -
Improve
performance of
bulk updates.

Thursday,

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (10 of 21)1/9/2008 2:49:17 AM


OracleBlog: Bookmark This Page

September 22,
2005
Column Name
as a Variable

Thursday, June
16, 2005
Common Table
Column Types
- Two tables
with columns
on the same
type, but not
actually related.

Wednesday,
August 24,
2005
COMPUTE -
How to
emulate a
feature found
in other
languages

Saturday, June
18, 2005
Connect By -
Heirarchical
queries,
something you
need to know.

Monday, June
20, 2005
Decode -
CASE's
precursor.

Thursday,
November 10,
2005
DUAL Table -

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (11 of 21)1/9/2008 2:49:17 AM


OracleBlog: Bookmark This Page

You've seen it,


what is it?

Thursday, May
19, 2005
Dynamically
assigning size
of varchar2 -
You do it in
other
languages, can
you do it in PL/
SQL (and how)?

Wednesday,
May 25, 2005
ENUM in Oracle
- Emulating a
common
programming
feature in PL/
SQL.

Friday, July 01,


2005
Extra Columns
in a GROUP BY

Tuesday, May
09, 2006
Finding Nearby
Rows. Three
methods of
solving similar
requirements.

Monday,
August 01,
2005
Import Export

Monday, May
28, 2007

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (12 of 21)1/9/2008 2:49:17 AM


OracleBlog: Bookmark This Page

Multirow
Inserts - Does
Oracle support
the ANSI SQL
standard of
inserting
multiple rows?
No. But here's
how you can
fake it.

Thursday, May
26, 2005
NOCOPY Hint -
Improve
performance
by changing
how variables
are passed to
PL/SQL
procedures.

Saturday, July
23, 2005
Oracle
BOOLEAN - PL/
SQL has
BOOLEAN,
here's how to
emulate it in
Oracle's SQL

Friday, July 29,


2005
Oracle By
Example -
Bringing
several
concepts
together to
solve a
problem.

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (13 of 21)1/9/2008 2:49:17 AM


OracleBlog: Bookmark This Page

Friday, June
24, 2005
Oracle Client -
How to install

Tuesday, July
04, 2006
Oracle and Java

Monday,
October 30,
2006
Oracle
Passwords -
Answering
your common
questions

Thursday,
December 15,
2005
Oracle and Perl

Thursday,
February 02,
2006
Oracle and
SOA - Covers
Oracle's
Service-
Oriented
Architecture at
a high level

Wednesday,
February 22,
2006
Oracle
Sequences -
This is the one
Oracle carried
on its main
page

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (14 of 21)1/9/2008 2:49:17 AM


OracleBlog: Bookmark This Page

Thursday,
September 01,
2005
Pivot and
Crosstab
Queries - A
very useful
technique for
turning rows
into columns,
and vice versa

Monday, April
03, 2006
Pivot Queries
Using Variable
Number of
Columns - Part
2 on pivot
queries, when
you don't know
how many
columns you
need in
advance.

Friday,
September 30,
2005
PL/SQL
Procedure Call
Overhead - Is
there one?

Friday, August
11, 2006
PL/SQL
Procedure Call
Overhead Re-
visited - By
Zsolt Lajosfalvi

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (15 of 21)1/9/2008 2:49:17 AM


OracleBlog: Bookmark This Page

Saturday,
September 02,
2006
Protecting PL/
SQL Code -
Using wrap.

Tuesday, May
24, 2005
Random
Numbers -
How to
generate them.

Monday,
November 21,
2005
RAW Datatype

Tuesday, June
27, 2006
Recursion vs
Iteration -
What are they,
what are the
advantages of
each one?

Tuesday, June
13, 2006
Refreshing
Data - A High-
level picture of
the flow and
what to keep in
mind when
designing your
data import
strategy

Thursday,
October 06,

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (16 of 21)1/9/2008 2:49:17 AM


OracleBlog: Bookmark This Page

2005
ROWNUM and
ROWID - And
how they're
used to solve
various issues,
and improve
retrieval times.

Tuesday,
February 07,
2006
TRANSLATE -
What it is, how
to use it.

Wednesday,
August 10,
2005
UNION ALL -
How and when
to avoid
performance
hits

Monday, April
17, 2006
Updating Views
- Can you do
it, and if so,
when.

Monday, June
27, 2005
Using Bad
Names in
Oracle

Tuesday,
October 04,
2005
Using DECODE
to exploit

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (17 of 21)1/9/2008 2:49:17 AM


OracleBlog: Bookmark This Page

COUNT/NULL
feature -
Applying
DECODE and
our knowledge
of COUNT/
NULL together
in a little trick
to speed up a
query.

Wednesday,
June 15, 2005
Variable
Constraints -
Can you use
variables in
constraints?
How?

Friday,
November 10,
2006
View
Constraints -
Can you
manage
integrity using
views?

Monday, July
18, 2005
Which instance
am I in?

Tuesday, May
30, 2006
Windowing
Clauses - How
they are used
to empower
your analytic
functions.

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (18 of 21)1/9/2008 2:49:17 AM


OracleBlog: Bookmark This Page

Other:

Monday,
February 26,
2007
Fun With Tom
Kyte - Get a
laugh out of
Oracle's king
of wit

Thursday, April
05, 2007
Oracle Beefs -
Here are mine.
What are yours?

Tuesday,
October 31,
2006
Oracle Gurus -
What makes an
Oracle guru?

Tuesday,
February 21,
2006
Oracle
Interview
Questions -
How to come
up with useful
ones.

Sunday, June
03, 2007
SQL Interview
Questions -
Here's what I
ask. Prepare
for your
interviews.

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (19 of 21)1/9/2008 2:49:17 AM


OracleBlog: Bookmark This Page

Friday, May 25,


2007
What Makes a
Great Oracle
Blog?

// posted by
Robert
Vollman @ Tuesday,
March 28, 2006

Comments:
Fear not, I've
got two posts
coming up

That's good.
For a moment I
thought you're
experiencing
the blogger
burnout effect.
Good luck in
your new job.

I've put
together an
organised list
of my previous
posts

Unlike other
blogging
platforms (like
WordPress for
example), one
of the
disadvantages
of Google's
Blogger is its

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (20 of 21)1/9/2008 2:49:17 AM


OracleBlog: Bookmark This Page

inability to
categorize
posts so that
you can easily
and
automatically
view an
archives page
just like the
one you just
posted (nicely
organized BTH).
# posted by
Eddie Awad :
Tuesday, 28
March, 2006

Post a
Comment

<< Home

http://thinkoracle.blogspot.com/2006/03/bookmark-this-page.html (21 of 21)1/9/2008 2:49:17 AM


OracleBlog: May 2005

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Thursday, May 26, 2005


About Me
On Vacation Name: Robert Vollman
I am taking a much needed vacation Location: Calgary, Alberta,
to Italy for my brother's wedding. Canada
I'll post new material on June 13th, so
please check back then. I was born and raised in
Ottawa, and have lived in Calgary since
In the mean time, here is how you 1991. I like playing sports (hockey,
can pass your break time, apart from soccer, ultimate, basketball, you name it)
reading my recent posts (including and military board games. I also enjoy
one today) or visiting the links on the reading, walking, and playing with my 2
right: cats Lilly and Brutus. I'm a database
application specialist, whatever that is.
1. The Dizwell Forum has some great
Oracle discussions on many topics. View my complete profile

http://www.phpbbserver.com/phpbb/
index.php?mforum=dizwellforum
Best Links
2. Oracle magazine has great articles, ● Ask Tom Kyte
especially Ask Tom and Steven ● Oracle Docs
Feuerstein's PL/SQL Best Practises: ● Dan Morgan and PSOUG
● Steven Feuerstein
http://www.oracle.com/technology/ ● Jonathan Lewis
index.html ● FAQ
Connor McDonald
3. Lots of other Oracle professionals

http://thinkoracle.blogspot.com/2005_05_01_archive.html (1 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

have blogs. I enjoy many of them, but The Oak Table


based on frequency of updates and ● Cary Millsap and Hotsos


number of Oracle-related posts, my ● Steve Adams and Ixora
favourites are David Aldridge and ● Anjo Kolk and OraPerf
Niall Litchfield: ● Dizwell Oracle Wiki
My Personal Blog
http://oraclesponge.blogspot.com/

http://www.niall.litchfield.dial.pipex.
com/

Please look under "Comments" for


Aggregators
more ideas, and of course contribute Brian Duff's OraBlogs

your own. ❍ Eddie Awad's OracleNA


❍ Pete Finnigan's Aggregator
Arrivederci! ❍ Oracle's Bloglist
❍ Oracle Base Aggregator
// posted by Robert Vollman @ Thursday, May

26, 2005 1 comments Top Blogs


❍ Oracle's Ask Tom Kyte
❍ Oracle Guru Jonathan Lewis
NOCOPY Hint ❍ Blogger of the Year Eddie Awad
What is NOCOPY? ❍ Data Warehouser David Aldridge
❍ Oracle Geek Lewis Cunningham
'NOCOPY' is an optional 'hint' to tell Database Expert James Koopmann
the PL/SQL 'compiler' not to go

Dizwell's Howard Rogers


through the overhead of making a

Oracle Master Laurent Schneider


copy of the variable, instead just send

Security Expert Pete Finnigan


a reference. This is generally because ❍

we don't plan on modifying it within ❍ Oracle Award Winner Mark Rittman


the procedure. ❍ Doug Burns
❍ Oracle ACE of the Year Dr. Tim Hall
My first surprise was that you ❍ UKOUG's Andrew (Arfur C.) Clarke
couldn't use "IN NOCOPY." Isn't ❍ Newbie DBA Lisa Dobson
NOCOPY your way of telling Oracle ❍ Coffee-Drinking DBA Jon Emmons
you don't plan on messing around Chris Foot
with the parameter? Yes, but you

The Pythian DBA Team Blog


CAN'T mess with IN parameters, try it!

❍ DBA Don Seiler


CREATE OR REPLACE PROCEDURE ❍ DBA Coskan Gundogar
MyProc (in_value IN number) ❍ Oracle WTF

ARCHIVES
AS
BEGIN
in_value := 3; ❍ LIST ALL ARTICLES

http://thinkoracle.blogspot.com/2005_05_01_archive.html (2 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

END; ❍ May 2005


June 2005
PLS-00363: expression 'IN_VALUE'

July 2005
cannot be used as an assignment

August 2005
target

❍ September 2005
Therefore, it is always safe to send IN ❍ October 2005
parameters by reference, making ❍ November 2005
NOCOPY redundant. ❍ December 2005
❍ January 2006
My second surprise was that you had ❍ February 2006
to specify NOCOPY for an OUT
March 2006
parameter. Because by definition isn't

April 2006
an OUT parameter stating that you

May 2006
plan on modifying the variable? Why ❍

would it be an OUT variable if you ❍ June 2006


weren't touching it? So why would ❍ July 2006
you NOT want NOCOPY? The answer ❍ August 2006
(like so many) comes from Ask Tom: ❍ September 2006
❍ October 2006
http://asktom.oracle.com/pls/ask/f? ❍ November 2006
p=4950:8::::: ❍ December 2006
F4950_P8_DISPLAYID:2047154868085 ❍ January 2007
❍ February 2007
Tom explains one situation where March 2007
you want a copy rather than a

April 2007
reference for an OUT or IN OUT

May 2007
parameter. When you change a

June 2007
NOCOPY parameter, it changes right ❍

away, instead of upon successful ❍ October 2007


completion of the stored procedure.
❍ Current Posts
Imagine you modified the parameter,
but threw an exception before
successful completion. But that
parameter has been changed and the
calling procedure could be stuck with
a bogus value.

Despite how much I trust Tom,


everybody knows that I don't believe
things until I see for myself. And
neither should you! Besides, things
change. Here's my example.

http://thinkoracle.blogspot.com/2005_05_01_archive.html (3 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

CREATE OR REPLACE PROCEDURE


NoCopyProc (in_value IN OUT
NOCOPY number)
AS
x number;
BEGIN
DBMS_OUTPUT.PUT_LINE(in_value || '
NoCopyProc');
in_value := 2;
x := 1/0;
END;

CREATE OR REPLACE PROCEDURE


CopyProc (in_value IN OUT number)
AS
x number;
BEGIN
DBMS_OUTPUT.PUT_LINE(in_value || '
CopyProc');
in_value := 4;
x := 1/0;
END;

CREATE OR REPLACE PROCEDURE


InterProc (in_value IN OUT NOCOPY
number)
AS
BEGIN
IF (in_value = 1) THEN NoCopyProc
(in_value);
ELSE CopyProc(in_value);
END IF;
EXCEPTION
WHEN OTHERS THEN NULL;
END;

CREATE OR REPLACE PROCEDURE


MyProc
AS
the_value NUMBER(1);
BEGIN
the_value := 1;
InterProc(the_value);

http://thinkoracle.blogspot.com/2005_05_01_archive.html (4 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

DBMS_OUTPUT.PUT_LINE(the_value);

the_value := 3;
InterProc(the_value);
DBMS_OUTPUT.PUT_LINE(the_value);
END;

BEGIN MyProc; END;

1 NoCopyProc
2
3 CopyProc
3

For an excellent and more detailed


overview of NOCOPY, complete with
examples, restrictions and
performance analysis, I once again
refer you to Steven Feuerstein's
writings. Although I encourage you to
add his books to your collection, this
chapter happens to be on-line for
free:

Oracle PL/SQL Programming Guide to


Oracle8i Features
http://www.unix.org.ua/orelly/oracle/
guide8i/ch10_01.htm

So what is a guy to do?

Well, first of all, it was suggested to


me that I should find a more gender-
neutral way of summing up an article.
Allow me to rephrase.

So what should we do?

1. Understand what NOCOPY means


and its uses and restrictions (by
following those links)
2. Take advantage of NOCOPY when
you want the performance advantage
of avoiding the cost of the temporary

http://thinkoracle.blogspot.com/2005_05_01_archive.html (5 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

storage for OUT or IN OUT


parameters.
3. Avoid NOCOPY when you don't
want the side effects if the procedure
fails early.

Remember, in the end, that NOCOPY


is just a "hint" and Oracle will do
whatever it wants anyway. Like all
hints, you have to ask yourself what
makes it necessary, and what makes
you think Oracle is going to choose
incorrectly.

// posted by Robert Vollman @ Thursday, May

26, 2005 2 comments

Wednesday, May 25, 2005


ENUM in Oracle
What is ENUM?

ENUM is short for enumeration. Its a


useful programming type that
contains an ordered list of string
values. The programmer can define
the valid values depending on their
application.

Some good examples of ENUMs


would be days and months, or
something like directions ('North',
'South', 'East', 'West').

Is there an Oracle 'ENUM' type?

No, not really. But there are other


ways of accomplishing the same
thing.

For tables, just set it to a string and


add a constraint that it is within a
certain set.

http://thinkoracle.blogspot.com/2005_05_01_archive.html (6 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

CREATE TABLE atable (


col1 varchar2(10),
CONSTRAINT cons_atable_col1
CHECK (col1 IN ('Monday', 'Tuesday',
'Wednesday', 'Thursday',
'Friday', 'Saturday', 'Sunday'))
);

SQL> INSERT INTO atable (col1)


VALUES ('Monday');

1 row created.

SQL> INSERT INTO atable (col1)


VALUES ('Blingday');
insert into atable (col1) values
('Blingday')
*
ERROR at line 1:
ORA-02290: check constraint
(ROBERT.CONS_ATABLE_COL1)
violated

What happens if you use this type in


a procedure? Will the constraint be
checked? No.

CREATE OR REPLACE PROCEDURE


MyProc (in_col IN atable.col1%TYPE)
AS
BEGIN
DBMS_OUTPUT.PUT_LINE(in_col);
END;

SET SERVEROUTPUT ON;

EXEC MyProc('Monday');
EXEC MyProc('Blingday');

So can you create a package subtype


for this? That would be more elegant
anyway.

But according to Oracle PL/SQL

http://thinkoracle.blogspot.com/2005_05_01_archive.html (7 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

Programming by Steven Feuerstein


Chapter 4, I don't think you can
(check comments for any refutations
to this).

http://www.amazon.com/exec/
obidos/ASIN/0596003811/
qid=1117039808/sr=2-1/
ref=pd_bbs_b_2_1/102-9543590-
3979349

I think the best thing to do in this


case is to create a procedure to
validate your input.

CREATE OR REPLACE PROCEDURE


MyCheck (in_col IN atable.col1%TYPE)
AS
BEGIN
IF (in_col NOT IN ('Monday', 'Tuesday',
'Wednesday', 'Thursday', 'Friday',
'Saturday', 'Sunday')) THEN
-- Throw Exception here, be sure to
catch it in MyProc!!
NULL;
END IF;
END;

This approach is consistent with


Steven Feuerstein's approach to
programming. He suggests
separating these things into separate
procedures. Then when a future
release of Oracle supports a concept,
or when you figure out how to do it,
you can make the change in a single
place.

So what is a guy to do?


1. If you want to use enum in a table,
use a check constraint.
2. If you want to use enum in a
stored procedure, write a separate

http://thinkoracle.blogspot.com/2005_05_01_archive.html (8 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

procedure to validate the input.

// posted by Robert Vollman @ Wednesday,

May 25, 2005 1 comments

Tuesday, May 24, 2005


Random Numbers
Let me get your advice on this one.

Here's the situation, you need an


evenly distributed sequence of
random integers from 1 to 20. You
decided to use the Oracle random
number package 'dbmsrand'.

Incidentally, I decided to do it this


way after searching Ask Tom.

http://asktom.oracle.com/~tkyte/
Misc/Random.html
http://asktom.oracle.com/pls/ask/f?
p=4950:8:::::
F4950_P8_DISPLAYID:831827028200

There is a link to his web site to the


right. Bookmark it.

While you're at it, bookmark Dan


Morgan's page (link on the right).

http://www.psoug.org/reference/
dbms_random.html

Ok, back to the story.

After you read the instructions on


using it, you probably write
something like this in your PL/SQL
stored procedure:

AS

http://thinkoracle.blogspot.com/2005_05_01_archive.html (9 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

random_value number(2,0);
BEGIN
random_value := dbms_random.value
(0,20);

Now you notice whoops, you're


getting some 0s. You don't want 0.
Plus you're not getting very many
20s. So you do this instead

random_value := dbms_random.value
(1,21);

Much better! But whoops - you're


getting the occasional 21! So you
scratch your brain and do this:

random_value := dbms_random.value
(1,21);
random_value := MOD(random_value,
20) + 1;

That should pour the 21s into the 1


pile, which you noticed is very, very
slightly lower than the others.

Now you think you're getting the


values you want. So here are my
questions:

1. Will this truly generate an even


sample of numbers from 1 to 20? Will
there be the right number of 1s and
20s?
2. Is there a better way?
3. Say you're generating a very large
sequence, thinking about
performance, do you see any
problems with this approach I should
consider?

Here is the complete solution:

--------------------
@utlraw

http://thinkoracle.blogspot.com/2005_05_01_archive.html (10 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

@prvtrawb.plb
@dbmsoctk
@prvtoctk.plb
@dbmsrand

create table value_holder as (f_value


NUMBER(2,0));

create or replace procedure


ValuePlacer (number_to_generate IN
number)
AS
random_value number(2,0);
BEGIN
for x in 1..number_to_generate
LOOP
random_value := dbms_random.value
(1,21);
random_value := MOD(random_value,
20) + 1;
insert into value_holder values
(random_value);
END LOOP;
END;

exec ValuePlacer(1000);

select f_value, count (f_value) from


value_holder group by f_value;
-----------------

Thanks!

// posted by Robert Vollman @ Tuesday, May

24, 2005 1 comments

Friday, May 20, 2005


Multiple Foreign Keys
on the Same ID
You can't set the same foreign key for
two different columns with the same
constraint:

http://thinkoracle.blogspot.com/2005_05_01_archive.html (11 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

create table atable (


id varchar2(65) primary key);

create table btable (


a_id1 varchar2(65),
a_id2 varchar2(65));

ALTER TABLE btable


ADD CONSTRAINT btable_fkey_both
FOREIGN KEY (a_id1, a_id2)
REFERENCES atable(id, id)
ON DELETE SET NULL;

ERROR at line 1:
ORA-00957: duplicate column name

ALTER TABLE btable


ADD CONSTRAINT btable_fkey_both
FOREIGN KEY (a_id1, a_id2)
REFERENCES atable(id)
ON DELETE SET NULL;

ERROR at line 1:
ORA-02256: number of referencing
columns must match referenced
columns

But you can do it if you break it up


into separate constraints:

ALTER TABLE btable


ADD CONSTRAINT btable_fkey1
FOREIGN KEY (a_id1)
REFERENCES atable (id)
ON DELETE SET NULL;

Table altered.

ALTER TABLE btable


ADD CONSTRAINT btable_fkey2
FOREIGN KEY (a_id2)
REFERENCES atable (id)
ON DELETE SET NULL;

http://thinkoracle.blogspot.com/2005_05_01_archive.html (12 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

Table altered.

Note: Monday is a holiday in Canada,


no update until Tuesday.

// posted by Robert Vollman @ Friday, May 20,

2005 0 comments

Thursday, May 19, 2005


Dynamically assigning
size of varchar2
I thought I would declare my variable-
lengthed variables with a pre-defined
constant. Why?

1. I'd be sure they matched up


everywhere.
2. I could change them all in a single
place if required.

But I don't think you can do that in PL/


SQL.

CREATE OR REPLACE PACKAGE


test_constants IS
MAX_LEN CONSTANT NUMBER := 32;
END test_constants;

Package created.

SET SERVEROUTPUT ON

-- Anonymous block
DECLARE
x VARCHAR2(test_constants.
MAX_LEN); -- Can't do this
BEGIN
x := 'Test ' || test_constants.MAX_LEN;
dbms_output.put_line(x);
END;

ERROR at line 2:

http://thinkoracle.blogspot.com/2005_05_01_archive.html (13 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

ORA-06550: line 2, column 31:


PLS-00491: numeric literal required

But what about other types?

Substitute NVARCHAR2, VARCHAR,


CHAR, NCHAR, or STRING if you like,
same result. Incidentally the "N" just
means you are specifying the length
in bytes instead of characters.

So what is a guy to do?

1. Just put a comment before every


number, and make it a practise to
make sure they all match.

DECLARE
x VARCHAR2(32); -- test_constants.
MAX_LEN = 32

But here is another option.

2. Create a table with the types you


want, and then use those types.

CREATE TABLE TEST_CONSTANTS (


MAX_LEN VARCHAR2(32)
);

Table created.

DECLARE
x TEST_CONSTANTS.MAX_LEN%TYPE;
BEGIN
x := 'Test';
dbms_output.put_line(x);
END;

// posted by Robert Vollman @ Thursday, May

19, 2005 4 comments

Wednesday, May 18, 2005

http://thinkoracle.blogspot.com/2005_05_01_archive.html (14 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

Steven Feuerstein on
Refactoring
Refactoring for PL/SQL Developers
By Steven Feuerstein

From Oracle Magazine January/


February 2005

http://www.oracle.com/technology/
oramag/oracle/05-jan/o15plsql.html

Steven Feuerstein is one of my


favourite PL/SQL authors, especially
when he lays off the socio-political
tangents.

I especially enjoyed his article on


refactoring PL/SQL code. I had a few
thoughts to add to it.

My additional thoughts on
Refactoring:

1. One of the advantages that also


bears note is that re-factoring your
code can encourage code re-use.
Clean, modular, well-written code is
easy to re-use, reducing future
programming efforts.

2. However, one of the disadvantages


of code re-factoring is that you can
introduce unknown factors to a
(presumably) working, trusted
procedure. There is an expense to re-
testing and re-validating the
modified code. Even if you FIXED
errors, some other procedures might
have been written in such a way that
they depend on them, and they will
now fail.

My additional imperfections in the

http://thinkoracle.blogspot.com/2005_05_01_archive.html (15 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

unfactored code sample:

1. Inline documentation

I think Steven failed to point out the


most egregious transgression: lack of
inline documentation! I believe
almost every procedure needs it, at
LEAST a 'header' but preferrably also
some comments that explain in plain
language what was intended by the
code. Steven did go ahead and add
some in-line documentation, but
didn't draw any attention to that.

* Note: Perhaps due to his friendly


nature, I am referring to him in this
post in the familiar. Certainly no
disrespect is intended.

2. Bad variable names

If this article was to be re-written, I


would change the initial code sample
to use very bad variable names and
then re-name them as part of the
"refactored" version. I think that's a
very common problem.

My comments on the refactored


version:

1. utl_file_constants

Rather than define my own file


utl_file_constants, I would use
something that was already defined
and possibly tied in. I mean, there's a
REASON that 32767 was used. You
are bound by a particular (probably
OS-level, or DB-level) limitation that
is probably defined in some package
or some configuration value, or right
in UTL_FILE.

http://thinkoracle.blogspot.com/2005_05_01_archive.html (16 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

If you define your own and then all of


a sudden the 32767 limitation is
changed at the OS or DB level, you
STILL have to go change all your
private constant packages. I mean
that's a bit better than having to
change magic numbers in your code,
but we can do a little better, I think.

get_next_line_from_file isn't even


aware of that limitation. How would
this program fail if you set the value
to, say, '4' instead of '32767' in
utl_file_constants?

It appears like Steven didn't even use


his utl_file_constant for 32767 in the
final version (Code Listing 7). Why
not? The answer is probably that you
can not dynamically define the length
of a string. That is, of course, a PL/
SQL restriction. I suppose we should
be happy with whatever magic
numbers we can remove.

2. compare_latest_read

I'm really not sure I would have


created "compare_latest_read". That
seems like we are overdoing it. I
mean this is not a big procedure and
its entire point is to do what is in that
procedure anyway. Why introduce the
overhead of another procedure
(assuming there is any overhead)?

Think of it this way, you are passing


in the lines. Instead of that, you could
pass in the files and
compare_latest_read can call
get_next_line_from_file to get the
lines. That would be reasonable. But
now, all of a sudden, the main

http://thinkoracle.blogspot.com/2005_05_01_archive.html (17 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

procedure is doing nothing but


initialising and calling a procedure.
So basically "compare_latest_read" is
one reasonable change away from
already doing all the work.

So why is it even necessary? It is only


done once ... How is the purpose of
this internal procedure significantly
different from the purpose of the
overall procedure? I suppose this is
just an opinion, and a matter of taste,
but I really think the extra procedure
is unnecessary.

Other comments and questions:

1. VARCHAR2 length

In the procedure Steven uses


VARCHAR2 as a variable-lengthed
string even though we know the
maximum size (32767). Is there any
value in specifying VARCHAR2
(32767) instead of VARCHAR2 in the
final version (as the IN or OUT
parameters)? Is there any advantage
to that? Is it even possible?

2. Procedures vs Functions

Any reason why Steven uses


procedures instead of functions?

3. Cleanup: closing an unopened file

In "cleanup", will there be a problem


if you UTL_FILE.fclose a file that
hasn't been opened? Because that will
happen if there is an exception while
opening the first file when cleanup
closes both.

4. Handling "WHEN OTHERS"

http://thinkoracle.blogspot.com/2005_05_01_archive.html (18 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

WHEN OTHERS - cleanup .... without


any error message written to screen
or log?? For shame! Steven said
earlier in the article you would re-
raise the exception, but in the end he
didn't.

Plus the problem with re-raising an


exception is you are actually getting a
NEW exception. If it is checked later,
the error messages will say the error
was created at this new line number
instead of the original spot. Might as
well fully handle the exception right
here when we catch it.

Conclusion:

A sure sign of a good article is that it


gets you thinking. Steven Feuerstein
rarely fails to achieve that. I have
shared these thoughts with him, and
I'll follow-up with any answers or
clarification he provides.

I noticed Harm Vershuren had some


thoughts in his blog as well:
http://technology.amis.nl/blog/index.
php?p=317

// posted by Robert Vollman @ Wednesday,

May 18, 2005 1 comments

Tuesday, May 17, 2005


NULL vs Nothing
In Oracle, there is a difference
between 'null' and nothing at all. Here
is my story.

I discovered this when playing with


default values. First, I created a table
that had a default value for one

http://thinkoracle.blogspot.com/2005_05_01_archive.html (19 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

column. Then I tried to insert a row


that had nothing at all, and it
wouldn't use the default value. So I
tried inserting a row with null, and it
didn't assign the default value.
Observe.

SQL> create table atable (


2 last_name varchar2(32) not null,
3 first_name varchar2(32) not null,
4 rating smallint default 0);

Table created.

SQL> insert into atable values


('Smith', 'John', null);

1 row created.

SQL> select * from atable;

LAST_NAME FIRST_NAME RATING


--------------------------------
--------------------------------
----------
Smith John

Notice it inserted NULL, and not the


default value.

SQL> insert into atable values


('Smith', 'John');
insert into atable values ('Smith',
'John')
*
ERROR at line 1:
ORA-00947: not enough values

Why doesn't this work? You may


know this already, but in the words of
Dan Morgan: "By not specifying
column names you are signifying that
you are providing values for ALL
columns. This is why it is a very bad
practice as doing an ALTER TABLE

http://thinkoracle.blogspot.com/2005_05_01_archive.html (20 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

ADD immediately invalidates all SQL


statements."

So let's do it the proper way and see


if there is a difference.

SQL> insert into atable (last_name,


first_name) values ('Smith', 'John');

1 row created.

SQL> select * from atable;

LAST_NAME FIRST_NAME RATING


--------------------------------
--------------------------------
----------
Smith John
Smith John 0

And there is a difference. Excellent.


Out of curiousity between the two
ways of inserting rows, I tried this:

SQL> insert into atable (last_name,


first_name, rating) values ('Smith',
'John', null);

1 row created.

SQL> select * from atable;

LAST_NAME FIRST_NAME RATING


--------------------------------
--------------------------------
----------
Smith John
Smith John 0
Smith John

So I was thinking, why isn't this null


being replaced with the default value?
Isn't the default value there for
instances to replace null? If you're as
skeptical as I am, it will make sense

http://thinkoracle.blogspot.com/2005_05_01_archive.html (21 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

after this second test, where I add the


"NOT NULL" constraint.

drop table atable;

create table atable (


last_name varchar2(32) not null,
first_name varchar2(32) not null,
rating smallint default 0 NOT NULL);

SQL> insert into atable (last_name,


first_name, rating) values ('Smith',
'John', null)
*
ERROR at line 1:
ORA-01400: cannot insert NULL into
("ROBERT"."ATABLE"."RATING")

That's when I figured out where I was


confused. There are 3 things you can
assign to a column when doing an
insert:
1. a value (eg: 0)
2. null
3. nothing at all

See, there is a difference between #2


(null) and #3 (nothing at all). To wit:
1. Using null (#2) is 'ok' if you are
inserting without specifying columns.
Nothing at all (#3) is not.
2. Null (#2) will not be replaced by a
default value when inserting, whereas
nothing at all (#3) will.

When I started looking at stored


procedures, I found even more
difference between NULL and
nothing. My second story starts off as
an investigation of passing NULL to
stored procedures.

There is no such thing as "NOT NULL"


for stored procedure parameters.

http://thinkoracle.blogspot.com/2005_05_01_archive.html (22 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

I noticed that the "NOT NULL"


keyword can't be used in procedure
parameters (nor can NULL).
Apparently that is for creating tables
only. You can not force input
parameters to a procedure to be non-
null. All you can do is start your
procedure by verifying the input
parameters.

SQL> create or replace procedure


MyProc1 (some_value IN number NOT
NULL)
2 AS
3 BEGIN
4 NULL;
5 END;
6/

Warning: Procedure created with


compilation errors.

Nor can you allow it to be NULL.

SQL> create or replace procedure


MyProc2 (some_value IN number
NULL)
2 AS
3 BEGIN
4 NULL;
5 END;
6/

Warning: Procedure created with


compilation errors.

You can, however, assign default


values. However, note the difference
between assigning "NULL" and
assigning nothing at all.

SQL> create or replace procedure


MyProc3 (some_value IN number := 0)

http://thinkoracle.blogspot.com/2005_05_01_archive.html (23 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

2 AS
3 BEGIN
4 DBMS_OUTPUT.PUT_LINE
(some_value);
5 NULL;
6 END;
7/

Procedure created.

SQL> exec MyProc3();


0

PL/SQL procedure successfully


completed.

SQL> exec MyProc3(NULL);

PL/SQL procedure successfully


completed.

SQL> exec MyProc3(1);


1

PL/SQL procedure successfully


completed.

Bottom line, there is a difference


NULL and nothing at all for both
tables and stored procedures. So
what is a guy to do?
1. Understand there is a difference
between NULL and nothing
2. For tables, use "NOT NULL" and for
stored procedures, verify the input
manually
3. Use default values for both tables
and stored procedures when passing
nothing at all.

// posted by Robert Vollman @ Tuesday, May

17, 2005 3 comments

http://thinkoracle.blogspot.com/2005_05_01_archive.html (24 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

Monday, May 16, 2005


Optimizing Oracle
Performance (Millsap,
Holt)
There are certain "camps" in the
worldwide Oracle community. For
example, there is the "Oak Table
Network" of "Oracle scientists" who
seek thorough understandings of
issues backed up by details, tests and
proofs. Contrasting is the "Silver
Bullet" family of field-tested generals
who prefer rules of thumb and quick
fixes even it means some false
understandings and occasionally
being wrong. Cary Millsap (of the Oak
Table Network) stands as someone
respected by both sides.

Cary Millsap worked at Oracle for 10


years on system performance before
co-founding Hotsos in 1999 (http://
www.hotsos.com - register for free).
He is one of the most trusted sources
on matters of Oracle system
performance, and "Optimizing Oracle
Performance" is considered his finest
work (4.5 out of 5 stars on Amazon).
The best way to learn more about
him is to see for yourself. Here are
some of his most popular articles:

"Diagnosing Performance Problems"


from Oracle Magazine. A brief
summary of what is covered in this
book:http://www.oracle.com/
technology/oramag/oracle/04-jan/
o14tech_perf.html

"Introduction", the first chapter from


"Optimizing Oracle
Performance."Chapter 1: http://www.

http://thinkoracle.blogspot.com/2005_05_01_archive.html (25 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

oreilly.com/catalog/optoraclep/
chapter/ch01.pdf

"Case Study", the 12th chapter from


"Optimizing Oracle
Performance."Chapter 12 (Case
Study): http://www.oreillynet.com/
pub/a/network/excerpt/
optimizing_oracle_chap12/index.html

"Performance Management: Myths


and Facts." One of his most popular
articles.https://secure.hotsos.com/
downloads/visitor/00000024.pdf

"Why a 99%+ Database Buffer Cache


Hit Ratio is Not Ok." Another of his
more popular articles.http://www.
oradream.com/pdf/Why%20a%2099%
20Cahe%20Hit%20Ratio%20is%20Not%
20OK.pdf

While everyone will have their own


favourite parts of the book, I think
most readers would agree that
getting a good taste of the author's
performance tuning philosophy is
one of the highlights. "Method R", not
to be confused with "System R" (ie.
SQL), is not about looking at
STATSPACK, cache hit ratios, or V$
tables and guessing. The author
wanted to devise a system to identify
and resolve the top performance
concerns of an organisation with
reliable, predictable results. The first
few chapters put this method in
writing in perhaps the best way since
the introduction of "YAPP" (Anjo Kolk).

"The performance enhancement


possible with a given improvement is
limited by the fraction of the

http://thinkoracle.blogspot.com/2005_05_01_archive.html (26 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

execution time that the improved


feature is used." - Amdahl's Law

After several years of research, the


author discovered that Extended SQL
Trace Data was at the centre of
"Method R". Some of the articles
should give you a good taste of what
Extended SQL Trace data is, if you
didn't know already. By the time you
finish reading this book you will
know exactly how to collect and
interpret all the little "ela=17101
p1=10 p2=2213 p3=1 ..." within into
something meaningful. For some,
that justifies the price tag right there.

So in essence I would have re-named


this book "Method R: Optimizing
Oracle Performance Using Extended
SQL Trace Data," because that is
basically what this book is about.
There are some reasonably "stand-
alone" chapters on other topics, for
instance on the Oracle Fixed View
tables (Chapter 8) and on Queueing
Theory (Chapter 9), but that is not
the primary focus of the book.

Those that are expecting a more


broad treatment of the subject of
performance tuning may be
justifiably disappointed that it
basically covers only this narrow
aspect. However, it is covered very
well, and it isn't really covered
anywhere else. The author makes no
apologies for this, claiming that
extended SQL trace data is the only
resource you will ever need for
diagnosing and solving performance
problems.

"You cannot extrapolate detail from

http://thinkoracle.blogspot.com/2005_05_01_archive.html (27 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

an aggregate." - Cary Millsap's


preference of SQL extended trace
data over fixed views (system-wide
average performance characteristics)

Indeed, some people might contend


that the author spends a little too
much time stating his beliefs,
defending them, and patting himself
on the back. But I think it adds a
certain flavour to the book, and I
respect an author who backs up his
statements.

"Proving that V$ data are superior to


extended SQL trace data because of
the 'missing time' issue is analagous
to proving that its safer to be in a
room with a hungry bear if you'll just
close your eyes." - Cary Millsap

The book can be a tough read in the


sense that the author goes very deep
into the material, and generally each
subject is treated thoroughly.
Chapter 9 on Queueing Theory can
be a particularly overwhelming
chapter. But the material is served in
bite-size pieces, and broken up with
tips, tricks, stories, diagrams and
code (sometimes 3+ pages worth at a
time, embedded directly in the
middle of a chapter). There are even
worthwhile exercises at the end of
each chapter.

In the end, I enjoyed this book and


I'm glad I got it. I don't consider it a
"must have" for your Oracle
collection, but I definitely feel it is
quite worthwhile. I recommend it
especially to those who read his
articles and were very comfortable
with his writing style and philosophy,

http://thinkoracle.blogspot.com/2005_05_01_archive.html (28 of 29)1/9/2008 2:49:22 AM


OracleBlog: May 2005

and also to those that need a book on


extended SQL trace data (because
this is basically the only one). But
even those in the "Silver Bullet" camp
will be glad to add another tool to
their belt.

Thumbs up.

http://www.coug.ab.ca/Resources/
BookReviews/MillsapsOOPByRVollman.
htm

// posted by Robert Vollman @ Monday, May

16, 2005 0 comments

http://thinkoracle.blogspot.com/2005_05_01_archive.html (29 of 29)1/9/2008 2:49:22 AM


OracleBlog: Never noticed this before

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Wednesday,
About Me
February 22, 2006
Name: Robert Vollman
Never Location: Calgary, Alberta, Canada
noticed
this before I was born and raised in Ottawa, and have lived in
So I was Calgary since 1991. I like playing sports (hockey,
searching soccer, ultimate, basketball, you name it) and military board
through the games. I also enjoy reading, walking, and playing with my 2 cats
latest Oracle 10g Lilly and Brutus. I'm a database application specialist, whatever
that is.
SQL Reference,
check out what I
View my complete profile
found on page 5-
175:

SELECT
manager_id,
Best Links
● Ask Tom Kyte
last_name, Oracle Docs
salary, SUM

Dan Morgan and PSOUG


(salary)

Steven Feuerstein
OVER (PARTITION

BY manager_id ● Jonathan Lewis


ORDER BY salary ● FAQ
RANGE ● Connor McDonald
UNBOUNDED ● The Oak Table
PRECEDING) ● Cary Millsap and Hotsos
l_csum ● Steve Adams and Ixora

http://thinkoracle.blogspot.com/2006/02/never-noticed-this-before.html (1 of 4)1/9/2008 2:49:25 AM


OracleBlog: Never noticed this before

FROM employees; ● Anjo Kolk and OraPerf


● Dizwell Oracle Wiki
MANAGER_ID ● My Personal Blog
LAST_NAME
SALARY L_CSUM
----------
---------
------ ------
Aggregators
100 Mourgos Brian Duff's OraBlogs

5800 5800 ❍ Eddie Awad's OracleNA


100 Vollman ❍ Pete Finnigan's Aggregator
6500 12300 ❍ Oracle's Bloglist
... ❍ Oracle Base Aggregator

I'm in the Oracle


default HR
Top Blogs
Oracle's Ask Tom Kyte
schema! I'm ❍

employee 123 ❍ Oracle Guru Jonathan Lewis


and I report ❍ Blogger of the Year Eddie Awad
directly to KING, ❍ Data Warehouser David Aldridge
the President! Of ❍ Oracle Geek Lewis Cunningham
course, I'm one ❍ Database Expert James Koopmann
of the lowest ❍ Dizwell's Howard Rogers
paid managers, ❍ Oracle Master Laurent Schneider
but still. ❍ Security Expert Pete Finnigan
Oracle Award Winner Mark Rittman
Of course, the

Doug Burns
first name is ❍

Shonta. But I can ❍ Oracle ACE of the Year Dr. Tim Hall
dream, right? I ❍ UKOUG's Andrew (Arfur C.) Clarke
can pretend that ❍ Newbie DBA Lisa Dobson
I'm one of Lex de ❍ Coffee-Drinking DBA Jon Emmons
Haan's fictional ❍ Chris Foot
colleagues, right? ❍ The Pythian DBA Team Blog
❍ DBA Don Seiler
I also saw this in DBA Coskan Gundogar
the latest version

Oracle WTF
of Oracle 9i

documentation:
SQL Reference: ARCHIVES
Page 365, 6-155 ❍ LIST ALL ARTICLES
for the example ❍ May 2005
of SUM. ❍ June 2005
Page 1532, 18- ❍ July 2005

http://thinkoracle.blogspot.com/2006/02/never-noticed-this-before.html (2 of 4)1/9/2008 2:49:25 AM


OracleBlog: Never noticed this before

42 on using ❍ August 2005


LEVEL Pseudo- ❍ September 2005
Column. ❍ October 2005
November 2005
and Sample

December 2005
Schemas:

January 2006
Page 68, section

February 2006
4-28 on Oracle's

March 2006
sample HR ❍

Schema ❍ April 2006


❍ May 2006
So it must have ❍ June 2006
been around for ❍ July 2006
awhile. I think ❍ August 2006
that's so cool! I'm ❍ September 2006
going to write ❍ October 2006
Oracle and ask
November 2006
them to fix my

December 2006
first name. I urge

January 2007
you to do the ❍

same in your ❍ February 2007


implementations: ❍ March 2007
❍ April 2007
UPDATE ❍ May 2007
employees SET ❍ June 2007
first_name = ❍ October 2007
'Robert' where
last_name =
'Vollman';

// posted by Robert
Vollman @ Wednesday,
February 22, 2006

Comments:
Oracle: Sure we
can..but are you
sure you dont
want salary
column updated ?
# posted by

http://thinkoracle.blogspot.com/2006/02/never-noticed-this-before.html (3 of 4)1/9/2008 2:49:25 AM


OracleBlog: Never noticed this before

Anonymous :
Thursday, 23
February, 2006

Post a
Comment

<< Home

http://thinkoracle.blogspot.com/2006/02/never-noticed-this-before.html (4 of 4)1/9/2008 2:49:25 AM


OracleBlog: June 2005

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I think data,
I think Oracle. I also enjoy writing, so I use this format to organise my thoughts. Please feel free
to discuss any thoughts you may have on the same topics, even old ones (I will see and respond
to such comments). You may want to start with "LIST ALL ARTICLES" under Archives.

Thursday, June 30, 2005


OOP in PL/SQL? Yep
I was recently speaking with someone who was stunned to find out that object-
oriented programming is available in PL/SQL (as of version 9, basically).

I guess I was stunned he didn't know this, but then again, I guess there isn't much
fanfare about it.

Inheritance? Yep.
Polymorphism? Yep.
Encapsulation? Yep.

I gave him this basic, bare-bones template. It isn't much, but it can get someone
started.

CREATE OR REPLACE TYPE some_object AS OBJECT (

some_variable NUMBER(10),

MEMBER FUNCTION member_function RETURN NUMBER,


MEMBER FUNCTION member_function (l_overloading IN NUMBER) RETURN NUMBER,
MEMBER PROCEDURE member_procedure,

-- Static functions can be used with an instance of the object


-- They can NOT reference any other non-static member functions or variables
STATIC FUNCTION static_function (l_value IN NUMBER DEFAULT 1) RETURN
NUMBER,

-- Constructors must return self. Constructors are optional


CONSTRUCTOR FUNCTION some_object (some_variable NUMBER) RETURN SELF AS
RESULT,

-- Used for comparison purposes: GROUP BY, ORDER BY, DISTINCT

http://thinkoracle.blogspot.com/2005_06_01_archive.html (1 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

-- No parameters allowed, returns NUMBER, DATE, VARCHAR2, CHAR or REAL


MAP MEMBER FUNCTION map_member_function RETURN NUMBER

-- ORDER takes one parameter of same type, and returns NUMBER


-- You may only have EITHER MAP OR ORDER
-- ORDER MEMBER FUNCTION order_member_function (some_other_object IN
some_object) RETURN NUMBER

)
INSTANTIABLE -- Or "NOT INSTANTIABLE" if this is a base class only
NOT FINAL -- Or "FINAL" if this class will NOT have a sub-class
;

CREATE OR REPLACE TYPE composition_object AS OBJECT (

composed_object some_object

);

CREATE OR REPLACE TYPE derived_object


UNDER some_object (

OVERRIDING MEMBER PROCEDURE member_procedure

);

CREATE OR REPLACE TYPE BODY some_object AS

MEMBER FUNCTION member_function RETURN NUMBER


IS
BEGIN
-- The "SELF" isn't necessary, but is always available by default in member
functions
RETURN SELF.some_variable;
END member_function;

MEMBER FUNCTION member_function (l_overloading IN NUMBER) RETURN NUMBER


IS
BEGIN
RETURN l_overloading;
END member_function;

MEMBER PROCEDURE member_procedure


IS
BEGIN
NULL;
END member_procedure;

-- Note: Unlike with packages, no private functions or declarations are allowed.

http://thinkoracle.blogspot.com/2005_06_01_archive.html (2 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

-- MEMBER FUNCTION hidden_proc RETURN NUMBER ...

-- Remember, static functions can't access SELF variables


STATIC FUNCTION static_function (l_value IN NUMBER DEFAULT 1) RETURN NUMBER
IS
BEGIN
RETURN l_value;
END static_function;

CONSTRUCTOR FUNCTION some_object (some_variable NUMBER) RETURN SELF AS


RESULT
AS
BEGIN
SELF.some_variable := some_variable;

-- It will automatically return self, don't even try to return anything else
RETURN;

END some_object;

MAP MEMBER FUNCTION map_member_function RETURN NUMBER IS


BEGIN
RETURN SELF.some_variable;
END map_member_function;

-- ORDER MEMBER FUNCTION order_member_function (some_other_object IN


some_object) RETURN NUMBER IS
-- BEGIN
-- IF some_other_object.some_variable < SELF.some_variable THEN RETURN 1;
-- ELSIF some_other_object.some_variable > SELF.some_variable THEN RETURN -1;
-- ELSE RETURN 0;
-- END IF;
-- END order_member_function;

END;

CREATE OR REPLACE TYPE BODY derived_object AS

OVERRIDING MEMBER PROCEDURE member_procedure


IS
BEGIN
NULL;
END member_procedure;

END;

-- Test!
DECLARE

http://thinkoracle.blogspot.com/2005_06_01_archive.html (3 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

-- You MUST instantiate it to use it. A NULL object is hard to use.


my_some_object some_object := some_object(0);
my_composition_object composition_object := composition_object
(my_some_object);
my_number NUMBER;
BEGIN
my_number := my_composition_object.composed_object.member_function;
my_number := some_object.static_function(my_number);
END;

// posted by Robert Vollman @ Thursday, June 30, 2005 2 comments

Constraints
No blog from me. But here is an excellent one from Jeff Hunter that I wish I'd
written.

http://marist89.blogspot.com/2005/06/deferrable-constraints_29.html

Also, check his Comments to see Doug Burns' link to an article by Chris Date.

// posted by Robert Vollman @ Thursday, June 30, 2005 1 comments

Monday, June 27, 2005


Using Bad Names in Oracle
In Oracle, you can't start a table, procedure or variable name with a number.

SQL> CREATE TABLE 123Table (aval NUMBER);


CREATE TABLE 123Table (aval NUMBER)
*
ERROR at line 1:
ORA-00903: invalid table name

You can get around this simply using quotes.

SQL> CREATE TABLE "123Table" (aval NUMBER);

Table created.

This will take the name very literally. So literally, in fact, that you can no longer rely
on Oracle's typical case-insensitivity.

SQL> drop table "123TABLE";


drop table "123TABLE"
*
ERROR at line 1:

http://thinkoracle.blogspot.com/2005_06_01_archive.html (4 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

ORA-00942: table or view does not exist

You can also use quotes to use reserved words.

SQL> CREATE TABLE "TABLE" ("NUMBER" NUMBER);

Table created.

// posted by Robert Vollman @ Monday, June 27, 2005 0 comments

Friday, June 24, 2005


Oracle Client
Here are the simple steps required for setting up an Oracle Client on a PC.

You will need:


- A working Oracle Server :)
- A compatible Oracle Client
- The service name, domain name, host name and port

1. Install Oracle SQL*Plus client on your PC

This should be quick and easy, accept all defaults.

2. Modify %ORACLE_HOME%\network\admin\tnsnames.ora

SRV_NAME.WHATEVER.COM =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = host_name)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = srv_name)
)
)

3. Check %ORACLE_HOME%\network\admin\sqlnet.ora

NAMES.DEFAULT_DOMAIN = whatever.com
NAMES.DIRECTORY_PATH= (TNSNAMES, HOSTNAME)

4. Modify %ORACLE_HOME%\network\admin\listener.ora

http://thinkoracle.blogspot.com/2005_06_01_archive.html (5 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(ORACLE_HOME = C:\oracle\ora92)
(SID_NAME = srv_name)
)

5. Test connection

sqlplus username/password@srv_name

// posted by Robert Vollman @ Friday, June 24, 2005 0 comments

Thursday, June 23, 2005


PL/SQL Books
There are 3 PL/SQL books considered above the pack.

I settled on Scott Urman's book, but that's only because I got a deal on it when
Nexus Computer Books in Calgary went out of business. I like it, and it is ranked
#1 among PL/SQL books on Amazon.com.

Oracle9i PL/SQL Programming


Scott Urman
32.99
664 Pages
4 on 7 reviews
Rank in sales: #5460

I really like Steven Feuerstein's work, most of which can be found on the web. He's
got Q&A, Puzzlers, and regular articles on Oracle's site. You can find sample
chapters on-line. Despite the fact that I already have a good PL/SQL book, I might
get this one, too. He also has a "Best Practises" book.

Oracle PL/SQL Programming, Third Edition


Steven Feuerstein
34.62
1018 Pages
4 on 66 reviews
Rank in sales: #17659

Connor McDonald of the Oak Table Network has a highly rated PL/SQL book as
well. He also has an Internet presense. His site is awesome, he's got some great
stuff, so his book ought to be great, too. I wouldn't mind picking this up.

Mastering Oracle PL/SQL: Practical Solutions

http://thinkoracle.blogspot.com/2005_06_01_archive.html (6 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

Connor McDonald
32.99
648 Pages
4.5 on 5 reviews
Rank in sales: #106559

There are other PL/SQL books out there, but any of these 3 is probably your best
bet. Leave some comments if you have a preference for the 3, or know of any other
really great PL/SQL books to consider.

// posted by Robert Vollman @ Thursday, June 23, 2005 0 comments

Wednesday, June 22, 2005


Expert One-on-One
The general consensus is that Tom Kyte's "Expert One-on-One Oracle" is the best
Oracle book available, and most Oracle professionals have a copy on their shelves.

In Chapter 1 of the first edition, you'll see a scheduling algorithm that is supposed
to avoid double-bookings. Here is an example of how to double-book a room:

CREATE TABLE resources (resource_name VARCHAR2(25) primary key);


CREATE TABLE schedules (resource_name VARCHAR2(25) references resources,
start_time DATE, end_time DATE);

INSERT INTO resources (resource_name) VALUES ('Room A');


INSERT INTO schedules (resource_name, start_time, end_time) VALUES ('Room A',
'01-Jan-04', '04-Jan-04');

VARIABLE new_start_time VARCHAR2(32)


EXEC :new_start_time := '02-Jan-04'

VARIABLE new_end_time VARCHAR2(32)


EXEC :new_end_time := '03-Jan-04'

VARIABLE room_name VARCHAR2(25)


EXEC :room_name := 'Room A'

-- If the count comes back 0, the room is yours


SELECT COUNT (*) FROM schedules WHERE resource_name = :room_name
AND (start_time BETWEEN :new_start_time AND :new_end_time
OR
end_time BETWEEN :new_start_time AND :new_end_time);

This returns 0, which means the room is double-booked!!

Here is the fixed version from the 2nd edition:

http://thinkoracle.blogspot.com/2005_06_01_archive.html (7 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

ops$tkyte@ORA10GR1> select count(*)


2 from schedules
3 where resource_name = :room_name
4 and (start_time <= :new_end_time)
5 and (end_time >= :new_start_time);

According to Tom, "the only [other] notable fix is with regards to function based
indexes where I said erroneously that the to_date() function was "broken" with
respect to the YYYY format - it is not (can you see why :)"

Here it is:

CREATE TABLE t (y VARCHAR2(32));

CREATE INDEX t2 ON t(to_date(y,'yyyy'));


ORA-01743: only pure functions can be indexed.

As a workaround in the book, Tom created his own "to_date" function. But there is
a far simpler reason why this doesn't work (and a far simpler solution). Even
though it was staring us all in the very same pages, not very many people could
figure out why this function-based index was disallowed:

"My conclusion in the book is wrong because to_date with the 'yyyy' format is not
deterministic."

That means that for the same input, you can get a different output. But how can
that be?

ops$tkyte@ORA10GR1> select to_date( '2005', 'yyyy' ) from dual;

TO_DATE('
---------
01-JUN-05

"Today, in june, to_date(2005) returns 01-jun, last month, same function, same
inputs - would return 01-may"

Wow. Never would have guessed to_date(year) would be non-deterministic.

Tom also clarified that the following function would be deterministic and therefore
eligible for a function-based index:

create index t2 on t( to_date( '01'||y, 'mmyyyy') );

That, of course, would force it to choose January no matter what time of year you
called the function.

To me, it is very funny that to_date:


1. IS deterministic if you leave out the day (it will always choose the 1st day)
2. IS NOT deterministic if you leave out the month (it will not choose the 1st

http://thinkoracle.blogspot.com/2005_06_01_archive.html (8 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

month, but rather the current month).

Often in Oracle there is method behind the madness, but I do now know why there
is this difference.

So I guess this issue is just another interesting footnote in some nerd's blog...

// posted by Robert Vollman @ Wednesday, June 22, 2005 2 comments

Tuesday, June 21, 2005


Natural vs Synthetic keys
Primary keys should be:
1. Unique
2. Never changed (or very infrequently)

This is because they are used in other tables to reference a single row.

(Definitions from www.orafaq.com)


Natural Key: A key made from existing attributes.
Surrogate Key: A system generated key with no business value. Usually
implemented with database generated sequences.

This topic has been discussed at great length many times. We recently re-hashed it
on the Dizwell Forum.

Disadvantages:

EDIT: Please note: There are some potentially important corrections and
clarifications to the below. Please see Howard's comments and follow the links to
his blog or the forum discussion.

Natural keys:
- May require the concatentation of many columns, so it gets very long
- Sometimes a natural key can be hard to find (in example: names can change)
- In a sense, you are duplicating data
- Can lead to future conflicts when the database expands beyond original
requirements
- Care must be taken to avoid block-splitting
- Care must be taken to avoid index range scans
- Tend to change, albeit infrequently

"You nearly always end up having to append a number to guarantee both


uniqueness and existence. If I always have to append a guaranteed unique existing
number to ensure I meet my requirements, why not make it the key itself."
- Niall Litchfield

Synthetic/Surrogate keys:

http://thinkoracle.blogspot.com/2005_06_01_archive.html (9 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

- Meaningless by itself (ie. no relationship to the data to which it is assigned)


- Implementation is database-dependent
- Care must be taken to avoid contention (monotically increasing and smaller
indexes)
- Similar rows would not have similar keys

Gauss suggested considering using a GUID for the surrogate key. No trigger is
required, uniqueness is guaranteed over space and time, but it is 16 bytes.

SQL> CREATE TABLE atable (pk RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
2 a_str VARCHAR2(32));
Table created.
SQL> INSERT INTO atable (a_str) VALUES ('One');
1 row created.
SQL> INSERT INTO atable (a_str) VALUES ('Two');
1 row created.
SQL> SELECT * FROM atable;
PK A_STR
-------------------------------- --------------------------------
5C3BCF77D55B41E78DE4016DFBE25FFA One
D3B959F3010745D3854F8FC2B09A18F3 Two

// posted by Robert Vollman @ Tuesday, June 21, 2005 9 comments

Monday, June 20, 2005


Decode
Here is another handy Oracle-only SQL tool: DECODE.

Decode allows you to do if/elseif/else logic within an SQL query, similar to a CASE
WHEN statement in a PL/SQL procedure.

DECODE (expression, if_equal_to_this_1, give_me_this_1, else_if_equal_to_this_2,


give_me_this_2, ..., default)

Dan Morgan's Reference on DECODE:


http://www.psoug.org/reference/decode_case.html

The default value is optional, if it is left out, it defaults to NULL. And the maximum
number of comparisons is 255.

It works very much like a CASE WHEN statement, so you can already think of uses,
especially if you nest your DECODEs.

Remember the article I wrote on NULL vs Nothing and on NULLs in general?

http://thinkoracle.blogspot.com/2005_06_01_archive.html (10 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

http://thinkoracle.blogspot.com/2005/05/null-vs-nothing.html
http://thinkoracle.blogspot.com/2005/06/nulls-in-oracle.html

Well, you can actually use DECODE like NVL. Don't believe me? I don't blame you,
because I told you that NULL is not equal to NULL. But here is a quote right from
the Oracle 9i SQL Reference:

"In a DECODE function, Oracle considers two nulls to be equivalent. If expr is null,
then Oracle returns the result of the first search that is also null."

And here is the example because like me you don't believe anything without proof:

SQL> CREATE TABLE atable (avalue VARCHAR2(32));

Table created.

SQL> INSERT INTO atable (avalue) VALUES (NULL);

1 row created.

SQL> INSERT INTO atable (avalue) VALUES ('This is not NULL');

1 row created.

SQL> SELECT DECODE(avalue, NULL, 'This is NULL', avalue) avalue


2 FROM atable;

AVALUE
--------------------------------
This is NULL
This is not NULL

If you don't believe how useful it can be, here is a FAQ that shows how to use
DECODE for (among other things) avoiding divide-by-zero errors:

http://www.db.cs.ucdavis.edu/public/oracle/faq/decode.html

In practise, I have seen DECODE used for the ORDER BY clause.

If you are still not convinced, you can "Ask Tom" how DECODE can be used to have
a conditional foreign key. That is, a foreign key that only applies to certain rows!

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::
F4950_P8_DISPLAYID:1249800833250

// posted by Robert Vollman @ Monday, June 20, 2005 4 comments

Saturday, June 18, 2005

http://thinkoracle.blogspot.com/2005_06_01_archive.html (11 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

Connect By
I couldn't resist sharing this one, which I found on DBA-Support recently:

http://www.dbasupport.com/forums/showthread.php?t=47760

The question was how to create a column as the concatentation of many rows into
one, without using PL/SQL: just a single query.

Here is the example given:

CREATE TABLE t1 (col1 VARCHAR2(1));


INSERT INTO t1 VALUES ('a');
INSERT INTO t1 VALUES ('b');
INSERT INTO t1 VALUES ('c');
INSERT INTO t1 VALUES ('d');
INSERT INTO t1 VALUES ('e');

Desired result of an SQL statement on test:

abcde

The answer came from Tamil Selvan:

1 SELECT REPLACE(col1, ' ')


2 FROM (SELECT SYS_CONNECT_BY_PATH(col1,' ') col1, level
3 FROM t1
4 START WITH col1 = (select min(col1) from t1) -- 'a'
5 CONNECT BY PRIOR col1 < col1
6 ORDER BY level DESC)
7* WHERE rownum = 1
SQL> /

REPLACE(COL1,'')
----------------------------------------
abcde

Here are the things that may be new to someone new to Oracle (especially Oracle 9
or 10):
- SYS_CONNECT_BY_PATH
- CONNECT BY

This is an interesting example, but it is just one use of these features.

Here is a link to Dan Morgan's reference on CONNECT BY


http://www.psoug.org/reference/connectby.html

And here is an Ask Tom article.


http://www.oracle.com/technology/oramag/oracle/05-may/o35asktom.html

http://thinkoracle.blogspot.com/2005_06_01_archive.html (12 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

// posted by Robert Vollman @ Saturday, June 18, 2005 5 comments

Friday, June 17, 2005


Asking For Help
There are a lot of people who know Oracle. It makes sense to leverage their
abilities when you're stuck. Why re-invent the wheel?

First of all, often answers are easy to come by yourself. For example, here is Jeff
Hunter's suggestions on where to find answers:

http://marist89.blogspot.com/2005/06/where-can-i-find-help.html

If you want to reach a large body of Oracle professionals, the best approach is to
post it to a popular newsgroup or forum. Here are a few of my favourites.

Oracle Technology Network:


http://forums.oracle.com/forums/forum.jsp?forum=75

comp.databases.oracle.server:
http://groups-beta.google.com/group/comp.databases.oracle.server

DBA-Support:
http://www.dbasupport.com/forums/

Dizwell Forum:
http://www.phpbbserver.com/phpbb/viewforum.php?f=2&mforum=dizwellforum

It is tempting to contact certain professionals directly. After all, there are several of
them that spend seemingly hours answering questions in these forums, and
putting together web pages to assist fellow Oracle professionals.

But be aware that some of them do not have the time (or sometimes the interest)
in answering questions, like Mark Rittman or Duncan Mills.

http://www.rittman.net/archives/001276.html
http://www.groundside.com/blog/content/DuncanMills/
2005/06/16/Questions_Questions.html

And be aware that those that do like to receive questions may have a specific
method of submitting them, such as Tom Kyte and Steven Feuerstein:

http://asktom.oracle.com
http://www.oracle.com/technology/pub/columns/plsql/index.html

If you do ask someone a question, it sounds like these are the ground rules to
follow:

http://thinkoracle.blogspot.com/2005_06_01_archive.html (13 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

1. Don't even bother submitting urgent questions with time deadlines.


2. Even if English isn't your first language, try to make the question as clear as
possible.
3. Try to keep the question brief, but ...
4. Try to provide all necessary information, including examples and error messages
5. Don't ask questions that are obviously school assignments
6. Include "why" you are doing something.

http://tkyte.blogspot.com/2005/05/why.html

But the most important thing is:

Always try to find the answer yourself first!

Loosely Related:
http://vollman.blogspot.com/2005/04/roberts-tips-on-asking-for-help-1.html

// posted by Robert Vollman @ Friday, June 17, 2005 4 comments

Thursday, June 16, 2005


Common Table Column Types
I have two tables which are created in an SQL file, and I want to have a column in
common in both.

CREATE TABLE atable (atable_id VARCHAR2(32), atable_value NUMBER);


CREATE TABLE btable (btable_id VARCHAR2(32), btable_name VARCHAR2(32));

However, I don't want to have to rely on manual verification to make sure they are
the same type. And if I want to change them for a future version, I'd rather only
change it in one place.

I can't do this (abbreviated example):

CREATE TABLE atable (atable_id VARCHAR2(32));


SQL> CREATE TABLE btable (btable_id atable.atable_id%TYPE);
CREATE TABLE btable (btable_id atable.atable_id%TYPE)
*
ERROR at line 1:
ORA-00911: invalid character

And I can't do this:

CREATE OR REPLACE PACKAGE table_types


AS
SUBTYPE table_id IS VARCHAR2(32);
END;

http://thinkoracle.blogspot.com/2005_06_01_archive.html (14 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

SQL> CREATE TABLE atable (atable_id table_types.table_id);


CREATE TABLE atable (atable_id table_types.table_id)
*
ERROR at line 1:
ORA-00902: invalid datatype

So what should we do?

If there is a logical link between these two fields, we can use referential integrity
constraints (thanks "hsheehan"):

SQL>CREATE TABLE atable(atable_id VARCHAR2(32), atable_value NUMBER);

Table created.

SQL>ALTER TABLE atable ADD UNIQUE(atable_id);

Table altered.

SQL>CREATE TABLE btable(btable_id REFERENCES atable(atable_id), btable_name


VARCHAR2(32));

Table created.

However, this will require that every atable.atable_id be unique (ORA-02270), and
it will also require that every btable.btable_id exists in atable.atable_id (ORA-
02291)

This may not always be appropriate, because sometimes there is no such


relationships between columns. You may simply want all columns in a database
that are somehow similar (example: people's names) to be the same type. You may
be doing this for convenience or because you have common functions on these
columns.

In that case, you may need to resort to a 3rd-party schema modeller. After all,
that's what they're for.

Otherwise, you can create a file of tags, use these tags in a "pre-SQL" file, then
write a Perl script to do text substitutions to generate the SQL file. For example:

Tags.txt:
ID_TYPE VARCHAR2(32)
CreateTable.pre:
CREATE TABLE ATABLE (atable_id ID_TYPE, atable_value NUMBER);
CREATE TABLE BTABLE (btable_id ID_TYPE, btable_name VARCHAR2(32));
Execute your Perl script here
CreateTable.sql:
CREATE TABLE ATABLE (atable_id VARCHAR2(32), atable_value NUMBER);
CREATE TABLE BTABLE (btable_id VARCHAR2(32), atable_name VARCHAR2(32));

http://thinkoracle.blogspot.com/2005_06_01_archive.html (15 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

Thanks to the folks at the Dizwell Forum for helping me think this one through.
http://www.phpbbserver.com/phpbb/viewtopic.php?
t=179&mforum=dizwellforum&sid=6802

Here are some loosely related previous blogs on this:


http://thinkoracle.blogspot.com/2005/05/dynamically-assigning-size-of-
varchar2.html
http://thinkoracle.blogspot.com/2005/05/null-vs-nothing.html

// posted by Robert Vollman @ Thursday, June 16, 2005 0 comments

Wednesday, June 15, 2005


Variable Constraints
You can't use variables in constraints.

CREATE OR REPLACE PACKAGE test_constants IS


test_val CONSTANT NUMBER := 20;
END test_constants;

CREATE TABLE atable (


a_id NUMBER,
CONSTRAINT atable_test CHECK (a_id > test_constants.test_val)
);

ORA-00904: "TEST_CONSTANTS"."TEST_VAL": invalid identifier

Check Constraints can NOT contain subqueries, so forget about doing it that way.

It is basically only for comparisons and simple operations.

How about this convoluted way of achieving the goal. Create a trigger that will
check the value upon insert or update, and then trigger a special constraint.

SQL> CREATE TABLE atable (


2 a_id NUMBER,
3 a_error NUMBER,
4 CONSTRAINT id_too_high CHECK (a_error <> 1)
5 );

Table created.

SQL> CREATE OR REPLACE TRIGGER atable_trig


2 BEFORE INSERT OR UPDATE OF a_id ON atable FOR EACH ROW
3 BEGIN
4 IF :new.a_id > test_constants.test_val THEN :new.a_error := 1;
5 END IF;

http://thinkoracle.blogspot.com/2005_06_01_archive.html (16 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

6 END;
7/

Trigger created.

SQL> INSERT INTO atable (a_id) VALUES (1);

1 row created.

SQL> INSERT INTO atable (a_id) VALUES (21);


INSERT INTO atable (a_id) VALUES (21)
*
ERROR at line 1:
ORA-02290: check constraint (SCOTT.ID_TOO_HIGH) violated

Check the comments to see if someone has a better way.

Related links:
http://thinkoracle.blogspot.com/2005/05/enum-in-oracle.html

// posted by Robert Vollman @ Wednesday, June 15, 2005 1 comments

Tuesday, June 14, 2005


Bind Variables in PL/SQL
If you learn nothing else from the Oracle experts out there but want to improve
your Oracle application development knowledge, then read up on bind variables.

Bind variables are already very well explained, here are my favourite links on the
subject:

Mark Rittman's Bind Variables Explained


http://www.rittman.net/archives/000832.html

Tom Kyte is one of the champions of using Bind Variables. Links to his articles and
books can be found at the bottom of Mark's article.

After reading these articles, I understood that PL/SQL automatically binds


variables, so you really don't have to worry. But I was still concerned that I might
be missing something.

Tom has a query that you can run to determine if you are currently using bind
variables or not. Find it here (Hint: select sql_test from v$sqlarea):
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::
F4950_P8_DISPLAYID:1163635055580.

I posted the following question to the Dizwell forum, which is an excellent place to
tap the minds of Oracle gurus directly.

http://thinkoracle.blogspot.com/2005_06_01_archive.html (17 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

http://www.phpbbserver.com/phpbb/viewtopic.php?t=169&mforum=dizwellforum

Is there any possible way to NOT use bind variables in a PL/SQL stored procedure
WITHOUT using 'execute immediate' or DBMS_SQL package?

I just want to make sure that there are only 2 situations I have to look out for in
my PL/SQL code with regards to bind variables.

A developer from Australia going by "gamyers" responded with ref cursors:

DECLARE
v_cur sys_refcursor;
BEGIN
OPEN v_cur FOR 'select 1 from dual where 1=2';
CLOSE v_cur;
END;

Also, you could code


IF v_value =1 then
select ... where col_a = 1;
ELSIF v_value = 2 then
select ... where col_a = 2;
....

But with that sort of code you are probably dealing with a very small set of SQL
statements and are specifically wanting different plans etc.

And the champion himself, Tom Kyte, had this reply and defined some new terms:
"Overbind" and "Underbind." Using these terms I was asking whether it was
possible to "Underbind" using PL/SQL.

The only way to improperly bind in PL/SQL is when you use dynamic sql.

Else, you can "overbind" -- bind when you didn't need to, but you cannot
"underbind", not binding when you should!

eg:

for x in ( select * from all_objects where object_type = 'TABLE' )


loop

is perfectly ok, you do NOT need to:

declare
l_otype varchar2(25) := 'TABLE';
begin
for x in ( select * from all_objects where object_type = l_otype )
loop

http://thinkoracle.blogspot.com/2005_06_01_archive.html (18 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

You do not need to bind 'TABLE' in that query since no matter how many times you
run that query, it'll be 'TABLE' over and over.

But with static SQL, it's not possible to "underbind"

As an aside, visit Jeff Hunter's Oracle blog, which is fast becoming one of my
favourites. Here is his recent post on where Oracle DBAs can get help:
http://marist89.blogspot.com/2005/06/where-can-i-find-help.html

// posted by Robert Vollman @ Tuesday, June 14, 2005 0 comments

Monday, June 13, 2005


Blank Lines and SQLPlus
Try creating the following table using SQLPlus Worksheet.

create table atable (

aint integer

);

You will get this error:

SP2-0734: unknown command beginning "aint integ..." - rest of line ignored.

It thinks "aint integer" is a new command. What is the problem? Repeat this test
using SQLPlus at a prompt:

SQL> create table atable


2(
3
SQL>

The blank line stops the statement.

This doesn't apply to all statements, but it does apply to select/insert/update/


delete queries. It doesn't apply to creating procedures:

SQL> CREATE OR REPLACE PROCEDURE MyProc


2
3 AS
4
5 BEGIN
6
7 NULL;
8
9 END;

http://thinkoracle.blogspot.com/2005_06_01_archive.html (19 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

10 /

Procedure created.

At first I just made the blank lines a comment:

create table atable (


--
aint integer
--
);

Table created.

But eventually I took a closer look and arrived at the correct solution. Here it is.

set sqlblanklines on;

SQL> create table atable


2(
3
4 aint integer
5
6 );

Table created.

Its just a little SQLPlus foible.

If you see something similar and you aren't using blank lines, see if you're using
any special symbols and look at "set sqlprefix" instead.

So what should we do?


1. Put in comments to avoid the blank lines.
2. Use something other than sqlplus.
3. Explicitly set blanklines on at the top of your statement.

// posted by Robert Vollman @ Monday, June 13, 2005 1 comments

Friday, June 10, 2005


NULLs in Oracle
If you read only one sentence per posting, read this:

NULLs may not behave as you'd expect in Oracle, and as a result, NULLs are the
cause of many application errors.

I got a fair bit of private feedback on my recent article on the differences between

http://thinkoracle.blogspot.com/2005_06_01_archive.html (20 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

"NULL" and nothing. Here is the link to the original article, and check out Howard
Rogers' comments.

http://thinkoracle.blogspot.com/2005/05/null-vs-nothing.html

Let's start with an example to demonstrate a simple property of NULL: that NULL is
not equal to anything, including NULL itself.

SELECT * FROM dual WHERE NULL = NULL;

No rows selected.

SELECT * FROM dual WHERE NULL <> NULL;

No rows selected.

What happened here? How can something be both not equal and not not equal to
something else at the same time? That probably doesn't make much sense, does it?

Essentially NULL means you don't know the value. Basically, you can't say whether
its equal or not equal to anything else. You need to abandon the binary logic you
learned in first-year math and embrace tri-value logic.

That was also a clear demonstration of how you should be careful using equals or
not equals when dealing with NULLs. Instead, use "IS". Observe:

SELECT * FROM dual WHERE NULL IS NULL;

D
-
X

As an aside, you may be wondering what the heck "dual" is. And what do we do
when we have a question? We ask Tom!

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::
F4950_P8_DISPLAYID:1562813956388

In my mind, dual is simply a table with a single row that is guaranteed to be there.
And when you use it, it makes you look clever because that's what the experts
use. :)

While I'm blowing your mind with the behaviour of NULL, check out this other case,
kindly provided by Tom Kyte:

IF (x = 'A') THEN something


ELSE something else
END IF;

IF NOT(x = 'A') THEN something else

http://thinkoracle.blogspot.com/2005_06_01_archive.html (21 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

ELSE something
END IF;

Do these two pieces of pseudo-code look the same to you? In many languages,
yes. But not in PL/SQL. Why?

Consider the case that x is NULL. In the first case it will do "something else"
because it is not equal to 'A'. In the second case it will do "something" because it is
also not not equal to 'A'.

Tom knows I never believe anything without proof, so he provided me with one:

ops$tkyte@ORA9IR2> declare
2 x varchar2(1);
3 begin
4 if ( x = 'A' )
5 then
6 dbms_output.put_line( 'X=A' );
7 else
8 dbms_output.put_line( 'NOT X=A' );
9 end if;
10
11 if NOT( x = 'A' )
12 then
13 dbms_output.put_line( 'NOT X=A' );
14 else
15 dbms_output.put_line( 'X=A' );
16 end if;
17 end;
18 /
NOT X=A
X=A

PL/SQL procedure successfully completed.

Pretty bizarre, eh? Starting to understand the behaviour of NULL? Starting to see
why misunderstanding NULL can lead to application errors?

While we are discussing NULLs, here a few more useful things.

First, you can use the "set null" command to change how NULL will appear in
SQLPLUS. This will not change anything in the database, or equality, it will just
change the appearance.

create table atable (last_name varchar(12));


insert into atable (last_name) values ('Smith');
insert into atable (last_name) values (NULL);

select * from atable;

http://thinkoracle.blogspot.com/2005_06_01_archive.html (22 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

LAST_NAME
------------
Smith

2 rows selected.

set null [NULL];

select * from atable;

LAST_NAME
------------
Smith
[NULL]

2 rows selected.

Also, you can use these two functions, nvl and nvl2:

nvl(expr_1, expr_2)
Returns expr_2 if expr_1 is null and expr_1 otherwise.

nvl2(expr_1, expr_2, expr_3)


Returns expr_3 if expr_1 is null and expr_2 otherwise.

select nvl(last_name, '[NONE]') as last_name from atable;


LAST_NAME
------------
Smith
[NONE]

2 rows selected.

select nvl2(last_name, 'Y: ' || last_name,'N') as last_name from atable;

LAST_NAME
---------------
Y: Smith
N

2 rows selected.

Those of you who, like me, work on many different databases have hopefully seen
by now that NULLs are handled differently in Oracle. As a final demonstration,
consider how NULLs are handled in Sybase ASE.

In Sybase ASE (and MS SQL), there is a configuration parameter that tells the
database whether to treat NULLs as they are defined in the ANSI SQL standard, or

http://thinkoracle.blogspot.com/2005_06_01_archive.html (23 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

whether to "bend the rules" a bit, and allow "NULL = NULL" to be true.
Furthermore, the behaviour changes depending on whether you're in a join clause
or a search clause.

http://sybasease.blogspot.com/2005/05/nulls-in-sybase-ase.html

That is not the case in Oracle. As confusing as NULLs may be at first, they are
consistent. They will behave the same logically everywhere no matter how and
where you use them.

So what should we do?


1. Understand that "NULL = NULL" and "NULL <> NULL" are both false because
NULL means "I don't know"
2. Use "IS NULL" instead of "= NULL" if you are checking for NULLness.
3. Use "nvl" and "nvl2" if you want to eliminate the possibility of a NULL in a
statement by assigning it a (temporary) value.

For future reference, consult Dan Morgan's page on NULL:


http://www.psoug.org/reference/null.html

This is definitely not the last article you'll see on NULL given how often it is
misunderstood. I encourage you to include your own experiences of your favourite
NULLisms in the "comments" section. And, naturally, I appreciate corrections and
clarifications.

And as a final thanks to Tom, here are some pictures from when he visited us in
Calgary this past March.
http://www.coug.ab.ca/events/05-mar.htm

// posted by Robert Vollman @ Friday, June 10, 2005 9 comments

About Me
Name: Robert Vollman
Location: Calgary, Alberta, Canada

I was born and raised in Ottawa, and have lived in Calgary since 1991. I like
playing sports (hockey, soccer, ultimate, basketball, you name it) and military
board games. I also enjoy reading, walking, and playing with my 2 cats Lilly and Brutus. I'm a
database application specialist, whatever that is.

View my complete profile

http://thinkoracle.blogspot.com/2005_06_01_archive.html (24 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

Best Links
● Ask Tom Kyte
● Oracle Docs
● Dan Morgan and PSOUG
● Steven Feuerstein
● Jonathan Lewis
● FAQ
● Connor McDonald
● The Oak Table
● Cary Millsap and Hotsos
● Steve Adams and Ixora
● Anjo Kolk and OraPerf
● Dizwell Oracle Wiki
● My Personal Blog

Aggregators
Brian Duff's OraBlogs

❍ Eddie Awad's OracleNA


❍ Pete Finnigan's Aggregator
❍ Oracle's Bloglist
❍ Oracle Base Aggregator

Top Blogs
❍ Oracle's Ask Tom Kyte
❍ Oracle Guru Jonathan Lewis
❍ Blogger of the Year Eddie Awad
❍ Data Warehouser David Aldridge
❍ Oracle Geek Lewis Cunningham
❍ Database Expert James Koopmann
❍ Dizwell's Howard Rogers
❍ Oracle Master Laurent Schneider
❍ Security Expert Pete Finnigan
❍ Oracle Award Winner Mark Rittman
❍ Doug Burns
❍ Oracle ACE of the Year Dr. Tim Hall
❍ UKOUG's Andrew (Arfur C.) Clarke
❍ Newbie DBA Lisa Dobson
❍ Coffee-Drinking DBA Jon Emmons
❍ Chris Foot

http://thinkoracle.blogspot.com/2005_06_01_archive.html (25 of 26)1/9/2008 2:49:31 AM


OracleBlog: June 2005

❍ The Pythian DBA Team Blog


❍ DBA Don Seiler
❍ DBA Coskan Gundogar
❍ Oracle WTF

ARCHIVES
❍ LIST ALL ARTICLES
❍ May 2005
❍ June 2005
❍ July 2005
❍ August 2005
❍ September 2005
❍ October 2005
❍ November 2005
❍ December 2005
❍ January 2006
❍ February 2006
❍ March 2006
❍ April 2006
❍ May 2006
❍ June 2006
❍ July 2006
❍ August 2006
❍ September 2006
❍ October 2006
❍ November 2006
❍ December 2006
❍ January 2007
❍ February 2007
❍ March 2007
❍ April 2007
❍ May 2007
❍ June 2007
❍ October 2007

❍ Current Posts

http://thinkoracle.blogspot.com/2005_06_01_archive.html (26 of 26)1/9/2008 2:49:31 AM


OracleBlog: July 2005

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Friday, July 29, 2005


Oracle By Example
I would like to elaborate on one point from my recent blog on Using
Views:

http://thinkoracle.blogspot.com/2005/07/use-views.html

The example in question is a recent case where I used Views to very


easily perform a complex query.

Let's set it up. We have a simple company with expenses and


revenues broken up by type and department. I'm ignoring many
columns/constraints and the expensetype table for simplicity.

CREATE TABLE department (


dept_name VARCHAR2(32) PRIMARY KEY,
dept_description VARCHAR2(64)
);
CREATE TABLE expenses (
dept_name REFERENCES department(dept_name),
expense_type VARCHAR2(32),
expense_description VARCHAR2(64),
expense_amount NUMBER(10,2)
);
CREATE TABLE revenues (
dept_name REFERENCES department(dept_name),
revenue_type VARCHAR2(32),

http://thinkoracle.blogspot.com/2005_07_01_archive.html (1 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

revenue_description VARCHAR2(64),
revenue_amount NUMBER(10,2)
);

Okay now I'd like to insert a little sample data so we can test some
queries

INSERT INTO department VALUES ('DEPT_A', 'Expenses Only');


INSERT INTO department VALUES ('DEPT_B', 'Revenues Only');
INSERT INTO department VALUES ('DEPT_C', 'Expenses and
Revenues');
INSERT INTO department VALUES ('DEPT_D', 'No Expenses Nor
Revenues');

INSERT INTO expenses VALUES ('DEPT_A', 'TYPE_1', 'Expense 1',


10.00);
INSERT INTO expenses VALUES ('DEPT_A', 'TYPE_2', 'Expense 2',
12.50);
INSERT INTO expenses VALUES ('DEPT_C', 'TYPE_1', 'Expense 3',
44.90);
INSERT INTO expenses VALUES ('DEPT_C', 'TYPE_3', 'Expense 4',
92.75);

INSERT INTO revenues VALUES ('DEPT_B', 'TYPE_1', 'Revenue 1',


14.60);
INSERT INTO revenues VALUES ('DEPT_B', 'TYPE_1', 'Revenue 2',
15.80);
INSERT INTO revenues VALUES ('DEPT_C', 'TYPE_4', 'Revenue 3',
47.75);
INSERT INTO revenues VALUES ('DEPT_C', 'TYPE_5', 'Revenue 4',
6.15);

We want a query that will show us every department, and its total
expenses and revenues. We want dept_name, sum(expenses), sum
(revenues), regardless of type.

Doing a single sum would be easy, we could just "GROUP BY" a


particular column. Even if we wanted to add dept_description, we
could just use Connor McDonald's trick:

http://thinkoracle.blogspot.com/2005/07/extra-columns-in-
group-by.html

http://thinkoracle.blogspot.com/2005_07_01_archive.html (2 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

For simplicity, by the way, we won't include dept_description - we


know we can using that technique.

Go ahead and write the query. I'm sure its possible! But not
everyone can figure it out, you might wind up with something really
complex.

So how will views help us? Well, we can create views that give us the
sum for expenses and values:

CREATE VIEW expensesview AS


SELECT dept_name, sum(expense_amount) expense_sum
FROM expenses
GROUP BY dept_name;
CREATE VIEW revenuesview AS
SELECT dept_name, sum(revenue_amount) revenue_sum
FROM revenues
GROUP BY dept_name;

Nothing could be easier. That is also some pretty handy views to


have. As you recall, a view can be thought of as a "virtual table" or
as a stored query. A stored query we are about to put to use.

SELECT d.dept_name, e.expense_sum, r.revenue_sum


FROM department d, expensesview e, revenuesview r
WHERE d.dept_name = e.dept_name
AND d.dept_name = r.dept_name;

Here are the results ... oops!

DEPT_NAME EXPENSE_SUM REVENUE_SUM


-------------------------------- ----------- -----------
DEPT_C 137.65 53.9

Why did we only get DEPT_C? Because, of course, either


expense_sum or revenue_sum was NULL in the other 3
departments. I'm only showing this mistake so I can show the

http://thinkoracle.blogspot.com/2005_07_01_archive.html (3 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

application of an outer join. An outer join will give you all possible
rows. Just add a (+) next to the column you're joining on.
Symbolically that means you want to add (+) rows where none exist.

SELECT d.dept_name, e.expense_sum, r.revenue_sum


FROM department d, expensesview e, revenuesview r
WHERE d.dept_name = e.dept_name(+)
AND d.dept_name = r.dept_name(+);
DEPT_NAME EXPENSE_SUM REVENUE_SUM
-------------------------------- ----------- -----------
DEPT_A 22.5
DEPT_B 30.4
DEPT_C 137.65 53.9
DEPT_D

Perfect.

We could have done this without views. Indeed, we could have


embedded the simple queries we used to make the views directly
into this final query. Maybe in an example as simple as this that
would be ok. But these kinds of things can get complex. Plus, now
other queries can take advantage of those views.

As a final note, how do you figure we can replace the NULLs up


there with zeros? The answer is something like DECODE or NVL.

http://thinkoracle.blogspot.com/2005/06/nulls-in-oracle.html

SELECT d.dept_name,
NVL(e.expense_sum,0) tot_expense,
NVL(r.revenue_sum,0) tot_revenue
FROM department d, expensesview e, revenuesview r
WHERE d.dept_name = e.dept_name(+)
AND d.dept_name = r.dept_name(+);
DEPT_NAME TOT_EXPENSE TOT_REVENUE
-------------------------------- ----------- -----------
DEPT_A 22.5 0
DEPT_B 0 30.4
DEPT_C 137.65 53.9
DEPT_D 0 0

http://thinkoracle.blogspot.com/2005_07_01_archive.html (4 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

// posted by Robert Vollman @ Friday, July 29, 2005 0 comments

Tuesday, July 26, 2005


Use Constraints
I was ready to explain to you why you should take advantage of
Oracle's ability to manage the integrity of your data rather than rely
on your applications, but I found a much better explanation in the
Oracle Data Warehousing Guide. Read the section "Why Integrity
Constraints are Useful in a Data Warehouse" in Chapter 7 on
"Integrity Constraints."

So instead, let me give you a just a really quick primer from my own
experience, and a couple of treats.

There are many types of constraints, including primary key, unique,


referential (foreign key) and check constraints. I'll talk about check
constraints.

There are basically three ways to set up your table constraint. Check
a reference (like Dan Morgan's http://www.psoug.org/reference/
constraints.html) for more detail, but I will review them here.

1. On the Same Line

CREATE TABLE ConstraintTable (


MyNumber NUMBER(1) CHECK (MyNumber < 5)
);

Using this method (only), you can't reference other columns in the
table in your check constraint. Try it:

CREATE TABLE ConstraintTable (


MyNumber1 NUMBER(1),
MyNumber2 NUMBER(1) CHECK (MyNumber2 > MyNumber1)
);

ORA-02438: Column check constraint cannot reference other


columns

It is also not obvious what name the constraint takes so it's more
difficult to alter it later. But here is how:

http://thinkoracle.blogspot.com/2005_07_01_archive.html (5 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

SQL> SELECT constraint_name


2 FROM user_constraints
3 WHERE table_name = 'CONSTRAINTTABLE';

CONSTRAINT_NAME
------------------------------
SYS_C007536

2. During table creation

Example:

CREATE TABLE ConstraintTable (


MyNumber NUMBER(1)
CONSTRAINT c_my_number CHECK (MyNumber < 5)
);

Doing it this way allows you to reference other columns in the table:

SQL> CREATE TABLE ConstraintTable (


2 MyNumber1 NUMBER(1),
3 MyNumber2 NUMBER(1),
4 CONSTRAINT c_my_number CHECK (MyNumber2 > MyNumber1)
5 );

3. Alter table

You can create your table as normal, and then add your constraints
separately. I don't think there is any actual difference to Oracle
between method #2 and #3.

CREATE TABLE ConstraintTable (MyNumber Number(1));

ALTER TABLE ConstraintTable ADD CONSTRAINT c_my_number


check (MyNumber < 5);

There is actually a 4th way, kind of. See, CHECK constraints can not
include sub-queries, and you can't reference other tables in them.
You also can't use package-defined constants or variables. All you
can basically do is simple things, like <>=, and [not] between/in/
like/equals

I get around all of this by using triggers. I add a simple constraint to


the table (possibly a "NOT NULL", if applicable) and then write a
trigger which will do my check - referencing other tables, writing

http://thinkoracle.blogspot.com/2005_07_01_archive.html (6 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

subqueries and using package-defined constants as I please - and


then deliberately set off the simple constraint.

Of course, this may look silly to a user, who gets an error on


inserting a row with a NULL value when it clearly isn't NULL. So I
usually write something to a log, or name my simple constraint, and
I certainly document the source code. But that's a topic for another
day.

Here is an article where I describe the concept in more detail,


picking especially on using variables in constraints. But apply the
same logic for complex integrity constraints when you want to
reference other tables.

http://thinkoracle.blogspot.com/2005/06/variable-constraints.html

Ok, let me wrap it up by saying that one of the other advantages of


constraints is that you can disable them when you need to:

SQL> INSERT INTO ConstraintTable (MyNumber) VALUES (6);

ORA-02290: check constraint (SYS.SYS_C007536) violated

(By the way, that's the other way to find out the name of your
constraint: violate it!)

SQL> ALTER TABLE ConstraintTable DISABLE CONSTRAINT


SYS_C007536;

SQL> INSERT INTO ConstraintTable (MyNumber) VALUES (6);

And you're ok! Of course, you better make sure the data is ok by the
time you turn it back on, or you'll get this error:

SQL> ALTER TABLE ConstraintTable ENABLE CONSTRAINT


SYS_C007536;

ORA-02293: cannot validate (SYS.SYS_C007536) - check constraint


violated

Which is a great segue into my closing, which includes two of my


favourite discussions on disabling and deferring constraints. Check
them out:

Jeff Hunter

http://thinkoracle.blogspot.com/2005_07_01_archive.html (7 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

http://marist89.blogspot.com/2005/06/deferrable-constraints_29.
html

Doug Burns
http://doug.burns.tripod.com/oracle/index.blog?entry_id=1170846

// posted by Robert Vollman @ Tuesday, July 26, 2005 2 comments

Monday, July 25, 2005


Use Views
Very often the solution to a problem involves using a view. Use
Views!

What is a View?

Most people think of a view either as a stored, named query, or as a


"virtual table."

Here are two definitions from Oracle, along with references to the
key documents on Views to review.

"A logical representation of a table or combination of tables."


- Oracle Application Developer's Guide, Section 2.11 (Views)

"A view takes the output of a query and presents it as a table."


- Oracle Concepts Guide, Section 10.16 (Views)

How do you create a View?

Nothing could be easier. Here:

CREATE OR REPLACE VIEW MyView AS


(Insert Query Here!)

For more, you can always reference Dan Morgan's library:


http://www.psoug.org/reference/views.html

How do I use Views?

Treat it just like a table. You can query them, as well as insert,
update and delete*. Bear in mind that these actions will update the
base table(s). Likewise, any changes to the base table(s) will
automatically update the View*.

http://thinkoracle.blogspot.com/2005_07_01_archive.html (8 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

*This is true in general. Some Views can't be updated, and you can
make a View READONLY.

Here is how to tell what Views exist:

SELECT view_name FROM user_views;

Here is how to tell what the View is:

SELECT text FROM user_views WHERE view_name = 'MyView';

Why are they useful?

I use them for many reasons, here are the most common situations
where I will advocate their use:

1. Denormalizing the database

Sometimes its nice to pull related data from several tables into a
single table. Using views allows you to satisfy both the Fabian
Pascalesque relational database purist, and the pragmatic user.

2. Making things look better

For example, you can use a view to substitute a generic ID number


with the name of the individual. You can leave out columns that are
rarely interesting. You can use a view to add information that is
derived from other data, for example figure out everyone's salary in
Canadian dollars in an international organisation.

3. Complex queries/query simplification

You might have several queries that have to perform similar logic.
You can just create a view for that logic, and make the queries far
simpler. Also, when I can't figure out how to write a really complex
query, sometimes I just create views as intermediate steps.

For example, say you have a table of expenses, with "department",


"type" and "total", a revenue table with the same columns, and a
department table. Now you have to put together a query that shows
each department, and their total expenses and revenues, regardless
of type.

Rather than write a really complex query, just write a view (or two)
that contains the sum of the expenses and revenues, by

http://thinkoracle.blogspot.com/2005_07_01_archive.html (9 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

department. Then you can create a query to put them all into a
single row by (outer) joining on those views. Simple!

4. Restrict access to a column or row

Say you want a user to have access to only part of a table (either by
row or column). Here's what you do: restrict his access to the table
completely, then create a view that contains the information the
user is allowed to access, and then grant that user access to the
view.

5. Rename a column

Create a view which is exactly like the table, but with the column
renamed. That is really easy, and it will save you from having to
possibly update lots of other tables or applications because you left
the base table alone. No, you can't write indexes on views, but
queries get optimized as normal, and it will use the base table's
indexes at that time.

6. Change schema, but still support an old version

Just like renaming a column. You can completely re-design your


database schema, but create views to support legacy applications
who still rely on the structure and naming of the original. That will
save a lot of hassle.

I will close with a really interesting aspect of Views.

SQL> CREATE TABLE BaseTable (MyNumber NUMBER(1));

Table created.

SQL> INSERT INTO BaseTable (MyNumber) VALUES (1);

1 row created.

SQL> CREATE VIEW MyView AS SELECT * FROM BaseTable;

View created.

SQL> ALTER TABLE BaseTable ADD (MyString VARCHAR2(32));

Table altered.

SQL> INSERT INTO BaseTable (MyNumber, MyString) VALUES (2,

http://thinkoracle.blogspot.com/2005_07_01_archive.html (10 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

'Hello');

1 row created.

SQL> SELECT * FROM MyView;

MYNUMBER
----------
1
2

SQL> SELECT * FROM BaseTable;

MYNUMBER MYSTRING
---------- --------------------------------
1
2 Hello

The View is NOT updated when the BaseTable is, even when you
SELECT *. When you write SELECT * the view chooses its columns
then and there.

// posted by Robert Vollman @ Monday, July 25, 2005 7 comments

Saturday, July 23, 2005


Oracle BOOLEAN
There is no BOOLEAN datatype in Oracle, as far as tables are
concerned.

CREATE TABLE BooleanTable (MyBool BOOLEAN);

ORA-00902: invalid datatype

But there is a BOOLEAN datatype in PL/SQL.

CREATE OR REPLACE PROCEDURE BoolProc (in_bool IN BOOLEAN)


AS
my_bool BOOLEAN := TRUE;
BEGIN
IF (in_bool = my_bool) THEN
DBMS_OUTPUT.PUT_LINE('True');
ELSE
DBMS_OUTPUT.PUT_LINE('False or NULL');

http://thinkoracle.blogspot.com/2005_07_01_archive.html (11 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

END IF;

EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
END BoolProc;

Why is there no Boolean in Oracle for tables? What should we do


instead? This:

CREATE TABLE BoolTable (MyBool CHAR(1) CHECK (MyBool IN ( 'Y',


'N' )));

As for the first question, as usual, let's Ask Tom:

http://asktom.oracle.com/pls/ask/f?
p=4950:8:2109566621053828525::NO::F4950_P8_DISPLAYID,
F4950_P8_CRITERIA:6263249199595

// posted by Robert Vollman @ Saturday, July 23, 2005 7 comments

Thursday, July 21, 2005


Oracle Blogs
If you enjoy this blog, there may be other Oracle-related blogs you
will also enjoy reading. You may be surprised to learn just how
many good Oracle blogs are out there. I follow quite a few on a daily
or casual basis. Here are my favourites.

Brian Duff hosts OraBlogs, which picks up several of the below


Oracle blogs, so it can be a one-stop blog.
http://www.orablogs.com/orablogs/

Tom Kyte, respected author of "Ask Tom." Covers a pretty wide


spectrum of Oracle-related topics, including new things and "best
practises." This is on practically everyone's favourite blog list, and
every post gets dozens of comments.
http://tkyte.blogspot.com/

Niall Litchfield has one of the first Oracle blogs I read. He has
interesting posts on a variety of topics including htmldb, and Oracle

http://thinkoracle.blogspot.com/2005_07_01_archive.html (12 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

10g.
http://www.niall.litchfield.dial.pipex.com/

Howard Rogers is the master of the Dizwell Forum. The discussions


therein are generally the inspiration for his posts. His passionate
Oracle rants give his blog a lot of flavour.
http://www.dizwell.com/blogindex.html

David Aldridge, is an all-purpose Oracle warehouse specialist. I love


his posts on warehouse design and maintenance. He also posts
regularly about Oracle 10g and its features.
http://oraclesponge.blogspot.com/

Mark Rittman is a database warehouse developer and covers a lot of


stuff, like modelling. He has a link to all the Oracle blogs that are
out there (good or bad), so you can go through there and pick your
favourites.
http://www.rittman.net/

Jeff Hunter is an Oracle DBA with a relatively new blog. He posts a


wide variety of topics, and he is on a lot of people's favourites list.
http://marist89.blogspot.com/

Tim Hall is an Oracle DBA, designer and developer. Posts on a


variety of topics and is not shy about sharing his opinions. Despite
the fact that he doesn't use IDEs, he's one of the few people who
mention them.
http://oracle-base.blogspot.com/

Doug Burns, another Oracle DBA, reads and writes papers and
books. I count on him to post about the latest news and papers/
books of interest.
http://doug.burns.tripod.com/oracle/

Pete Finnigan, an Oracle security expert, provides the latest news of


bugs and security flaws. Even though I'm not into security that
much, I still enjoy his posts.
http://www.petefinnigan.com/weblog/entries

Eddie Awad, an Oracle application developer who posts interesting


things about Oracle as he finds them. Also talks about ColdFusion
and Biztalk occasionally. Has me in his blogroll! :)
http://awads.net/wp/

http://thinkoracle.blogspot.com/2005_07_01_archive.html (13 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

Peter Scott is a manager (!) in charge of an Oracle data warehouse.


As a result his posts are generally about the situation of the day,
which is usually of significance to everyone.
http://pjs-random.blogspot.com/

Lisa Dobson, an Oracle DBA whose brand new blog focuses on the
Newbie perspective.
http://newbiedba.blogspot.com/

Amis Technology Corner has a number of Oracle professionals from


various backgrounds that post on a variety of topics, including
Oracle-related events and publications, and various designs and
features.
http://technology.amis.nl/blog/

Mike Ault, a Burleson consultant and published author, posts on a


variety of Oracle-related topics related to his interesting adventures
while consulting. No comments allowed, ostensibly for legal reasons
but people posted a lot of corrections when they were allowed.
http://mikerault.blogspot.com/

Robert Freeman, another Burleson consultant and a 15-year Oracle


DBA, posts on a variety of Oracle-related topics of interest to DBAs,
including the types of problems he sees and solves and things he
finds in the latest releases.
http://robertgfreeman.blogspot.com/

If you know of any other Oracle-related blogs that you enjoy, please
add a Comment so I can check it out. Please spread the word of
these great blogs!

// posted by Robert Vollman @ Thursday, July 21, 2005 4 comments

Monday, July 18, 2005


Which instance am I in?
Here's an easy one a colleague asked me.

You are logged into your default session (example: sqlplus scott/
tiger with no @instance)

You want to know which instance you are logged into.

http://thinkoracle.blogspot.com/2005_07_01_archive.html (14 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

You can't query V$ tables directly, because you're not logged in as


SYS.

So while looking around at similar questions on Jonathan Lewis'


cooperative FAQ:
http://www.jlcomp.demon.co.uk/faq/MySessID.html

I saw SYS_CONTEXT. That looked like it would do the trick. So I


looked it up in my favourite reference, Dan Morgan's:
http://www.psoug.org/reference/sys_context.html

And came up with this:

SELECT SYS_CONTEXT(‘USERENV’,’DB_NAME’) FROM DUAL;

You can also get the 'INSTANCE' using this, but that doesn't do you
any good if you can't query the V$INSTANCE table.

That solves the problem, but I'm sure that's just one of many ways
to do it:

1. Some other queries on some system tables, and/or


2. Some command-line command, and/or
3. Some environment file somewhere.

Also, I know some people who put this directly into their sqlplus
prompt.

// posted by Robert Vollman @ Monday, July 18, 2005 1 comments

Thursday, July 14, 2005


Oracle Docs
We have seen articles on where to go for help, and how to ask for
help:

http://thinkoracle.blogspot.com/2005/06/asking-for-help.html

Recently Tom Kyte wrote an article on Reading the F'n Manual:

http://tkyte.blogspot.com/2005/07/rtfm.html

Which begs the F'n question. Where are the F'n manuals? Which

http://thinkoracle.blogspot.com/2005_07_01_archive.html (15 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

manuals should you F'n read?

The first question is easy, it's all here:

http://www.oracle.com/technology/documentation/index.html

Personally, I use Oracle9, so I have this page bookmarked:

http://www.oracle.com/technology/documentation/oracle9i.html

For the novice, you want to go to View Library and Getting Started

There you will find links for the Installer, the Administrator, and the
Developer. These links give you recommendations for which F'n
manuals to read.

Being an application developer the key F'n manual for me, without
dispute, is:

Oracle9i Application Developer's Guide - Fundamentals


http://download-west.oracle.com/docs/cd/B10501_01/
appdev.920/a96590.pdf

I won't include all the links, because a list of all F'n manuals for
Oracle9i can be found here:

http://www.oracle.com/pls/db92/db92.docindex?
remark=homepage

Here are the F'n manuals that are recommended for Application
Developers:

Oracle9i Database Concepts Guide


Oracle9i SQL Reference
Oracle9i Data Warehousing Guide
PL/SQL User's Guide and Reference
Oracle9i Supplied PL/SQL Packages and Types Reference
Oracle9i Database Performance Tuning Guide and Reference
Oracle9i Database Error Messages

Beyond that, there are also F'n manuals for more advanced
programming (Java, C++, XML, Object-Related).

Please feel free to leave me some F'n comments with other F'n good
manuals and books.

http://thinkoracle.blogspot.com/2005_07_01_archive.html (16 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

// posted by Robert Vollman @ Thursday, July 14, 2005 4 comments

Wednesday, July 13, 2005


Stored Procedure template
Since there was some interest in the "object" template,

http://thinkoracle.blogspot.com/2005/06/oop-in-plsql-yep.html

and since I've been dry on ideas lately because I haven't been
working on non-Oracle things the last week or two, I decided to
share another one of my templates. This time: stored procedures.
Enjoy!

SET SERVEROUTPUT ON;

-- 'NOCOPY' makes it a pointer (pass by reference) - faster.


-- 'DETERMINISTIC' means the output is the same for every input -
allows caching (for return type tables)
-- CREATE OR REPLACE FUNCTION MyFunc (p_something IN OUT
NOCOPY Transactions.number%TYPE)
-- RETURN BOOLEAN DETERMINISTIC
-- 'DEFAULT' is the same as ':=' for both here and DECLARE
CREATE OR REPLACE PROCEDURE MyProc (p_something IN
Transactions.number%TYPE DEFAULT 1)
-- The following says it is independent of anything calling it (eg:
rollbacks, etc)
-- IS PRAGMA AUTONOMOUS_TRANSACTION
AS
[[BlockName]]
-- If its an anonymous block:
-- DECLARE
v_datetime TIMESTAMP;
v_transaction Transactions.number%TYPE := 0;
v_the_date_is CONSTANT VARCHAR2(12) := 'The date is ';

-- Create an exception, the pragma is optional


v_my_exception EXCEPTION;
PRAGMA EXCEPTION_INIT(v_my_exception, 100);

-- subprograms (functions) MUST be declared last


PROCEDURE NothingReally IS BEGIN NULL; END NothingReally;

http://thinkoracle.blogspot.com/2005_07_01_archive.html (17 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

BEGIN
-- SET TRANSACTION READ ONLY; -- Use consistent snapshot of
the database
-- SET TRANSACTION READ WRITE; -- The default. Turns "off" the
Read Only
-- SET TRANSACTION ISOLATION LEVEL READ COMMITTED
-- SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
-- SET TRANSACTION USE ROLLBACK SEGMENT

-- This is a comment
SELECT systime INTO BlockName.v_datetime FROM dual;
DBMS_OUTPUT.PUT_LINE(v_the_date_is || v_datetime);

[[LoopName]]
IF 1=1
THEN NULL;
ELSIF 1=2
THEN RAISE NO_DATA_FOUND;
ELSE
THEN NothingReally;
END IF;

CASE
WHEN 1=1 THEN NULL;
-- Application Errors have to be -20000 to -20999 inclusive and
can't be caught specifically
WHEN 1=2 THEN RAISE_APPLICATION_ERROR(-20000, 'Error: '||
v_the_date_is||' BAH');
ELSE NULL;
END CASE;

LOOP
EXIT WHEN 1=1;
END LOOP;

FOR v_transaction IN 0 .. 10
LOOP
NULL;
END LOOP;

WHILE 1=2
LOOP
RAISE v_my_exception;
END LOOP;

http://thinkoracle.blogspot.com/2005_07_01_archive.html (18 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

COMMIT;
EXCEPTION
-- This only covers errors raised after BEGIN (but NOT in 'DECLARE'!)
-- You can "OR" exceptions.
-- An exception can't be in more than 1 block
WHEN v_my_exception
THEN NULL;
-- This is optional but good practice.
-- Unhandled exceptions fall through to the next block or statement
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
END MyProc;
/

// posted by Robert Vollman @ Wednesday, July 13, 2005 0 comments

Monday, July 11, 2005


Specifying INSERT Columns
Here is a quick one that I touched on briefly in one of my first blogs:

http://thinkoracle.blogspot.com/2005/05/null-vs-nothing.html

It can be important to specify which columns you plan on providing


values for in an INSERT statement. Repeating Dan Morgan's quote:

"By not specifying column names you are signifying that you are
providing values for ALL columns. This is why it is a very bad
practice as doing an ALTER TABLE ADD immediately invalidates all
SQL statements."

Here is an example. I created a table, and then wrote a procedure


that will insert a row WITHOUT specifying the values. Works fine if
the table doesn't change:

SET SERVEROUTPUT ON;

CREATE TABLE MyTable (MyInt NUMBER);

CREATE OR REPLACE PROCEDURE InsertIntoMyTable (InValue IN

http://thinkoracle.blogspot.com/2005_07_01_archive.html (19 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

NUMBER)
AS
BEGIN
DBMS_OUTPUT.PUT_LINE('Inserting ' || InValue || ' into MyTable');
INSERT INTO MyTable VALUES (InValue);
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);

END InsertIntoMyTable;
/

EXEC InsertIntoMyTable(1);
Inserting 1 into MyTable

PL/SQL procedure successfully completed.

So let's try modifying the table, and try again.

ALTER TABLE MyTable ADD (MyString VARCHAR2(32));

EXEC InsertIntoMyTable(2);
BEGIN InsertIntoMyTable(2); END;

*
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00905: object SCOTT.INSERTINTOMYTABLE is invalid
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored

The procedure fails, and can't recompile. Perhaps you want that
behaviour, because you want to require all your procedures to be
checked every time a related table has changed. But, then again,
maybe you don't.

In that case, modify the stored procedure to specify which value you
are inserting, and then you're good to go. Let's repeat this test that
way:

CREATE OR REPLACE PROCEDURE InsertIntoMyTable (InValue IN


NUMBER)
AS

http://thinkoracle.blogspot.com/2005_07_01_archive.html (20 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

BEGIN
DBMS_OUTPUT.PUT_LINE('Inserting ' || InValue || ' into MyTable');
INSERT INTO MyTable (MyInt) VALUES (InValue);
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);

END InsertIntoMyTable;
/

SQL> EXEC InsertIntoMyTable(2);


Inserting 2 into MyTable

PL/SQL procedure successfully completed.

SQL> ALTER TABLE MyTable ADD (MyOtherInt NUMBER);

Table altered.

SQL> EXEC InsertIntoMyTable(3);


Inserting 3 into MyTable

PL/SQL procedure successfully completed.

// posted by Robert Vollman @ Monday, July 11, 2005 0 comments

Tuesday, July 05, 2005


Regular Expressions in Oracle
I was recently asked to do a blog about Regular Expressions in
Oracle 10, because they were cool.

They are cool.

Except to people that get spooked by a bunch of [:whatever:] in


their code, and feel their lunch come up when they see '[^:]+,\?.{3}
(tip: if that is you, don't ever read Perl code).

Anyway I can not do a blog on Regular Expressions in Oracle 10 for


two reasons:

1. I only blog about what I'm currently working on and studying, and

http://thinkoracle.blogspot.com/2005_07_01_archive.html (21 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

2. I use Oracle 9.

But no worries. There is a great article on Oracle Regular


Expressions:

http://www.oracle.com/technology/oramag/webcolumns/
2003/techarticles/rischert_regexp_pt1.html

Hmph, looks like I blogged about Oracle Regular Expressions after


all.

Oh yes, and here is your Regular Expression reference, courtesy of


(who else) Dan Morgan:

http://www.psoug.org/reference/regexp.html

He covers REGEXP_INSTR, REGEXP_LIKE, REGEXP_REPLACE,


REGEXP_SUBSTR.

// posted by Robert Vollman @ Tuesday, July 05, 2005 3 comments

Monday, July 04, 2005


SQLCODE and SQLERRM in INSERTs
Here is an interesting foible. Normally you can build strings on the
fly from functions and insert them into a table. Like so:

CREATE TABLE LogTable (logString VARCHAR2(128));

CREATE OR REPLACE FUNCTION MyFunc RETURN VARCHAR2


AS
BEGIN
RETURN 'Hello';
END;

CREATE OR REPLACE PROCEDURE MyProc


AS
BEGIN
NULL;
EXCEPTION
WHEN OTHERS
THEN
INSERT INTO LogTable (logString) VALUES (MyFunc || ' ' || MyFunc);

http://thinkoracle.blogspot.com/2005_07_01_archive.html (22 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

END;

But you can't do this with SQLCODE and SQLERRM.

CREATE OR REPLACE PROCEDURE MyProc


AS
BEGIN
NULL;
EXCEPTION
WHEN OTHERS
THEN
INSERT INTO LogTable (logString) VALUES (SQLCODE || ' ' ||
SQLERRM);
END;

PL/SQL: ORA-00984: column not allowed here

You can always put the values in a string for a workaround.

CREATE OR REPLACE PROCEDURE MyProc


AS
errString LogTable.logString%TYPE;
BEGIN
NULL;
EXCEPTION
WHEN OTHERS
THEN
errString := SQLCODE || ' ' || SQLERRM;
INSERT INTO LogTable (logString) VALUES (errString);
END;

Procedure created.

For reference, look up SQLCODE and SQLERRM in the PL/SQL User's


Guide and Reference.

Bonus. I found the following blog while reviewing OraBlogs:


http://blog.niftypaint.nl/

Which pointed me to Eddie Awad's great blog:


http://awads.net/wp/

Enjoy!

http://thinkoracle.blogspot.com/2005_07_01_archive.html (23 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

// posted by Robert Vollman @ Monday, July 04, 2005 5 comments

Friday, July 01, 2005


Extra Columns in a GROUP BY
Happy Canada Day. I have a really good one today.

My problem:

I have a table 'ASSIGNMENTS' that keeps track of each assignment,


who holds which assignment, and as of which date they have held it.

It would be very handy to have a view that shows all assignments,


and who is currently on that assignment.

CREATE TABLE ASSIGNMENTS(ASSIGNMENT VARCHAR2(32),


EMPLOYEE VARCHAR2(32), EFFECTIVE DATE);

INSERT INTO ASSIGNMENTS(ASSIGNMENT, EMPLOYEE, EFFECTIVE)


VALUES ('Prime Minister', 'Jean Chretien', '04-Nov-93');
INSERT INTO ASSIGNMENTS(ASSIGNMENT, EMPLOYEE, EFFECTIVE)
VALUES ('Governor General', 'Adrienne Clarkson', '07-Oct-99');
INSERT INTO ASSIGNMENTS(ASSIGNMENT, EMPLOYEE, EFFECTIVE)
VALUES ('Prime Minister', 'Paul Martin', '12-Dec-03');

You must be familiar with GROUP BY.

SELECT ASSIGNMENT, MAX(EFFECTIVE) AS_OF FROM ASSIGNMENTS


GROUP BY ASSIGNMENT;

ASSIGNMENT AS_OF
-------------------------------- ---------
Governor General 07-OCT-99
Prime Minister 12-DEC-03

2 rows selected.

Ok, now we would like to add in the name of the person. But
whoops, doesn't work as you'd expect.

SELECT ASSIGNMENT, EMPLOYEE, MAX(EFFECTIVE) AS_OF FROM


ASSIGNMENTS GROUP BY ASSIGNMENT;

ORA-00979: not a GROUP BY expression

http://thinkoracle.blogspot.com/2005_07_01_archive.html (24 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

You see, we can't include any columns that aren't part of the GROUP
BY. And, we can't include it in the group by, because then we'd get a
result no different from assignments.

There is an answer. Connor McDonald has it:

http://www.oracledba.co.uk/tips/9i_first_last.htm

Alright, what is Connor talking about? Basically he is grouping the


"extra" column (empno), and making it a secondary grouping to the
main grouping (sal).

But, really, MIN(EMPNO)? Why are we including an aggregate


function on empno? Well, Connor is doing it because he wants to
break ties.

Even though we don't need to break ties, we still need to use an


aggregate function, otherwise it becomes part of the group by. Any
aggregate function will do since we shouldn't have duplicates.

DENSE_RANK , FIRST, ORDER BY

- ORDER BY will sort a set of rows by a particular column. In


Connor's case it is salary, in our case, it will be 'effective'.
- DENSE_RANK provides the positioning of a particular row within
an ordered list of rows.
- FIRST goes hand-in-hand with DENSE_RANK and will naturally
provide us with the first, ranked row in a ordered list of rows.

Note that the ORDER BY defaults to ascending order, and so in our


case we either want to choose LAST or put the ORDER BY in
descending order instead.

Essentially he is creating an ordered list of all salaries, and choosing


the empno that shows up first on that list. Sounds like what we
want!

Here is Dan Morgan's reference on numeric functions like these:


http://www.psoug.org/reference/number_func.html

KEEP is just a clever Oracle trick to keep the work we're doing in the
shared pool because we're using it twice in the same query.

So applying Connor's teachings to our situation, we get:

http://thinkoracle.blogspot.com/2005_07_01_archive.html (25 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

CREATE OR REPLACE VIEW CURRENT_ASSIGNMENTS AS


SELECT ASSIGNMENT,
MAX(EMPLOYEE) KEEP (DENSE_RANK LAST ORDER BY EFFECTIVE)
EMPLOYEE,
MAX(EFFECTIVE) AS_OF
FROM ASSIGNMENTS
GROUP BY ASSIGNMENT;

SELECT * FROM CURRENT_ASSIGNMENTS;

ASSIGNMENT EMPLOYEE AS_OF


--------------------------------
-------------------------------- ---------
Governor General Adrienne Clarkson 07-OCT-99
Prime Minister Paul Martin 12-DEC-03

2 rows selected.

Coming up in some future blog, Tom Kyte mentioned the awesome


"MEMBER OF" feature that is in Oracle 10g. It will tell you easily
whether a value is contained in a particular set/table. I'm looking
for a way to do this in Oracle 9.

http://thinkoracle.blogspot.com/2005/05/enum-in-oracle.html

// posted by Robert Vollman @ Friday, July 01, 2005 1 comments

About Me
Name: Robert Vollman
Location: Calgary, Alberta, Canada

I was born and raised in Ottawa, and have lived in Calgary since 1991. I
like playing sports (hockey, soccer, ultimate, basketball, you name it)
and military board games. I also enjoy reading, walking, and playing with my 2 cats
Lilly and Brutus. I'm a database application specialist, whatever that is.

http://thinkoracle.blogspot.com/2005_07_01_archive.html (26 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

View my complete profile

Best Links
● Ask Tom Kyte
● Oracle Docs
● Dan Morgan and PSOUG
● Steven Feuerstein
● Jonathan Lewis
● FAQ
● Connor McDonald
● The Oak Table
● Cary Millsap and Hotsos
● Steve Adams and Ixora
● Anjo Kolk and OraPerf
● Dizwell Oracle Wiki
● My Personal Blog

Aggregators
Brian Duff's OraBlogs

❍ Eddie Awad's OracleNA


❍ Pete Finnigan's Aggregator
❍ Oracle's Bloglist
❍ Oracle Base Aggregator

Top Blogs
❍ Oracle's Ask Tom Kyte
❍ Oracle Guru Jonathan Lewis
❍ Blogger of the Year Eddie Awad
❍ Data Warehouser David Aldridge
❍ Oracle Geek Lewis Cunningham
❍ Database Expert James Koopmann
❍ Dizwell's Howard Rogers
❍ Oracle Master Laurent Schneider
❍ Security Expert Pete Finnigan
❍ Oracle Award Winner Mark Rittman
❍ Doug Burns

http://thinkoracle.blogspot.com/2005_07_01_archive.html (27 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

❍ Oracle ACE of the Year Dr. Tim Hall


❍ UKOUG's Andrew (Arfur C.) Clarke
❍ Newbie DBA Lisa Dobson
❍ Coffee-Drinking DBA Jon Emmons
❍ Chris Foot
❍ The Pythian DBA Team Blog
❍ DBA Don Seiler
❍ DBA Coskan Gundogar
❍ Oracle WTF

ARCHIVES
❍ LIST ALL ARTICLES
❍ May 2005
❍ June 2005
❍ July 2005
❍ August 2005
❍ September 2005
❍ October 2005
❍ November 2005
❍ December 2005
❍ January 2006
❍ February 2006
❍ March 2006
❍ April 2006
❍ May 2006
❍ June 2006
❍ July 2006
❍ August 2006
❍ September 2006
❍ October 2006
❍ November 2006
❍ December 2006
❍ January 2007
❍ February 2007
❍ March 2007
❍ April 2007
❍ May 2007
❍ June 2007
❍ October 2007

http://thinkoracle.blogspot.com/2005_07_01_archive.html (28 of 29)1/9/2008 2:49:36 AM


OracleBlog: July 2005

❍ Current Posts

http://thinkoracle.blogspot.com/2005_07_01_archive.html (29 of 29)1/9/2008 2:49:36 AM


OracleBlog: August 2005

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be complicated, but it
is the most powerful tool when it comes to data. That's why when I think data, I think Oracle. I also enjoy
writing, so I use this format to organise my thoughts. Please feel free to discuss any thoughts you may
have on the same topics, even old ones (I will see and respond to such comments). You may want to
start with "LIST ALL ARTICLES" under Archives.

Monday, August 29, 2005


About Me
New Blogs Name: Robert
Not long ago, I wrote a blog on all the Oracle Blogs out Vollman
there: Location: Calgary,
Alberta, Canada
http://thinkoracle.blogspot.com/2005/07/oracle-blogs.
html
I was born and raised in Ottawa,
and have lived in Calgary since
Not long after that, I included a list of links to all the blogs
1991. I like playing sports
I follow (see the side, below links).
(hockey, soccer, ultimate,
Well there have been a couple of changes and new basketball, you name it) and
additions. The most exciting of which is I found a blog by military board games. I also
Laurent Schneider. He is one of my favourite posters from enjoy reading, walking, and
the Oracle Forum: playing with my 2 cats Lilly and
Brutus. I'm a database
http://forums.oracle.com/forums/forum.jspa?forumID=75 application specialist, whatever
that is.
His posts usually involve how to use Oracle to solve
someone's problems. Over the months I've been reading View my complete profile
this forum, I've seen him cover a wide spectrum.

Here is a link to one of of his most recent articles:


Best Links
http://laurentschneider.blogspot.com/2005/08/pivot- ● Ask Tom Kyte
table.html ● Oracle Docs
● Dan Morgan and PSOUG
There are a few other changes: ● Steven Feuerstein
Jonathan Lewis
Doug Burns changed his blog's location:

FAQ
http://oracledoug.blogspot.com/

● Connor McDonald
Radoslav Rusinov has a new blog, which he has kicked off ● The Oak Table
with a discussion of the latest Burleson Boondoggle on PGA: ● Cary Millsap and Hotsos
http://dba-blog.blogspot.com/ ● Steve Adams and Ixora
● Anjo Kolk and OraPerf

http://thinkoracle.blogspot.com/2005_08_01_archive.html (1 of 15)1/9/2008 2:49:41 AM


OracleBlog: August 2005

Hopefully these blogs will make up for my lack of content ● Dizwell Oracle Wiki
recently! ● My Personal Blog

// posted by Robert Vollman @ Monday, August 29, 2005 2 comments

Aggregators
Brian Duff's OraBlogs

Wednesday, August 24, 2005 ❍ Eddie Awad's OracleNA


Pete Finnigan's Aggregator
COMPUTE ❍

Oracle's Bloglist
Let's say you wanted to write a query that contained an

Oracle Base Aggregator


aggregate (eg: sum, min, max, count). No problem, you can ❍

use 'GROUP BY'.


Top Blogs
But suppose you wanted to write a query that was a report ❍ Oracle's Ask Tom Kyte
containing both the aggregate and the detail. That makes it ❍ Oracle Guru Jonathan Lewis
trickier. ❍ Blogger of the Year Eddie Awad
Data Warehouser David Aldridge
You may even know how to do it in other databases: ❍

❍ Oracle Geek Lewis Cunningham


http://sybasease.blogspot.com/2005/08/compute.html ❍ Database Expert James Koopmann
❍ Dizwell's Howard Rogers
There is a simple way of accomplishing this in SQL*Plus. ❍ Oracle Master Laurent Schneider
SQL*Plus includes a function of the same name (COMPUTE) ❍ Security Expert Pete Finnigan
that will do the formatting for you. ❍ Oracle Award Winner Mark
Rittman
In order to use it, you also have to use 'BREAK'. Let's take a
Doug Burns
very brief look at it. BREAK, like COMPUTE, is an SQL*Plus

command that you would issue at any time prior to your ❍ Oracle ACE of the Year Dr. Tim
query. For example, the following BREAK command will Hall
remove all values in DEPTNO if they are the same as the ❍ UKOUG's Andrew (Arfur C.) Clarke
preceding value, and skip 1 line after each grouping. ❍ Newbie DBA Lisa Dobson
❍ Coffee-Drinking DBA Jon Emmons
scott@Robert> BREAK ON deptno SKIP 1 NODUPLICATES ❍ Chris Foot
scott@Robert> SELECT ename, sal, deptno ❍ The Pythian DBA Team Blog
2 FROM emp ❍ DBA Don Seiler
3 ORDER BY deptno; ❍ DBA Coskan Gundogar
ENAME SAL DEPTNO ❍ Oracle WTF

ARCHIVES
---------- ---------- ----------
CLARK 2450 10
VOLLMAN 5000
❍ LIST ALL ARTICLES
MILLER 1300
SMITH 800 20 ❍ May 2005
ADAMS 1100 ❍ June 2005
FORD 3000 ❍ July 2005
SCOTT 3000 ❍ August 2005
JONES 2975 ❍ September 2005
ALLEN 1600 30 ❍ October 2005
BLAKE 2850 ❍ November 2005
MARTIN 1250 ❍ December 2005
JAMES 950 ❍ January 2006

http://thinkoracle.blogspot.com/2005_08_01_archive.html (2 of 15)1/9/2008 2:49:41 AM


OracleBlog: August 2005

TURNER 1500 ❍ February 2006


WARD 1250 ❍ March 2006
❍ April 2006
❍ May 2006
June 2006
Now let's add our COMPUTE command. This one will ❍

calculate the subtotal of salary, just like it would using ❍ July 2006
GROUP BY. The advantage here is that its in the same table. ❍ August 2006
❍ September 2006
scott@Robert> COMPUTE SUM LABEL subtotal OF sal ON ❍ October 2006
deptno ❍ November 2006
scott@Robert> SELECT ename, sal, deptno FROM emp ❍ December 2006
ORDER BY deptno; ❍ January 2007
❍ February 2007
ENAME SAL DEPTNO ❍ March 2007
---------- ---------- ----------
❍ April 2007
CLARK 2450 10
❍ May 2007
VOLLMAN 5000
❍ June 2007
MILLER 1300
---------- ********** ❍ October 2007
8750 subtotal
❍ Current Posts
SMITH 800 20
ADAMS 1100
FORD 3000
SCOTT 3000
JONES 2975
---------- **********
10875 subtotal
ALLEN 1600 30
BLAKE 2850
MARTIN 1250
JAMES 950
TURNER 1500
WARD 1250
---------- **********
9400 subtotal

Naturally, this also works with other aggregate functions


like SUM, MIN, MAX, AVG, STD, VARIANCE, COUNT,
NUMBER.

For reference, check out the SQL*Plus User's Guide:


http://download-west.oracle.com/docs/cd/B10501_01/
server.920/a90842.pdf

You want chapters 7 and 13:


7 Formatting SQL*Plus Reports
13 SQL*Plus Command Reference

http://thinkoracle.blogspot.com/2005_08_01_archive.html (3 of 15)1/9/2008 2:49:41 AM


OracleBlog: August 2005

UPDATE: Actually there's a simple way without SQL*Plus, by


using GROUPING, see Tom Kyte's Comment. Here is his
example of my Oracle9 environment.

scott@Robert> SELECT DECODE(GROUPING_ID(ename), 1,


'Subtotal' ) tag
2 ename, deptno, SUM(sal)
3 FROM emp
4 GROUP BY GROUPING SETS( (ename,deptno), (deptno) );

TAG ENAME DEPTNO SUM(SAL)


-------- ---------- ---------- ----------
CLARK 10 2450
MILLER 10 1300
VOLLMAN 10 5000
Subtotal 10 8750
FORD 20 3000
ADAMS 20 1100
JONES 20 2975
SCOTT 20 3000
SMITH 20 800
Subtotal 20 10875
WARD 30 1250
ALLEN 30 1600
BLAKE 30 2850
JAMES 30 950
MARTIN 30 1250
TURNER 30 1500
Subtotal 30 9400

Read about GROUPING, GROUPING_ID and GROUPING SETS


in SQL Reference:
http://download-west.oracle.com/docs/cd/B10501_01/
server.920/a96540.pdf

// posted by Robert Vollman @ Wednesday, August 24, 2005 6 comments

Wednesday, August 17, 2005


Keeping Tables Small
David Aldridge recently put together a list of ways to make
table scans faster:

http://oraclesponge.blogspot.com/2005/08/list-ways-to-
scan-table-faster.html

There is one really simple, effective but often overlooked

http://thinkoracle.blogspot.com/2005_08_01_archive.html (4 of 15)1/9/2008 2:49:41 AM


OracleBlog: August 2005

way of decreasing the time it takes to scan a table that I


want to elaborate on. It's based on this simple premise:

Fewer Rows = Faster Scans.

The time it takes to scan a table can be roughly calculated


like so:
Number of Rows TIMES Time to Process One Row

Many people focus on the second part of the question (the


time it takes to process a single row), when sometimes it is
far more simple to decrease the number of rows.

What that means is, look at the table and determine if some
of the data is used infrequently enough that it can be
moved aside to an archived version of this table.

You may need to modify your existing applications to


account for cases where you truly do need to look at all
that data. In that case, you might keep a view of all data.

That is basically my point, so you can stop reading there if


you wish. I have put together an example, where I elaborate
on this a little further. It is meant only as a demonstration
of what I mean, not any kind of compelling argument or
proof.

First off, here is an easy way to create a nice, big test table.

CREATE TABLE ReallyBigTable AS SELECT * FROM


ALL_OBJECTS;

SELECT COUNT (*) FROM ReallyBigTable;

40763

Now I'm going to create a query that ought to really suffer,


performance-wise, the larger the table is:

SELECT SUM(object_id) FROM ReallyBigTable


WHERE object_id * 2 NOT IN
(SELECT object_id FROM ReallyBigTable);

Time Elapsed: 00:11:42.09

Alright, now let's create an archive and active version of


this table. For argument's sake, let's say that anything with
an object_id below 40000 is used infrequently enough that
it is safe to push aside for our business-specific purposes:

CREATE TABLE ReallyBigTable_Archive AS SELECT * FROM


ReallyBigTable
WHERE object_id < 40000;

http://thinkoracle.blogspot.com/2005_08_01_archive.html (5 of 15)1/9/2008 2:49:41 AM


OracleBlog: August 2005

SELECT COUNT (*) FROM ReallyBigTable_Archive;

38000

CREATE TABLE ReallyBigTable_Active AS SELECT * FROM


ReallyBigTable
WHERE object_id >= 40000;

SELECT COUNT (*) FROM ReallyBigTable_Active;

2763

I'm in a single-user environment doing a test, so I really


don't have to worry right now about updates taking place.
Otherwise we'd have to more clever about the creation of
our archive and active tables. But I will say that creating
these tables can be lightning-fast!

Ok, now let's try our query on our little table:

SELECT SUM(object_id) FROM ReallyBigTable_Active


WHERE object_id * 2 NOT IN
(SELECT object_id FROM ReallyBigTable_Active);

Time Elapsed: 00:00:02.08

So it completed in 0.3% of the time. Awesome!

"OK," you say, "but you're cheating!" So what if I am?


Sometimes in the real world we CAN cheat. Sometimes we
don't have to go through all the data, every time, every
case. Don't get mad at Oracle or your DBA or your
application when it's not fast enough, just get creative. You
don't always have to apply painful Kolkian techniques or
Millsapian analysis to get results.

Moving on, there may still be some applications that want


to query on the whole dataset. No problem, that is still
possible using UNION. But what kind of price will we pay?
Let's see, in this one example:

DROP TABLE ReallyBigTable;

CREATE VIEW ReallyBigTable AS


SELECT * FROM ReallyBigTable_Archive
UNION ALL
SELECT * FROM ReallyBigTable_Active;

Remember, a view is just like a stored query, but we can


use it like a table. Which means our applications don't have
to change their queries.

http://thinkoracle.blogspot.com/2005_08_01_archive.html (6 of 15)1/9/2008 2:49:41 AM


OracleBlog: August 2005

http://thinkoracle.blogspot.com/2005/07/use-views.html

One limitation of this kind of view is that we won't be able


to insert from our legacy applications anymore:

INSERT INTO ReallyBigTable (object_id) VALUES (NULL);

ORA-01732: data manipulation operation not legal on this


view

Let's see how much of a performance penalty we have in


this case by using a view instead of the original base table:

SELECT SUM(object_id) FROM ReallyBigTable


WHERE object_id * 2 NOT IN
(SELECT object_id FROM ReallyBigTable);

Time Elapsed: 00:08:18.02

What??? The use of a view on two smaller sub-tables took


less time than the original table? It only took 70% as much
time. Probably something to do with having the data in
memory, or statistics, or something like that. I'll get back
to you in another blog. The main thing I wanted to
demonstrate was that the performance would be in the
same "order" as the original query. That is, you're not
taking a huge performance hit by using a view.

Out of curiousity, let's take a mixed sub-example, where


we are using our new, smaller table against that big view.

SELECT SUM (object_id) FROM ReallyBigTable_Active


WHERE object_id * 2 NOT IN
(SELECT object_id FROM ReallyBigTable);

Time Elapsed: 00:00:43.05

Nice.

One final point, if I may. Notice I used "UNION ALL" instead


of "UNION." I did this because UNION rearranges the order
of the table, and removes duplicates.

http://thinkoracle.blogspot.com/2005/08/union-all.html

I don't care about duplicates and order, and I didn't want


the performance hit, so I used UNION ALL. Of course, I am
curious to know how significant the performance hit is in
this case. Let's see.

CREATE OR REPLACE VIEW ReallyBigTable AS


SELECT * FROM ReallyBigTable_Archive
UNION

http://thinkoracle.blogspot.com/2005_08_01_archive.html (7 of 15)1/9/2008 2:49:41 AM


OracleBlog: August 2005

SELECT * FROM ReallyBigTable_Active;

SELECT SUM(object_id) FROM ReallyBigTable


WHERE object_id * 2 NOT IN
(SELECT object_id FROM ReallyBigTable);

Time Elapsed: 00:13:20.02

So it took about 60% longer than with UNION ALL.

SELECT SUM (object_id) FROM ReallyBigTable_Active


WHERE object_id * 2 NOT IN
(SELECT object_id FROM ReallyBigTable);

Time Elapsed: 00:00:54.05

And this one about 25% longer. So in this case it was


definitely noticeable.

Wrap-up:
1. David Aldridge has a great article on how to make your
table scans go faster.
2. In addition to his techniques, I recommend "being
creative" (aka "cheating") and trying to split your data.
3. Use Views to maintain applications that SELECT from the
big, original table so you don't have to change code and
can still query the whole set.
4. Using Views will not have a big performance hit. In fact,
in this demonstration it was faster (a topic for another
day's blog).
5. Use UNION ALL instead of UNION in this view to avoid
the noticeable performance hit.

// posted by Robert Vollman @ Wednesday, August 17, 2005 4 comments

Sunday, August 14, 2005


UTL_HTTP
Let's say you want to pull some real-time information off
the Internet and put it in your database. For example:
- Stock Market Quotes
- Temperature
- Sports scores

No need to write a separate application in Java or whatever,


you can do it all directly in Oracle.

Your solution will involve using one of the many handy


Oracle built-in utilities: UTL_HTTP.

For reference, flip open Chapter 78 of the 'Supplied PL/SQL

http://thinkoracle.blogspot.com/2005_08_01_archive.html (8 of 15)1/9/2008 2:49:41 AM


OracleBlog: August 2005

Packages and Types Reference'.

Tom Kyte also had a discussion in the Appendix of "Expert


One-on-One Oracle", and also on Ask Tom:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::
F4950_P8_DISPLAYID:285215954607

Let's look at a simple example, grabbing a market


quotation.

You can get the latest quotes from Yahoo Finance. Using
UTL_HTTP.REQUEST, you can get the content of that page,
and then search within for the data you want.

SELECT UTL_HTTP.REQUEST('http://finance.yahoo.com/q?
s=KMP') FROM DUAL;

If you're behind a firewall, include the IP or name of your


proxy server as the second parameter.

For simplicity, I'm not including the output here, but you
can see that we don't have our quote in there. That's
because we only got the first 2000 bytes of the web page.
If we want more, we need to use REQUEST_PIECES.

Down below I have included a working example. It's


roughly thrown together, but it does illustrate the point:
you can use UTL_HTTP to retrieve information from the
Internet that you can put in the database.

As an aside, talk to some lawyers to make sure the data


you are mining is not violating any copyrights.

After you write stored procedures to retrieve web pages,


and to extract information from within and insert them into
the database, you can automate the updates by calling the
stored procedures using DBMS_JOB (a topic for another
day!).

SET SERVEROUTPUT ON

DECLARE
l_pieces UTL_HTTP.HTML_PIECES;
-- We'll look at two 2000-byte pages at a time
l_two_pages VARCHAR2(4000);
l_start_read NUMBER;
l_end_read NUMBER;
l_quote VARCHAR2(12);
BEGIN
-- Grab up to a maxium of 32 2000-byte pages, and then
go through them,
-- looking at 2 pages at a time in case the data we are

http://thinkoracle.blogspot.com/2005_08_01_archive.html (9 of 15)1/9/2008 2:49:41 AM


OracleBlog: August 2005

looking for
-- overlaps a page boundary
l_pieces := UTL_HTTP.REQUEST_PIECES('http://finance.
yahoo.com/q?s=KMP', 32);
FOR i IN 1 .. l_pieces.COUNT LOOP
l_two_pages := l_two_pages || l_pieces(i);
-- Look for a string preceding the information we want
-- If we find it, add 52 (magic, Yahoo-specific number)
-- to find the point where the quote will begin
SELECT INSTR(l_two_pages, 'Last Trade', 1, 1) INTO
l_start_read FROM dual;
IF (l_start_read > 0) THEN
l_start_read := l_start_read + 52;
IF (l_start_read < 3950) THEN
SELECT INSTR(l_two_pages, '<', l_start_read, 1) INTO
l_end_read FROM dual;
IF (l_end_read > 0) THEN
IF ((l_end_read - l_start_read) < 12) THEN
SELECT SUBSTR(l_two_pages, l_start_read, l_end_read -
l_start_read) INTO l_quote FROM dual;
DBMS_OUTPUT.PUT_LINE(l_quote);
ELSE
DBMS_OUTPUT.PUT_LINE('Error (Quote more than 12
chars)');
END IF;
EXIT;
END IF;
END IF;
END IF;
l_two_pages := l_pieces(i);
END LOOP;
END;

// posted by Robert Vollman @ Sunday, August 14, 2005 4 comments

Wednesday, August 10, 2005


UNION ALL
You want to write a query that contains the rows from 2 or
more tables. What you want to use is one of Oracle's set
operators: UNION, INTERSECT, or MINUS. (Note: in the ANSI
SQL standard, MINUS is referred to as EXCEPT). My example
will deal with UNION.

You may have tables containing your employees,


contractors and clients, each with their own unique and
appropriate columns. For illustrative purposes, however,
let's consider only their names and phone numbers.

http://thinkoracle.blogspot.com/2005_08_01_archive.html (10 of 15)1/9/2008 2:49:41 AM


OracleBlog: August 2005

CREATE TABLE Employee (e_name VARCHAR2(32),


e_phonenumber VARCHAR2(16));
CREATE TABLE Contractor (c_name VARCHAR2(32),
c_phonenumber VARCHAR2(16), c_startcontract DATE,
c_endcontract DATE);
CREATE TABLE Client (c_name VARCHAR2(32),
c_phonenumber VARCHAR2(16));

Let's get some sample data:

INSERT INTO Employee VALUES ('Joe Smith', '555-555-


1234');
INSERT INTO Contractor VALUES ('Adam Johnson', '555-
555-8888', '01-Jan-04', '01-Mar-04');
INSERT INTO Contractor VALUES ('Bob Jackson', '555-555-
1111', '01-Jan-04', NULL);
INSERT INTO Contractor VALUES ('Adam Johnson', '555-
555-8888', '01-Jan-05', '01-Mar-05');
INSERT INTO Client VALUES ('Bill Taylor', '555-555-6767');
INSERT INTO Client VALUES ('Adam Johnson', '555-555-
8888');

What you would like to do is create a view to contain all the


phone numbers. You can use the UNION operator, which is
very easy. Write your queries however you wish, just make
sure that they all have the same number of columns and
similar data types.

SELECT e_name, e_phonenumber FROM Employee


UNION
SELECT c_name, c_phonenumber FROM Contractor
UNION
SELECT c_name, c_phonenumber FROM Client;

E_NAME E_PHONENUMBER
-------------------------------- ----------------
Adam Johnson 555-555-8888
Bill Taylor 555-555-6767
Bob Jackson 555-555-1111
Joe Smith 555-555-1234

Excellent!

But observe two things:


1. The order of the results have been re-arranged
2. There are no duplicates.

Actually, 1 and 2 are tied closely together. Oracle re-


arranges the results in order to put identical rows next to
each other and remove duplicates. On large tables, you

http://thinkoracle.blogspot.com/2005_08_01_archive.html (11 of 15)1/9/2008 2:49:41 AM


OracleBlog: August 2005

may get a bit of a performance hit.

If you don't care about removing duplicates, or especially if


you want the duplicates, use UNION ALL instead:

SELECT e_name, e_phonenumber FROM Employee


UNION ALL
SELECT c_name, c_phonenumber FROM Contractor
UNION ALL
SELECT c_name, c_phonenumber FROM Client;

E_NAME E_PHONENUMBER
-------------------------------- ----------------
Joe Smith 555-555-1234
Adam Johnson 555-555-8888
Bob Jackson 555-555-1111
Adam Johnson 555-555-8888
Bill Taylor 555-555-6767
Adam Johnson 555-555-8888

If you want them sorted, but don't want duplicates


removed, you can include an ORDER BY clause. Use UNION
with ORDER BY if you want duplicates removed and you
want a guaranteed order.

SELECT e_name, e_phonenumber FROM Employee


UNION ALL
SELECT c_name, c_phonenumber FROM Contractor
UNION ALL
SELECT c_name, c_phonenumber FROM Client
ORDER BY 1;

E_NAME E_PHONENUMBER
-------------------------------- ----------------
Adam Johnson 555-555-8888
Adam Johnson 555-555-8888
Adam Johnson 555-555-8888
Bill Taylor 555-555-6767
Bob Jackson 555-555-1111
Joe Smith 555-555-1234

If you just want to remove duplicates within tables, but not


in the merged set, try the DISTINCT clause.

SELECT DISTINCT e_name, e_phonenumber FROM Employee


UNION ALL
SELECT DISTINCT c_name, c_phonenumber FROM

http://thinkoracle.blogspot.com/2005_08_01_archive.html (12 of 15)1/9/2008 2:49:41 AM


OracleBlog: August 2005

Contractor
UNION ALL
SELECT DISTINCT c_name, c_phonenumber FROM Client;

E_NAME E_PHONENUMBER
-------------------------------- ----------------
Joe Smith 555-555-1234
Adam Johnson 555-555-8888
Bob Jackson 555-555-1111
Adam Johnson 555-555-8888
Bill Taylor 555-555-6767

I guess it all depends what you want.

Here is Dan Morgan's reference on Built-In Operators:


http://www.psoug.org/reference/ora_operators.html

But you also want to check out the Oracle SQL Reference,
Chapter 8: SQL Queries and Subqueries.

For your reading pleasure, check out this article by


Jonathan Gennick on set operators, including UNION:
http://five.pairlist.net/pipermail/oracle-
article/2003/000003.html

Administrative note: I've added a new section to include the


links to all the Oracle blogs I regularly visit, to save you
from going here:
http://thinkoracle.blogspot.com/2005/07/oracle-blogs.
html

// posted by Robert Vollman @ Wednesday, August 10, 2005 3 comments

Tuesday, August 09, 2005


OraBlogs!
Brian Duff maintains a blog that brings together all the
feeds from the various Oracle blogs that are out there.

http://www.orablogs.com/orablogs/

There are some fine blogs that are not included because
they do not support RSS 2.0 feed. Mine was one such case,
I used atom. Peter Scott and Doug Burns then pointed me
to Feedburner. It converts your feed from one format into
another.

http://thinkoracle.blogspot.com/2005_08_01_archive.html (13 of 15)1/9/2008 2:49:41 AM


OracleBlog: August 2005

http://www.feedburner.com/

Just go to their web site, type in the URL to your feed, and
then accept all the defaults. Just be sure that you have
these three settings (courtesy of Doug):

1) Do NOT select Smartfeed


2) Select Convert Format Burner
3) Select RSS 2.0 from the list of options.

If all goes well, this should be my first post on OraBlogs. It


would be great to kick things off with a great post but,
alas, I have nothing to post about today. Instead, just like a
bad 80s sitcom, I will do a "flashback highlight episode.
Here are my 5 favourite posts from my 3 months of
existence:

May 17th: NULL is not nothing


http://thinkoracle.blogspot.com/2005/05/null-vs-nothing.
html

June 10th: NULLs in Oracle (kind of a "Part 2")


http://thinkoracle.blogspot.com/2005/06/nulls-in-oracle.
html

July 1st (Canada Day): Extra Columns in a Group By


http://thinkoracle.blogspot.com/2005/07/extra-columns-
in-group-by.html

July 26th: Use Constraints!


http://thinkoracle.blogspot.com/2005/07/use-constraints.
html

July 29th: Using Views and other techniques to solve a


particular problem
http://thinkoracle.blogspot.com/2005/07/oracle-by-
example.html

// posted by Robert Vollman @ Tuesday, August 09, 2005 0 comments

Monday, August 01, 2005


Import Export
I recently installed a new Oracle instance on my laptop. I
wanted to migrate my small development database
(complete with structure and data) from my main
workstation to my laptop.

It was very easy using the import (IMP) and export (EXP)

http://thinkoracle.blogspot.com/2005_08_01_archive.html (14 of 15)1/9/2008 2:49:41 AM


OracleBlog: August 2005

tools. They are described in Chapter 1 (Export) and Chapter


2 (Import) of the Oracle Utilities Guide, available here:

http://www.oracle.com/technology/documentation/index.
html

Everything you should need to know is in there. For good


measure, I read Chapter 8 of Tom Kyte's "Expert One-on-
One Oracle" on Import and Export.

Word of caution: Think twice before using IMP/EXP as your


back-up strategy on large, complex databases.

Both utilities are located in $ORACLE_HOME/bin directory.


You need to run the $ORACLE_HOME/rdbms/admin/catexp.
sql file. You can see the commands you need by using the
HELP=Y option at your command prompt

C:\> EXP HELP=Y

So for me, the process was as easy as this:

1. Export the data

C:\> EXP USERID=scott/tiger OWNER=scott FILE=scott.dmp

2. Copy the DMP file to the target machine

3. Import the data

C:\> IMP USERID=scott/tiger FILE=scott.dmp FULL=Y

Done! All the tables, triggers, procedures, view and


constraints, as well as all the data. While I was at it, I just
created a BAT file out of this and added it to the Task
Manager to back-up my data regularly. (Unix: SH file and
CRON).

As a final note, here is a good FQ, by Frank Naude:


http://www.orafaq.com/faqiexp.htm

// posted by Robert Vollman @ Monday, August 01, 2005 2 comments

http://thinkoracle.blogspot.com/2005_08_01_archive.html (15 of 15)1/9/2008 2:49:41 AM


OracleBlog: September 2005

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Friday, September 30, 2005


PL/SQL Procedure Call Overhead
Is there much overhead in calling PL/SQL procedures?

I assume that if the answer is "yes," you'll want to avoid procedure calls,
which would likely mean making your procedures bigger (by combining
several into one). That makes me shudder because clean, modular code
is easier to read and maintain, not to mention making it easier to
develop new code if its based on reliable, tested code.

I assume there is at least some overhead to calling PL/SQL procedures. I


mean, if the procedure is not in the cache, you'll obviously have to go
the disk to fetch it.

If it's already in memory, there could still be some overhead in the


passing of parameters. UNLESS you can use the "NOCOPY" hint, that is.

http://thinkoracle.blogspot.com/2005/05/nocopy-hint.html

But to be honest, I don't know how much overhead any particular


procedure call will have. Sorry to those that read the title and hoped that
the content would contain the definitive answer. I might have something
more conclusive after doing some research. In the meantime, here is
what I do every time I have a question: I test it.

Even if I showed you a quote in a book that shows you how to calculate
the overhead, I would STILL advise testing it. Documents can be out-of-
date, misunderstood and just plain wrong. You need to test it.

http://thinkoracle.blogspot.com/2005_09_01_archive.html (1 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

Here is how to test it.

1. Write (or identify) a stored procedure that reflects your business


requirements.

CREATE OR REPLACE PROCEDURE DoIt


IS
BEGIN
NULL;
-- Do some stuff in here!
END DoIt;

2. Now split that stored procedure into two (or more) parts, and a master
proc

CREATE OR REPLACE PROCEDURE DoItPartOne


IS
BEGIN
NULL;
-- Do part of the stuff here...
END DoItPartOne;

...etc!

CREATE OR REPLACE PROCEDURE DoItInParts


IS
BEGIN
DoItPartOne;
-- DoItPartTwo;
-- etc...
END DoItInParts;

3. With stats on, call that first stored procedure that does everything,
and then run TKPROF to analyse it.

ALTER SESSION SET SQL_TRACE = TRUE;


EXEC DoIt;
ALTER SESSION SET SQL_TRACE = FALSE;

TKPROF robert_ora_3028.trc robert_ora_3028.prf explain='sys/********


as sysdba'

More on gathering and analysing simple performance statistics:


http://thinkoracle.blogspot.com/2005/09/analyzing-query-

http://thinkoracle.blogspot.com/2005_09_01_archive.html (2 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

performance.html

4. With stats on, call that second stored procedure.

ALTER SESSION SET SQL_TRACE = TRUE;


EXEC DoItInParts;
ALTER SESSION SET SQL_TRACE = FALSE;

You may find, as I did, that it is very hard to set up a test that reveals any
kind of noticeable performance overhead. But if the procedures were
spread out over the disk and not in the cache, or if there were lots and
lots of parameters, I bet we could see some overhead. But if your
procedure is called often enough for it to be important to you, the
procedures would probably be in the cache at any given time.

But don't spend too much time in conjecture, and even when I do
produce some facts, set up your tests anyway.

// posted by Robert Vollman @ Friday, September 30, 2005 4 comments

Thursday, September 22, 2005


Column Name as a Variable
Consider the situation where you are writing a stored procedure that
takes a column name as a variable, and then does some work based on a
query that uses that column name. How would you do it?

Let's consider a hypothetical situation. Say you have a table with all your
employees. Some of the columns are responsible for their pay.
Employees can get paid in different ways, for example: base salary,
hourly wage, bonus, dividend, etc. You have made each one of these a
separate column in the table. (Note: all these columns are of the same
type).

You have a number of stored procedures that access these tables. They
all share some things in common, so you have decided to make some
common "helper" procedures for all the "master" procedures to use.

Your "helper" procedure would have to take the column name from the
"master" procedure, and then perform the common queries and data
manipulations for that given column.

1. Dynamic SQL

http://thinkoracle.blogspot.com/2005_09_01_archive.html (3 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

One way of doing that is with dynamic SQL. Observe:

CREATE OR REPLACE PROCEDURE HelperProc (


in_col_name IN VARCHAR2,
out_val OUT NUMBER)
IS
BEGIN
EXECUTE IMMEDIATE 'SELECT MAX(' || in_col_name || ') FROM EMP' INTO
out_val;
END;

SET SERVEROUTPUT ON;

DECLARE
out_val NUMBER;
BEGIN
HelperProc('EMPNO', out_val);
DBMS_OUTPUT.PUT_LINE(out_val);
END;

It works very well:


- It's a single line, no matter how many possible columns are used
- You don't need to know the column names in advance
- You don't need to change it after a DDL change

However, there are drawbacks to Dynamic SQL. Among others, there is


extra parsing and (most seriously) vulnerabilities to SQL injection. I won't
go into more detail on Dynamic SQL, but I promise to blog on it soon.

2. Static SQL

The obvious recourse is to use something like IF or CASE or (my


favourite) DECODE.

CREATE OR REPLACE PROCEDURE HelperProc (


in_col_name IN VARCHAR2,
out_val OUT NUMBER)
IS
BEGIN
SELECT MAX(DECODE(in_col_name, 'EMPNO', EMPNO, 'MGR', MGR, 'SAL',
SAL, 'COMM', COMM, 'DEPTNO', DEPTNO, NULL))
INTO out_val
FROM EMP;
END;

http://thinkoracle.blogspot.com/2005_09_01_archive.html (4 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

Essentially this is like looking at the column name, and doing something
different depending on what it is. That's practically all you can do with
static SQL, by definition. This almost defeats the purpose of having a
common "helper" procedure, but there are still two reasons it would still
make sense:
1. Modularity (and abstraction) is generally a good thing
2. Any extra work done on out_val will justify the "helper" procedure.

3. Revised Data Model

There is an even more important consideration. Whenever you are


struggling to do something clever, take a step back and consider your
data model. It could be ill-suited for your needs.

In this case, what could we do?

We could break this information into separate tables. For example:


EmpBaseSalary, EmpHoury, EmpBonus, etc. Then we could join them to
the Emp table by employee id. Of course, that just makes the table name
variable instead of the column, so that doesn't really help us, so instead:

We could elongate the employee table, making something like this:

ID;...;SALARY;HOURLY;BONUS;DIVIDEND
1;...;60;NULL;NULL;NULL
2;...;100;NULL;NULL;20

into a separate table mapped by ID:

ID;VALUE;TYPE
1;60;'SALARY'
2;100;'SALARY'
2;20;'DIVIDEND'

That would effectively move the "column name" into the WHERE clause.
That would certainly make the task easier. That is sort of a "reverse
pivot."

Also, that opens the door to add extra columns for effective start and
end dates. We could even do this with views if we wanted to leave the
data model alone.

http://thinkoracle.blogspot.com/2005/07/use-views.html
http://thinkoracle.blogspot.com/2005/09/pivot-and-crosstab-queries.

http://thinkoracle.blogspot.com/2005_09_01_archive.html (5 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

html

That is just one example, but it shows how you need to take a step back
and consider the real-world application.

Here is a link to the Dizwell discussion forum where we discussed this,


and where most of this came from:
http://www.phpbbserver.com/phpbb/viewtopic.php?
t=450&mforum=dizwellforum

// posted by Robert Vollman @ Thursday, September 22, 2005 3 comments

Tuesday, September 20, 2005


Wanted: Your Unwanted Oracle/DB Books
Please excuse the spammy post today. But I would like to ask anyone
who is reading this who may have unwanted Oracle (8 and up) or General
DB (College) books to contact me (email address is in my profile).

Rather than gather dust on your shelf, I can give them a good home. I
will pay for shipping costs to Canada, and you will have my heartfelt
appreciation.

Many thanks!

// posted by Robert Vollman @ Tuesday, September 20, 2005 3 comments

Monday, September 19, 2005


PL/SQL Code Storage: Files vs In-DB Packages
I read this interesting exchange on Steven Feuerstein's Q&A:

http://htmldb.oracle.com/pls/otn/f?p=2853:4:1727923121986559057::
NO::P4_QA_ID:246

Essentially the question is where to stored your PL/SQL stored


procedures. H. Sheehan, Gary Myers, William Robertson, Pete Scott, Scott
Swank, A. Nadrian and I discussed this on the Dizwell Forum.

http://www.phpbbserver.com/phpbb/viewtopic.php?
t=458&mforum=dizwellforum

http://thinkoracle.blogspot.com/2005_09_01_archive.html (6 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

To sum up their positions:

Option 1: In organized, packaged files on your DB server


- Fewer security holes
- Handles failover situations better
- Easier to use version-control system
- Available for a greater number of nice PL/SQL editors
- Harder to inadvertantly overwrite source code, leads to greater
confidence

Option 2: In-the-db packages


- Greater efficiency (pre-loaded)
- Greater code integrity (shows invalidation)
- Search code in USER_SOURCE table
- Use some PL/SQL tools easier
(Note: there are IDEs that integrate with source control and compile
directly into the database)

It seems like the leading camp is Option 2. The advantages of having


your packages pre-loaded into the database are just so significant,
especially since you should be able to find an IDE that integrates directly
with source control and can compile directly into the database. Scott
Swank provided this suggestion:

http://www.oracle.com/technology/products/jdev/101/
howtos/extools/subversion.html

One general consensus, however, is this:


- Code should be contained in packages
- These packages should be wrapped.

// posted by Robert Vollman @ Monday, September 19, 2005 2 comments

Wednesday, September 14, 2005


Analyzing Query Performance
Alternate title: Keeping Tables Small, Revisited

In an earlier article I spoke about how removing old data can help speed
up table scans:

http://thinkoracle.blogspot.com/2005/08/keeping-tables-small.html

http://thinkoracle.blogspot.com/2005_09_01_archive.html (7 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

During a test in that article, I seemed to detect that querying a view


composed of the 90/10 split of a large table was much faster than
querying that table directly.

I was only trying to demonstrate that it wouldn't be much slower, I did


not expect for it to be faster. I didn't pursue it at the time, but
reproduced those results in 2 separate tests later on.

Incidentally, David Aldridge, who inspired my original article, has a


theory on this:
http://oraclesponge.blogspot.com/2005/08/more-on-partition-not-
quite-pruning.html

So the greater question was:


"How do you determine why a query is faster (or slower) than you
expected?"

The first step is to use SQL Trace and TKProf:


http://download-west.oracle.com/
docs/cd/B10501_01/server.920/a96533/sqltrace.htm#1018

Note: there are MANY sources of information on this. Apart from the
Oracle documentation, I also used articled by Tom Kyte, as well as his
book "Expert One-on-One Oracle."

Here was my test.

1. Set some variables:

ALTER SESSION SET TIMED_STATISTICS=true;


ALTER SYSTEM SET MAX_DUMP_FILE_SIZE=1000;
ALTER SYSTEM SET USER_DUMP_DEST="C:/temp/trace";

2. Create the ReallyBigTable

CREATE TABLE ReallyBigTable AS SELECT * FROM ALL_OBJECTS;

3. Turn on tracing

ALTER SESSION SET SQL_TRACE = TRUE;

4. Run the query

SELECT SUM(object_id) FROM ReallyBigTable

http://thinkoracle.blogspot.com/2005_09_01_archive.html (8 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

WHERE object_id * 2 NOT IN


(SELECT object_id FROM ReallyBigTable);

Note: 00:44:50.07

5. Turn off tracing

ALTER SESSION SET SQL_TRACE = FALSE;

6. Run TKPROF (separate window)

TKPROF robert_ora_3236.trc robert_ora_3236.prf explain='sys/********


as sysdba'
- Save that file somewhere (it will be overwritten later)

7. Create Archive and Active tables.

CREATE TABLE ReallyBigTable_Archive AS SELECT * FROM ReallyBigTable


WHERE object_id < 40000;

CREATE TABLE ReallyBigTable_Active AS SELECT * FROM ReallyBigTable


WHERE object_id >= 40000;

8. Drop ReallyBigTable

DROP TABLE ReallyBigTable;

9. Create the view

CREATE VIEW ReallyBigTable AS


SELECT * FROM ReallyBigTable_Archive
UNION ALL
SELECT * FROM ReallyBigTable_Active;

10. Turn on Tracing

ALTER SESSION SET SQL_TRACE = TRUE;

11. Run the query again

SELECT SUM(object_id) FROM ReallyBigTable


WHERE object_id * 2 NOT IN
(SELECT object_id FROM ReallyBigTable);

Elapsed: 00:45:21.04

http://thinkoracle.blogspot.com/2005_09_01_archive.html (9 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

12. Turn off tracing

ALTER SESSION SET SQL_TRACE = FALSE;

13. Run TKPROF (separate window)

TKPROF robert_ora_3236.trc robert_ora_3236.prf explain='sys/********


as sysdba'

Conclusion:

I repeated the test 3 times with tracing on, and each time I could not
reproduce the results. I saw virtually no difference in time elapsed
between querying a big table, and querying a big table

So I guess we're left in the dark as to why querying the view was so much
faster during my earlier tests. Perhaps we can apply Occam's Razor and
the safest conclusion was simply that I goofed.

Either way, it made for an interesting article of how to generate


performance data and query plans. I will leave you with an excerpt from
the TKPROF output:

SELECT SUM(object_id) FROM ReallyBigTable


WHERE object_id * 2 NOT IN
(SELECT object_id FROM ReallyBigTable)
call count cpu elapsed disk query
------- ------ -------- ---------- ---------- ----------
Parse 1 0.01 0.00 0 0
Execute 1 0.00 0.00 0 0
Fetch 2 612.03 2690.60 16168915 17030020
------- ------ -------- ---------- ---------- ----------
total 4 612.04 2690.60 16168915 17030020
Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: SYS
Rows Row Source Operation
------- ---------------------------------------------------
1 SORT AGGREGATE
20495 FILTER
40764 TABLE ACCESS FULL REALLYBIGTABLE
20269 TABLE ACCESS FULL REALLYBIGTABLE
Rows Execution Plan
------- ---------------------------------------------------

http://thinkoracle.blogspot.com/2005_09_01_archive.html (10 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

0 SELECT STATEMENT GOAL: CHOOSE


1 SORT (AGGREGATE)
20495 FILTER
40764 TABLE ACCESS (FULL) OF 'REALLYBIGTABLE'
20269 TABLE ACCESS (FULL) OF 'REALLYBIGTABLE'

// posted by Robert Vollman @ Wednesday, September 14, 2005 2 comments

Monday, September 12, 2005


20 Oracle Lessons
I started using Oracle with version 8 in 1999. After a few years I changed
companies to a Sybase/SQL-Server shop. But the past year has found me
back working with Oracle, this time version 8, and 9.

It has been an interesting time getting myself back into "game shape"
with Oracle, and digging into version 9. If you've been reading this blog,
you've been able to follow along with me in my adventures.

I decided this was as good a time as any to pause and reflect on some of
the lessons I've learned in this past year.

Oracle:
1. Oracle is very complex.
I always thought "a database is a database" but Oracle is about 4 times
as complex as Sybase/MS-SQL.

2. Fortunately Oracle is well-documented.


I have fallen in love with Oracle documentation. Clear, well-written,
comprehensive and lots of examples.

http://thinkoracle.blogspot.com/2005/07/oracle-docs.html

3. There are many on-line Oracle sites and forums to find help.
The primary benefit of a popular product is that whatever your mistake
is, you're probably not the first person to experience it. There is a huge
on-line Oracle community, and so many places to search for help. My
favourite links and blogs are kept current on this site.

Testing:
4. It's quick, free and very easy to set up a personal Oracle database on
your Windows PC for testing purposes.

http://thinkoracle.blogspot.com/2005_09_01_archive.html (11 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

5. Build proper test cases, and test everything you read before your
implement.
This is part of my personal style that I apply to all my work, regardless of
technology. But I feel it is especially true of a database as complex as
Oracle. Especially with all the different versions out there.

6. Burleson Consulting makes a lot of mistakes.


So test those even more carefully. But remember, even the stellar Tom
Kyte makes mistakes.

http://thinkoracle.blogspot.com/2005/06/expert-one-on-one.html

Coding/Modelling Practises:
7. Document your code.
It makes it easier to reuse good code, and fix bad code. Again, this is my
personal style that I apply to all project, regardless of technology. Do the
best I can, and explain what I'm doing.

8. Specify column/parameter names when writing queries or making


stored procedure calls.

http://thinkoracle.blogspot.com/2005/07/specifying-insert-columns.
html

9. NULLs are very special


This is one of my favourite topics. Casual database programmers might
not be aware of all the special cases related to NULLs, making them a
common cause of honest (but costly) mistakes.

http://thinkoracle.blogspot.com/2005/05/null-vs-nothing.html
http://thinkoracle.blogspot.com/2005/06/nulls-in-oracle.html
http://thinkoracle.blogspot.com/2005/09/nulls-in-count.html

10. Data integrity is best accomplished in the database layer (as opposed
to procedure or application layers).
Why use a sophisticated database like Oracle if you're just going to use it
as a data store? Use Oracle's ability to protect your data's integrity, and
then you can fear badly written applications a little bit less.

11. Triggers can be used as a form of "advanced constraint" for data


integrity.

http://thinkoracle.blogspot.com/2005/07/use-constraints.html

http://thinkoracle.blogspot.com/2005_09_01_archive.html (12 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

12. Views are very useful in solving complex queries without affecting
your data model (among many other uses!)

http://thinkoracle.blogspot.com/2005/07/use-views.html

13. A great way to improve performance is to archive/partition data.

http://thinkoracle.blogspot.com/2005/08/keeping-tables-small.html

14. You can often achieve common table types and procedure
parameters by defining user types, using %TYPE and referencing foreign
keys. Otherwise, use an advanced SQL modeller to develop your PL/SQL.

http://thinkoracle.blogspot.com/2005/06/common-table-column-types.
html

15. Choose carefully between using natural and synthetic keys when
designing your tables.

http://thinkoracle.blogspot.com/2005/06/natural-vs-synthetic-keys.
html

Useful Oracle (other than REGEXP, in Version 10):

16. DECODE is incredibly useful (CASE WHEN can also be used).


I am a huge fan of DECODE, I can't imagine working without it. It is
perhaps poorly named.

http://thinkoracle.blogspot.com/2005/06/decode.html

17. CONNECT BY is useful when you need hierarchical, string


aggregation (stragg).

http://thinkoracle.blogspot.com/2005/06/connect-by.html

18. GROUP BY has a lot of relatives to help write queries for complex
analytic functions: RANK, GROUPING SETS, GROUPING_ID, ROLLUP

http://thinkoracle.blogspot.com/2005/08/compute.html

19. PL/SQL supports OOP (Object-Oriented Programming)

http://thinkoracle.blogspot.com/2005/06/oop-in-plsql-yep.html

http://thinkoracle.blogspot.com/2005_09_01_archive.html (13 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

20. Oracle has a lot of handy toolkits


For example UTL_HTTP can be used to achieve very simple screen-
scraping (among other things)

http://thinkoracle.blogspot.com/2005/08/utlhttp.html

One more thing that didn't make the list (because it would push the total
from an even 20 to an odd 21):
When you're having trouble writing a very clever query or procedure, take
a step back and look at your data model. It might be inappropriate for
how you're using it.

Thanks for joining me on this stroll down memory lane!

// posted by Robert Vollman @ Monday, September 12, 2005 4 comments

Friday, September 09, 2005


NULLs in COUNT
Quick, easy one, but it trips up beginners. Something of which to be
mindful. Observe:

SELECT COUNT (*) FROM EMP;


COUNT(*)
----------
14
SELECT COUNT (COMM) FROM EMP;
COUNT(COMM)
-----------
4

Note: 4 instead of 14. But if we do this:

SELECT COMM FROM EMP;

COMM
----------
300
500
1400
0

http://thinkoracle.blogspot.com/2005_09_01_archive.html (14 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

14 rows selected.

We get all 14.

This is expected behaviour. From the Oracle SQL Reference: "If you
specify 'expr' then COUNT returns the number of rows where 'expr' is not
null."

http://download-west.oracle.com/docs/cd/B10501_01/server.920/
a96540.pdf

COUNT can take virtually any parameter, including 1, *, or a column. But


be aware that if you're counting a particular column, NULLs won't be
counted.

Additional reading material:

Everyone knows NULL is one of my favourite topics:


http://thinkoracle.blogspot.com/2005/05/null-vs-nothing.html
http://thinkoracle.blogspot.com/2005/06/nulls-in-oracle.html

Eddie Awad on the difference between COUNT(*) and COUNT(1)


http://awads.net/wp/2005/07/06/count-vs-count1/
(Note: see the links in the comments for more information)

// posted by Robert Vollman @ Friday, September 09, 2005 2 comments

Thursday, September 01, 2005


Pivot and Crosstab Queries
Here is another advanced concept that will come in useful when solving
Oracle problems.

Imagine you're trying to create a result set where the rows need to be
columns, or vice versa. In essence, you need to "pivot" rows into
columns, or vice versa. That is a very common requirement, and this is
where you need to look at a pivot (or crosstab) query to get the job done.

As always, when you want to understand something, you can start by


Asking Tom:
http://asktom.oracle.com/pls/ask/f?

http://thinkoracle.blogspot.com/2005_09_01_archive.html (15 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

p=4950:8:16663421538065257584::NO::
F4950_P8_DISPLAYID,F4950_P8_CRITERIA:766825833740

A simple pivot query is accomplished by basically doing the following:


1. Add some kind of count or row number to your query, if necessary for
the grouping
2. Then use your (revised) original query as a sub-query
3. Use "decode" to turn rows into columns (ie. a "sparse" matrix).
4. Use "max" to "squash" the multiple rows you moved to columns, into
single rows. Don't forget to group by.
(Note: it gets more complicated if you don't know how many columns
you'll need).

Here is another one of Ask Tom's example. It clearly shows how you use
decode to create a "sparse" matrix, and then use max to "squash" it
down.
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::
F4950_P8_DISPLAYID:124812348063

Let's look a simple example in slow motion.

Here's the data


CREATE TABLE CFL (season NUMBER(4), team VARCHAR2(16), points
NUMBER(3));
INSERT INTO CFL (season, team, points) VALUES (2004, 'Argonauts', 21);
INSERT INTO CFL (season, team, points) VALUES (2004, 'Alouettes', 28);
INSERT INTO CFL (season, team, points) VALUES (2004, 'Tiger-Cats', 19);
INSERT INTO CFL (season, team, points) VALUES (2004, 'Renegades', 10);
INSERT INTO CFL (season, team, points) VALUES (2003, 'Argonauts', 18);
INSERT INTO CFL (season, team, points) VALUES (2003, 'Alouettes', 26);
INSERT INTO CFL (season, team, points) VALUES (2003, 'Tiger-Cats', 2);
INSERT INTO CFL (season, team, points) VALUES (2003, 'Renegades', 14);
INSERT INTO CFL (season, team, points) VALUES (2002, 'Argonauts', 16);
INSERT INTO CFL (season, team, points) VALUES (2002, 'Alouettes', 27);
INSERT INTO CFL (season, team, points) VALUES (2002, 'Tiger-Cats', 15);
INSERT INTO CFL (season, team, points) VALUES (2002, 'Renegades', 10);

What we want:
A table showing each of these 4 teams and their point tables for these 3
seasons.

So what is our pivot row/column? Season.

Step 1/2: We are using season, so we don't need to create our own

http://thinkoracle.blogspot.com/2005_09_01_archive.html (16 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

grouping field, like count, rownum, or running total (sum) for example.
That would be easy enough to do, but let's keep this simple.

Step 3: Use "decode" to turn the season row into a column. Take a look
at our "sparse" matrix.

SELECT team,
DECODE (season, 2002, points, NULL) Yr2002,
DECODE (season, 2003, points, NULL) Yr2003,
DECODE (season, 2004, points, NULL) Yr2004
FROM (SELECT season, team, points FROM CFL);

TEAM YR2002 YR2003 YR2004


---------------- ---------- ---------- ----------
Argonauts 21
Alouettes 28
Tiger-Cats 19
Renegades 10
Argonauts 18
Alouettes 26
Tiger-Cats 2
Renegades 14
Argonauts 16
Alouettes 27
Tiger-Cats 15
Renegades 10

Step 4: Now let's use max to "squash" this into single rows. Don't forget
GROUP BY.

SELECT team,
MAX (DECODE (season, 2002, points, NULL)) Yr2002,
MAX (DECODE (season, 2003, points, NULL)) Yr2003,
MAX (DECODE (season, 2004, points, NULL)) Yr2004
FROM (SELECT season, team, points FROM CFL)
GROUP BY team;

TEAM YR2002 YR2003 YR2004


---------------- ---------- ---------- ----------
Alouettes 27 26 28
Argonauts 16 18 21
Renegades 10 14 10

http://thinkoracle.blogspot.com/2005_09_01_archive.html (17 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

Tiger-Cats 15 2 19

Pretty cool, eh? Easy, too.

Notice that the key to this is DECODE. If DECODE is not already part of
your toolbelt, I recommend studying up.

http://thinkoracle.blogspot.com/2005/06/decode.html

Ready for a tougher example? Let's look at another Ask Tom:


http://asktom.oracle.com/pls/ask/f?
p=4950:8:16663421538065257584::NO::
F4950_P8_DISPLAYID,F4950_P8_CRITERIA:7086279412131

For further study of pivot queries and analytic functions in general, there
is an awesome write-up in Chapter 12 of Tom Kyte's "Expert One-on-
One Oracle." You'd think I'd get a kickback from Tom Kyte with all the
promotion I'm doing, but the honest truth is that no one explains it as
well as he.

So, do you understand pivot queries now? No problems?

If so, now you're ready for one of Ask Tom's more complex examples:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::
F4950_P8_DISPLAYID:6923393629227

Pivot Tables

One final word: don't confuse pivot queries with pivot tables. Pivot tables
are a different concept, and have different uses (most typically to fill in
missing data). Until I blog about pivot tables, check out these two links:

Jonathan Gennick
http://www.oracle.com/technology/oramag/oracle/02-sep/o52sql.html

Laurent Schneider
http://laurentschneider.blogspot.com/2005/08/pivot-table.html

// posted by Robert Vollman @ Thursday, September 01, 2005 13 comments

http://thinkoracle.blogspot.com/2005_09_01_archive.html (18 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

Oracle WTF
Another great way to learn Oracle is to study mistakes.

Generally people have (misguided) reasons behind their mistakes, and


studying them can improve your understanding of Oracle. As such I'd
like you to check out a new blog out there dedicated to the most
spectacular misunderstandings of Oracle:

http://oracle-wtf.blogspot.com/

It's written by William Robertson, James Padfield, Thai Rices, Adrian


Billington and inspired by http://thedailywtf.com.

Another advantage of this blog, as compared to the 20-plus (and


growing) other Oracle blogs out there, is you a more likely to get a laugh
out of it. Or at least a good cry.

For those of you who enjoy the Dizwell Forum, I have gotten into the
habit of posting the occasional WTF there myself:

http://www.phpbbserver.com/phpbb/viewtopic.php?
t=310&mforum=dizwellforum
http://www.phpbbserver.com/phpbb/viewtopic.php?
t=383&mforum=dizwellforum
http://www.phpbbserver.com/phpbb/viewtopic.php?
t=417&mforum=dizwellforum

By the way, "WTF" stands for "What the F." As in "What the F was the
developer thinking?" :)

// posted by Robert Vollman @ Thursday, September 01, 2005 2 comments

About Me
Name: Robert Vollman
Location: Calgary, Alberta, Canada

http://thinkoracle.blogspot.com/2005_09_01_archive.html (19 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

I was born and raised in Ottawa, and have lived in Calgary since 1991. I
like playing sports (hockey, soccer, ultimate, basketball, you name it)
and military board games. I also enjoy reading, walking, and playing with my 2 cats
Lilly and Brutus. I'm a database application specialist, whatever that is.

View my complete profile

Best Links
● Ask Tom Kyte
● Oracle Docs
● Dan Morgan and PSOUG
● Steven Feuerstein
● Jonathan Lewis
● FAQ
● Connor McDonald
● The Oak Table
● Cary Millsap and Hotsos
● Steve Adams and Ixora
● Anjo Kolk and OraPerf
● Dizwell Oracle Wiki
● My Personal Blog

Aggregators
Brian Duff's OraBlogs

❍ Eddie Awad's OracleNA


❍ Pete Finnigan's Aggregator
❍ Oracle's Bloglist
❍ Oracle Base Aggregator

Top Blogs
❍ Oracle's Ask Tom Kyte
❍ Oracle Guru Jonathan Lewis
❍ Blogger of the Year Eddie Awad
❍ Data Warehouser David Aldridge
❍ Oracle Geek Lewis Cunningham
❍ Database Expert James Koopmann
❍ Dizwell's Howard Rogers

http://thinkoracle.blogspot.com/2005_09_01_archive.html (20 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

❍ Oracle Master Laurent Schneider


❍ Security Expert Pete Finnigan
❍ Oracle Award Winner Mark Rittman
❍ Doug Burns
❍ Oracle ACE of the Year Dr. Tim Hall
❍ UKOUG's Andrew (Arfur C.) Clarke
❍ Newbie DBA Lisa Dobson
❍ Coffee-Drinking DBA Jon Emmons
❍ Chris Foot
❍ The Pythian DBA Team Blog
❍ DBA Don Seiler
❍ DBA Coskan Gundogar
❍ Oracle WTF

ARCHIVES
❍ LIST ALL ARTICLES
❍ May 2005
❍ June 2005
❍ July 2005
❍ August 2005
❍ September 2005
❍ October 2005
❍ November 2005
❍ December 2005
❍ January 2006
❍ February 2006
❍ March 2006
❍ April 2006
❍ May 2006
❍ June 2006
❍ July 2006
❍ August 2006
❍ September 2006
❍ October 2006
❍ November 2006
❍ December 2006
❍ January 2007
❍ February 2007
❍ March 2007
❍ April 2007

http://thinkoracle.blogspot.com/2005_09_01_archive.html (21 of 22)1/9/2008 2:49:46 AM


OracleBlog: September 2005

❍ May 2007
❍ June 2007
❍ October 2007

❍ Current Posts

http://thinkoracle.blogspot.com/2005_09_01_archive.html (22 of 22)1/9/2008 2:49:46 AM


OracleBlog: October 2005

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be complicated,
but it is the most powerful tool when it comes to data. That's why when I think data, I think Oracle. I
also enjoy writing, so I use this format to organise my thoughts. Please feel free to discuss any
thoughts you may have on the same topics, even old ones (I will see and respond to such
comments). You may want to start with "LIST ALL ARTICLES" under Archives.

Monday, October 31, 2005


Oracle Packages
What is a "package"?

According to the PL/SQL User's Guide and Reference, "A package is a schema object
that groups logically related PL/SQL types, items and subprograms."

But I believe a package is far more than just a way of logically grouping objects
together.

Before I digress, let's very briefly understand what a package is. It's probably easiest
if you take a look at Oracle's documentation, which has a good description of
packages and some examples:

PL/SQL User's Guide and Reference, Chapter 9: PL/SQL Packages:


http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96624.pdf

Put simply, packages have two parts, the specification and the body.

The specification is the interface into the package. It describes all the types,
variables, procedures (etc) within the package. Ideally the specification does not
change.

The body has all the implementation. Inside the body you would actually write the
procedures, assign the values, and have all the details and logic behind the package.
Often (unless you are the developer), you can treat the body as a "black box."

As always, I'll refer you to Dan Morgan to understand the syntax of Oracle PL/SQL
Packages:
http://www.psoug.org/reference/packages.html

Back to the story.

According to one of my favourite PL/SQL Authors Connor McDonald, "The main


reason packages are not more widely adopted is that users are unaware of the

http://thinkoracle.blogspot.com/2005_10_01_archive.html (1 of 13)1/9/2008 2:49:50 AM


OracleBlog: October 2005

benefits they offer."

Beyond the known, obvious advantage of grouping together related items, which is
great for organising your code and "modularity", what are these benefits of which we
are speaking?

1. Objects don't get invalidated when you makes changes to the body. That saves a
lot of recompilation and makes changing the implementation much more painless.
You will still have to recompile if you change the specification, but that's not
something you should be doing very often.

2. You can "overload" subprograms (procedures/functions). You can have several


subprograms with the same name, but with a different number of parameters, or
different types. That is another thing that makes implementation changes more
painless because you can keep legacy code if you like. You can also see the extra
flexibility that offers developers.

3. You can have persistent variables throughout a session without storing anything in
a database table. Packages can have variables and constants that are initialised when
the packages is first used within a session, and then they are available for the
remainder of the session for all future references to anything within that package.
That comes in very handy.

4. Speaking of initialisation, being able to call a procedure automatically the first


time a package is used within a session can also come in very handy.

5. You can take advantage of "encapsulation." In essence, you can hide the
implementation details from users but still give them all the information they need to
use the package. Since they aren't aware of the details, that means you can change
them with minimal impact or risk. Packages also support private subprograms and
variables which are available only to other subprograms within the package, and
remain completely hidden and inaccessible to anything outside the package.

6. You may notice some performance improvement when using packages. When you
first use a package, the entire package may be loaded into memory, meaning fewer
disk I/Os as you use the related items within.

I'm sure there are other advantages, but those are the ones I've noticed.

Let me close with links to my favourite two articles about Packages, from two of my
favourite PL/SQL experts:
Connor McDonald's Chapter 2 from Mastering Oracle PL/SQL: Practical Solutions
http://www.oracle.com/technology/books/pdfs/sample2174ch2.pdf

Steven Feuerstein's article "Picking Your Packages" from May/June 2005 Oracle
Magazine
http://www.oracle.com/technology/oramag/oracle/05-may/o35plsql.html

---
Addition:

http://thinkoracle.blogspot.com/2005_10_01_archive.html (2 of 13)1/9/2008 2:49:50 AM


OracleBlog: October 2005

By the way, to use packages, just prefix the package name using dot notation

Check out PL/SQL Supplied Packages and Types Reference


http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96612.pdf

It includes UTL_HTTP and DBMS_OUTPUT


http://thinkoracle.blogspot.com/2005/08/utlhttp.html
http://thinkoracle.blogspot.com/2005/10/dbmsoutputputline.html

But also check out UTL_FILE, DBMS_PIPE, DBMS_ALERT and the DBMS_XML stuff.

// posted by Robert Vollman @ Monday, October 31, 2005 3 comments

Wednesday, October 12, 2005


DBMS_OUTPUT.PUT_LINE
DBMS_OUTPUT.PUT_LINE allows you to write information to a buffer throughout the
execution of a trigger/procedure. That information is available to be read by a
trigger/procedure (using GET_LINE(S)), or dumped to SQL*Plus upon completion of
execution.

One of the most common misconceptions is that PUT_LINE writes data immediately to
SQL*Plus. That is not true. PUT_LINE only puts it in the buffer. You will not see it
before the block has executed. I can prove that with this example (note: you must
load the user_lock package for this):

scott@Robert> BEGIN
2 DBMS_OUTPUT.PUT_LINE('Going to sleep for 10 seconds...');
3 USER_LOCK.SLEEP(1000);
4 DBMS_OUTPUT.PUT_LINE('Woke up after 10 seconds.');
5 END;
6/
Going to sleep for 10 seconds...
Woke up after 10 seconds.

You will have seen both messages come out after 10 seconds as opposed to one
before and one after.

Despite the fact that it doesn't write messages throughout its progress, PUT_LINE can
still make a useful debugging tool. I like the way that the messages can be kept but
easily disabled by using DBMS_OUTPUT.DISABLE. Any PUT_LINE messages are silently
ignored if you have DISABLEd DBMS_OUTPUT (or failed to ENABLE).

To see the messages, you need to call DBMS_OUTPUT.ENABLE. The only parameter is
buffer_size, which, if NULL, will default to 20000. The buffer size can be anywhere
from 2000 to 1000000.

scott@Robert> BEGIN
2 DBMS_OUTPUT.DISABLE;

http://thinkoracle.blogspot.com/2005_10_01_archive.html (3 of 13)1/9/2008 2:49:50 AM


OracleBlog: October 2005

3 DBMS_OUTPUT.PUT_LINE('Disabled');
4 DBMS_OUTPUT.ENABLE;
5 DBMS_OUTPUT.PUT_LINE('Enabled');
6 END;
7/
Enabled

PL/SQL procedure successfully completed.

Incidentally, SQL*Plus's SET SERVEROUTPUT ON will call DBMS_OUTPUT.ENABLE. You


can even use SIZE with that command. SET SERVEROUTPUT also includes formatting
options, such as FORMAT WRAPPED, WORD_WRAPPED and TRUNCATE (along with a
SET LINESIZE) to get the output the way you want it. [EDIT: Fixed Typo]

There are two common errors related to DBMS_OUTPUT.PUT_LINE. The first one is
trying to put more than 255 characters per line.

scott@Robert> DECLARE
2 l_string VARCHAR2(300);
3 BEGIN
4 l_string := '1234567890';
5 l_string := l_string || l_string || l_string || l_string || l_string;
6 l_string := l_string || l_string || l_string || l_string || l_string || l_string;
7 DBMS_OUTPUT.PUT_LINE(l_string);
8 END;
9/
DECLARE
*
ERROR at line 1:
ORA-20000: ORU-10028: line length overflow, limit of 255 chars per line
ORA-06512: at "SYS.DBMS_OUTPUT", line 35
ORA-06512: at "SYS.DBMS_OUTPUT", line 133
ORA-06512: at line 7

The solution here is to use DBMS_OUTPUT.NEW_LINE to split it up into lines. 255 is a


hard limit, if you really want to print a line with more than that, you can write your
own package that does the same thing as DBMS_OUTPUT. That is actually a very
common thing to do. Tom Kyte's has a handy one in Appendix A of "Expert One-on-
One Oracle."

The second common error is overfilling your buffer.

scott@Robert> BEGIN
2 DBMS_OUTPUT.ENABLE(2000);
3 FOR i IN 1..1000 LOOP
4 DBMS_OUTPUT.PUT_LINE('This is line ' || i);
5 END LOOP;
6 END;
7/
This is line 1

http://thinkoracle.blogspot.com/2005_10_01_archive.html (4 of 13)1/9/2008 2:49:50 AM


OracleBlog: October 2005

This is line 105


BEGIN
*
ERROR at line 1:
ORA-20000: ORU-10027: buffer overflow, limit of 2000 bytes
ORA-06512: at "SYS.DBMS_OUTPUT", line 35
ORA-06512: at "SYS.DBMS_OUTPUT", line 198
ORA-06512: at "SYS.DBMS_OUTPUT", line 139
ORA-06512: at line 4

The solution here is increase the size of your buffer, using ENABLE. The maximum
size is 1000000 and that is a hard limit. Once again, you can write your own package
as a workaround.

This example also illustrated that even if you have an exception, the contents of the
buffer until that point is still available.

The alternative to writing your own package is to write your messages to a table.
Then you can query the table at any time to see your debug messages. DBMS_PIPE is
another option to consider.

I will close with two more interesting "gotchas" for DBMS_OUTPUT.PUT_LINE.

scott@Robert> BEGIN
2 DBMS_OUTPUT.PUT_LINE(' What happened to my leading spaces?');
3 END;
4 /
What happened to my leading spaces?

This is an SQL*Plus Gotcha. Just be sure to use FORMAT WRAPPED, like so:

scott@Robert> SET SERVEROUTPUT ON FORMAT WRAPPED


scott@Robert> BEGIN
2 DBMS_OUTPUT.PUT_LINE(' There they are!');
3 END;
4 /
There they are!

Here is the second gotcha.

scott@Robert> DECLARE
2 l_bool BOOLEAN;
3 BEGIN
4 l_bool := TRUE;
5 DBMS_OUTPUT.PUT_LINE(l_bool);

http://thinkoracle.blogspot.com/2005_10_01_archive.html (5 of 13)1/9/2008 2:49:50 AM


OracleBlog: October 2005

6 END;
7/
DBMS_OUTPUT.PUT_LINE(l_bool);
*
ERROR at line 5:
ORA-06550: line 5, column 1:
PLS-00306: wrong number or types of arguments in call to 'PUT_LINE'
ORA-06550: line 5, column 1:
PL/SQL: Statement ignored

DBMS_OUTPUT.PUT_LINE is not overloaded for Booleans. The solution is to either to


write your own package (as mentioned above), or convert from Boolean type to
something else for the PUT_LINE call.

For more information, this package is described in (among other places) Oracle's
Supplied PL/SQL Packages Reference Guide, Chapter 43:
http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96612.pdf

And here is Dan Morgan's Quick Reference:


http://www.psoug.org/reference/dbms_output.html

// posted by Robert Vollman @ Wednesday, October 12, 2005 6 comments

Thursday, October 06, 2005


ROWNUM and ROWID
Questions:
How do I limit the number of rows returned by a query?
How do I write a query to get the Top-N salaries from the employee table?
How can I add unique, sequential numbers to an existing table?
How can I differentiate between two completely identical rows?
How can I find a faster way to retrieve a queried row?
How can I find the last row processed in a big batch?

There is one thing all these questions have in common: the answer involves either
ROWNUM or ROWID.

So what is ROWNUM and ROWID?

First of all, both are covered in the SQL Reference, Basic Elements of Oracle SQL,
Chapter 2:
http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96540.pdf

They are also both referred to as pseudo-columns. That is, they are not "real"
columns that will show up when you DESC a table. They don't actually exist anywhere
in the database. But they're available for you to use.

In fact, ROWNUM only exists for a row once it is retrieved from a query. It represents
the sequential order in which Oracle has retrieved the row. Therefore it will always

http://thinkoracle.blogspot.com/2005_10_01_archive.html (6 of 13)1/9/2008 2:49:50 AM


OracleBlog: October 2005

exist, be at least 1, and be unique (among the rows returned by the query). Obviously
it will change from query-to-query. Let's look at a quick example:

scott@Robert> SELECT ROWNUM, ENAME, SAL


2 FROM EMP;
ROWNUM ENAME SAL
---------- ---------- ----------
1 SMITH 800
2 ALLEN 1600
3 WARD 1250
4 JONES 2975
5 MARTIN 1250
6 BLAKE 2850
7 CLARK 2450
8 SCOTT 3000
9 VOLLMAN 5000
10 TURNER 1500
11 ADAMS 1100
12 JAMES 950
13 FORD 3000
14 MILLER 1300

Ok so let's say we want the 5 highest paid employees. Should be easy:

scott@Robert> SELECT ROWNUM, ENAME, SAL


2 FROM EMP
3 WHERE ROWNUM < 6
4 ORDER BY SAL DESC;
ROWNUM ENAME SAL
---------- ---------- ----------
4 JONES 2975
2 ALLEN 1600
3 WARD 1250
5 MARTIN 1250
1 SMITH 800

Whoops! Turns out ROWNUM is assigned before results are ordered, not after.
Knowing that, we can write it like this:

scott@Robert> SELECT ENAME, SAL


2 FROM (SELECT ENAME, SAL FROM EMP ORDER BY SAL DESC) E
3 WHERE ROWNUM < 6;
ENAME SAL
---------- ----------
VOLLMAN 5000

http://thinkoracle.blogspot.com/2005_10_01_archive.html (7 of 13)1/9/2008 2:49:50 AM


OracleBlog: October 2005

SCOTT 3000
FORD 3000
JONES 2975
BLAKE 2850

What about ROWID? ROWID actually represents the physical location of the record/
row in the database. That being the case, it is (according to Oracle documentation)
the fastest way to retrieve a particular row. Faster than an index, even.

Can you use ROWID to differentiate between duplicate rows?


Yes, you can. Since it actually represents the physical location of a row, no two rows
within the same table will have the same ROWID. Notice the caveat I added: within the
same table. If you're using clustering, two records from different tables could
theoretically share the same ROWID.

Do ROWIDs change?
Yes, especially with index organized or partitioned tables. Because ROWIDs represent
the physical location of a record/row, the ROWID will change every time the record is
physically moved.

Can you use ROWID as a primary key?


No, that's not advisable. While the ROWID will be unique, you would ideally want to
use a primary key that doesn't change.

How do you use ROWID to figure out what was the last record that was processed?
Using DBMS_SQL.LAST_ROW_ID to get the ROWID of the last row processed.

You'll see ROWNUM and ROWID pop up occasionally within solutions to problems on
AskTom and various Discussion Forums, so I recommend adding it to your own
toolbelt as well.

// posted by Robert Vollman @ Thursday, October 06, 2005 16 comments

Tuesday, October 04, 2005


Using DECODE to exploit COUNT/NULL feature
Not long ago, I mentioned that if you do a COUNT on a column (as opposed to on *
or a constant), the result will not include rows that have a NULL value for that column.

http://thinkoracle.blogspot.com/2005/09/nulls-in-count.html

Apparently you can exploit this situation, by using DECODE, and improve the
efficiency of your queries.

http://www.akadia.com/services/ora_decode.html

I found that very interesting. However, I had to check it for myself. Why? Because this

http://thinkoracle.blogspot.com/2005_10_01_archive.html (8 of 13)1/9/2008 2:49:50 AM


OracleBlog: October 2005

assertion may be:


1. Applicable only to a different version than mine (9.2.0.6).
2. Misunderstood by me.
3. Just plain wrong.

Note: My first attempt at this was a case of #2, therefore this article was updated
after my error was kindly pointed out by Gary Myers

Here is the test I ran which confirmed the results.

CREATE TABLE ReallyBigTable AS SELECT * FROM all_objects;

**Note: I did this about 15-20 times to get a really big table.

ALTER SESSION SET SQL_TRACE = TRUE;

SELECT rbt1.the_count, rbt1.the_sum,


rbt2.the_count, rbt2.the_sum FROM
(SELECT COUNT(*) the_count, SUM(object_id) the_sum
FROM ReallyBigTable WHERE object_type='TABLE') rbt1,
(SELECT COUNT(*) the_count, SUM(object_id) the_sum
FROM ReallyBigTable WHERE object_type='INDEX') rbt2;

ALTER SESSION SET SQL_TRACE = FALSE;

TKPROF robert_ora_2236.trc robert_ora_2236.prf explain='sys/******** as sysdba'

ALTER SESSION SET SQL_TRACE = TRUE;

SELECT COUNT(DECODE(object_type,'TABLE','*',NULL)) the_count,


SUM(DECODE(object_type,'TABLE',object_id,NULL)) the_sum,
COUNT(DECODE(object_type,'INDEX','*',NULL)) the_count2,
SUM(DECODE(object_type,'INDEX',object_id,NULL)) the_sum2
FROM ReallyBigTable;

ALTER SESSION SET SQL_TRACE = FALSE;

TKPROF robert_ora_2416.trc robert_ora_2416.prf explain='sys/******** as sysdba'

The DECODE version completed twice as quickly, because it only need to make one
pass through the data instead of 2.

Excerpt of the results:

SELECT rbt1.the_count, rbt1.the_sum,


rbt2.the_count, rbt2.the_sum FROM
(SELECT COUNT(*) the_count, SUM(object_id)
the_sum FROM ReallyBigTable
WHERE object_type='TABLE') rbt1,
(SELECT COUNT(*) the_count, SUM(object_id)
the_sum FROM ReallyBigTable

http://thinkoracle.blogspot.com/2005_10_01_archive.html (9 of 13)1/9/2008 2:49:50 AM


OracleBlog: October 2005

WHERE object_type='INDEX') rbt2


call count cpu elapsed disk query
------- ------ -------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0
Execute 1 0.00 0.00 0 0
Fetch 2 0.64 2.97 16994 17542
------- ------ -------- ---------- ---------- ----------
total 4 0.64 2.97 16994 17542
SELECT COUNT(DECODE(object_type,'TABLE','*',NULL)) the_count,
SUM(DECODE(object_type,'TABLE',object_id,NULL)) the_sum,
COUNT(DECODE(object_type,'INDEX','*',NULL)) the_count2,
SUM(DECODE(object_type,'INDEX',object_id,NULL)) the_sum2
FROM ReallyBigTable
call count cpu elapsed disk query
------- ------ -------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0
Execute 1 0.00 0.00 0 0
Fetch 2 0.60 1.76 8498 8771
------- ------ -------- ---------- ---------- ----------
total 4 0.60 1.76 8498 8771

// posted by Robert Vollman @ Tuesday, October 04, 2005 7 comments

Database Specialists
Recently Dr. Tim Hall posted a brief blog on SQL Tuning. He may have based it on a
number of questions on the topic that have popped up recently on some of the
Oracle forums.

http://oracle-base.blogspot.com/2005/10/no-shortcuts-for-sql-tuning.html

You might also have seen Steve Callan's 2-part article on Oracle Performance Tuning
on DBASupport.com:

http://www.dbasupport.com/oracle/ora10g/perfTuning01.shtml

So I was searching for a good article I had once read on this topic, and I found it.
Here it is, courtesy of Ian Jones and Roger Schrag of Database Specialists:

http://www.dbspecialists.com/presentations.html#perf_bottleneck

The articles on their site are sometimes dated, but I still find them useful and
interesting. Here is a particularly fun article on "Database Mysteries" courtesy of Chris
Lawson:

http://www.dbspecialists.com/presentations.html#dba_mysteries

http://thinkoracle.blogspot.com/2005_10_01_archive.html (10 of 13)1/9/2008 2:49:50 AM


OracleBlog: October 2005

// posted by Robert Vollman @ Tuesday, October 04, 2005 1 comments

About Me
Name: Robert Vollman
Location: Calgary, Alberta, Canada

I was born and raised in Ottawa, and have lived in Calgary since 1991. I like playing
sports (hockey, soccer, ultimate, basketball, you name it) and military board
games. I also enjoy reading, walking, and playing with my 2 cats Lilly and Brutus. I'm a
database application specialist, whatever that is.

View my complete profile

Best Links
● Ask Tom Kyte
● Oracle Docs
● Dan Morgan and PSOUG
● Steven Feuerstein
● Jonathan Lewis
● FAQ
● Connor McDonald
● The Oak Table
● Cary Millsap and Hotsos
● Steve Adams and Ixora
● Anjo Kolk and OraPerf
● Dizwell Oracle Wiki
● My Personal Blog

Aggregators
❍ Brian Duff's OraBlogs
❍ Eddie Awad's OracleNA
❍ Pete Finnigan's Aggregator
❍ Oracle's Bloglist
❍ Oracle Base Aggregator

Top Blogs
http://thinkoracle.blogspot.com/2005_10_01_archive.html (11 of 13)1/9/2008 2:49:50 AM
OracleBlog: October 2005

❍ Oracle's Ask Tom Kyte


❍ Oracle Guru Jonathan Lewis
❍ Blogger of the Year Eddie Awad
❍ Data Warehouser David Aldridge
❍ Oracle Geek Lewis Cunningham
❍ Database Expert James Koopmann
❍ Dizwell's Howard Rogers
❍ Oracle Master Laurent Schneider
❍ Security Expert Pete Finnigan
❍ Oracle Award Winner Mark Rittman
❍ Doug Burns
❍ Oracle ACE of the Year Dr. Tim Hall
❍ UKOUG's Andrew (Arfur C.) Clarke
❍ Newbie DBA Lisa Dobson
❍ Coffee-Drinking DBA Jon Emmons
❍ Chris Foot
❍ The Pythian DBA Team Blog
❍ DBA Don Seiler
❍ DBA Coskan Gundogar
❍ Oracle WTF

ARCHIVES
❍ LIST ALL ARTICLES
❍ May 2005
❍ June 2005
❍ July 2005
❍ August 2005
❍ September 2005
❍ October 2005
❍ November 2005
❍ December 2005
❍ January 2006
❍ February 2006
❍ March 2006
❍ April 2006
❍ May 2006
❍ June 2006
❍ July 2006
❍ August 2006
❍ September 2006
❍ October 2006
❍ November 2006
❍ December 2006
❍ January 2007
❍ February 2007

http://thinkoracle.blogspot.com/2005_10_01_archive.html (12 of 13)1/9/2008 2:49:50 AM


OracleBlog: October 2005

❍ March 2007
❍ April 2007
❍ May 2007
❍ June 2007
❍ October 2007

❍ Current Posts

http://thinkoracle.blogspot.com/2005_10_01_archive.html (13 of 13)1/9/2008 2:49:50 AM


OracleBlog: November 2005

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be complicated,
but it is the most powerful tool when it comes to data. That's why when I think data, I think Oracle.
I also enjoy writing, so I use this format to organise my thoughts. Please feel free to discuss any
thoughts you may have on the same topics, even old ones (I will see and respond to such
comments). You may want to start with "LIST ALL ARTICLES" under Archives.

Thursday, November 24, 2005


DBMS_PIPE
You would like to communicate with a 3rd-party application from your PL/SQL
program, for example you want to run a UNIX command. Or perhaps you'd like to
communicate directly with another Oracle session. Whatever your specific
communication needs are, DBMS_PIPE is your solution.

What is DBMS_PIPE?

DBMS_PIPE is a package provided by Oracle that allows two or more sessions in the
same instance to communicate.

If you know anything about UNIX pipes, its a similar concept in Oracle. It is called a
pipe because it connects two (or more) sessions, and messages are queued up
inside, just like a pipe. Each session can take the next received item out of a pipe,
or insert the next item to send. Anybody (with access) can insert or remove
something from the pipe, in any order. Messages can only be removed and read
once - two people can't remove the same message from a pipe.

In more real terms, these pipes are buffers in the system global area (the SGA).
Messages are prepared for loading using PACK_MESSAGE, loaded into a pipe using
SEND_MESSAGE, and read similarly (RECEIVE_MESSAGE then UNPACK_MESSAGE).

There are basically 3 different types of pipes. Briefly:


Implicit Public Pipe: Automatically created when first accessed, disappears when it is
emptym, available to entire schema
Explicit Public Pipe: Created with CREATE_PIPE, freed with REMOVE_PIPE, available to
entire schema
Explicit Private Pipe: Created with CREATE_PIPE and private=true, freed with
REMOVE_PIPE, available only to that userid privileges, or SYSDBA.

Check chapter 45 of the PL/SQL Supplied Packages and Types Reference.


http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96612.pdf

http://thinkoracle.blogspot.com/2005_11_01_archive.html (1 of 16)1/9/2008 2:49:55 AM


OracleBlog: November 2005

Example:

For this test, open up two sessions as the SAME user on the SAME instance. Make
sure your user has access to the DBMS_PIPE package.

We are going to have the first instance create the pipe, send in an SQL command,
and have the second instance retrieve that message and execute it. That should
accomplish two things: show the basic usage of DBMS_PIPE, and give Pete Finnigan a
heart attack.

I have largely left out error-checking and handling, for brevity's sake. At many
points throughout the "ORA-23322" error is possible, which is for insufficient
privileges to access that pipe.

Session #1:

DECLARE
l_status NUMBER(2);
BEGIN
-- Create the pipe. 0 is success.
-- Possible error: name in use.
l_status := DBMS_PIPE.CREATE_PIPE (pipename => 'TEST_PIPE',
maxpipesize => 8192, private => TRUE);

-- Let's pack an instruction for another session.


-- Possible error: buffer overflow (4093 bytes of data)
DBMS_PIPE.PACK_MESSAGE(item => 'SELECT SYSDATE FROM DUAL;');

-- Let's stuff it into the pipe


-- We'll use defaults for maxpipesize and timeout
-- Returns 0 on success, 1 for timeout, 3 for interrupt
l_status := DBMS_PIPE.SEND_MESSAGE(pipename => 'TEST_PIPE');

-- Ok we're done, we should get 0 for success


l_status := DBMS_PIPE.REMOVE_PIPE (pipename => 'TEST_PIPE');
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
END;

Session #2:

DECLARE
l_received_message VARCHAR2(128);
l_message_type NUMBER(2);

http://thinkoracle.blogspot.com/2005_11_01_archive.html (2 of 16)1/9/2008 2:49:55 AM


OracleBlog: November 2005

l_status NUMBER(2);
BEGIN
-- Receive the message, use default timeout
-- If the pipe doesn't exist, Oracle will create it,
-- and wait for a message.
-- Returns 0 on success, 1 on a timeout, 3 for an interrupt
l_status := DBMS_PIPE.RECEIVE_MESSAGE(pipename => 'TEST_PIPE');
-- Ok, so what type are we extracting?
-- 0 nothing, 6 number, 9 varchar2, 11 ROWID, 12 DATE, 23 RAW
l_message_type := DBMS_PIPE.NEXT_ITEM_TYPE;

-- Open up the message, we can get ORA-06556 or ORA-06559


-- if its the wrong time, or nothing is left.
IF (l_message_type = 9) THEN
DBMS_PIPE.UNPACK_MESSAGE(item => l_received_message);
EXECUTE IMMEDIATE(l_received_message);
END IF;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
END;

By the way, I realise that I have removed the pipe in the first session before
accessing that message in the second session. But because there is still a message
in there, the pipe will stick around. To destroy it immediately I would have to purge
it first.

More Examples:

The aforementioned guide has an example on how to use DBMS_PIPE for debugging.
There is also a great example on communication with the shell to execute UNIX
commands (like listing the contents of a directory). These are complete, excellent
examples.

I'll close with some other little notes about DBMS_PIPES:


- There is a constant called maxwait which determines how long the pipe will wait
for a message to be picked up.
- The two major errors with DBMS_PIPE are ORA-23321 (bad pipename) or ORA-
23322 (insufficient privileges).
- You can use PURGE to empty out a pipe, and RESET_BUFFER for the local packing
buffer
- You can use UNIQUE_SESSION_NAME to help distinguish between sessions if there
are several accessing the pipe.

http://thinkoracle.blogspot.com/2005_11_01_archive.html (3 of 16)1/9/2008 2:49:55 AM


OracleBlog: November 2005

// posted by Robert Vollman @ Thursday, November 24, 2005 2 comments

Monday, November 21, 2005


RAW Datatype
Earlier I mentioned the idea of using a RAW datatype for your table's primary key. I
stumbled upon a minor inconvenience with using the RAW datatype today, so I
thought I would take a step back and talk a little bit more about the RAW datatype.
http://thinkoracle.blogspot.com/2005/06/natural-vs-synthetic-keys.html

RAW(size) is used for raw binary data or byte strings of length "size" bytes (must be
specified). The maximum is 2000 bytes, but in PL/SQL it is 32767, which can lead to
interesting situations.

Think of RAW very much like VARCHAR2, but unlike VARCHAR, RAW data will not be
converted depending on the character set (by import/export, for example). More
generally, Oracle will treat this as binary data and will not interpret it as a number,
character, or anything else (generally done when moving data from one system/
session to another).

RAW data can still be viewed as characters (2 characters per byte). Something like
SQL*Plus does this for you automatically when you query. But RAW data is a little
harder to use in pure SQL, because you often have to use HEXTORAW or RAWTOHEX
to do your work (example shortly). However in PL/SQL you can just use the
UTL_RAW package.

Now back to the story.

In the aforementioned article I mentioned using it as a primary key, using SYS_GUID.


The advantages are you get a (generally) unique and randomly-dispersed key that
you should never have to change. Please note: I do not want to get dragged into a
debate on whether or not it is a good idea, I'm just saying its possible, and has
some advantages. And yes, RAW data can be indexed just fine.

Now let me give you an example of the type of minor annoyance you have to deal
with when using RAW datatypes.

Associative arrays, also referred to as:


1. Hash arrays: in other languages, like Perl, that is what they are called
2. "Index-by tables": because they are declared just like nested tables except with
"index by" added to it.
Can not use RAW datatypes as their keys.

For this example I will use "NUMBER" instead of the %ROWTYPE you would have if
using RAW(16) as your primary key.

DECLARE
TYPE ASS_TYPE IS TABLE OF NUMBER INDEX BY RAW(16);
test_ass ASS_TYPE;

http://thinkoracle.blogspot.com/2005_11_01_archive.html (4 of 16)1/9/2008 2:49:55 AM


OracleBlog: November 2005

BEGIN
test_ass(SYS_GUID()) := 1;
test_ass(SYS_GUID()) := 2;
test_ass(SYS_GUID()) := 3;
END;

PLS-00315: Implementation restriction: unsupported table index type

So you have to convert it to VARCHAR2 in order to use it, using RAWTOHEX. You can
use HEXTORAW to turn it back. Here is a working example:

DECLARE
TYPE ASS_TYPE IS TABLE OF NUMBER INDEX BY VARCHAR2(32);
test_ass ASS_TYPE;
BEGIN
test_ass(RAWTOHEX(SYS_GUID())) := 1;
test_ass(RAWTOHEX(SYS_GUID())) := 2;
test_ass(RAWTOHEX(SYS_GUID())) := 3;
END;

---

Related Info:

There is some additional information the Oracle SQL Reference and Oracle
Application Developer's Guide - Fundamentals.

Other binary data types, depending on your version, include BLOB, Bfile, LONG RAW,
and others.

Here is a link to an AskTom discussion on RAW


http://asktom.oracle.com/pls/ask/f?p=4950:8:::::
F4950_P8_DISPLAYID:142612348066

// posted by Robert Vollman @ Monday, November 21, 2005 4 comments

Friday, November 11, 2005


More Oracle Essays
I recently posted an assorted list of Oracle essays from some of my favourite Oracle
authors:
http://thinkoracle.blogspot.com/2005/11/oracle-essays.html

There are so many other great Oracle writers out there pleased to provide free
insights into Oracle. So I thought I'd share a few more with Troy and everyone else.
Remember that each of these authors have written several papers, let me know if
you have trouble locating more work from your favourites.

http://thinkoracle.blogspot.com/2005_11_01_archive.html (5 of 16)1/9/2008 2:49:55 AM


OracleBlog: November 2005

Improving SQL Efficiency Using CASE by Doug Burns


http://doug.burns.tripod.com/case.pdf

Exploiting and Protecting Oracle by Pete Finnigan for PenTest Limited


http://downloads.securityfocus.com/library/oracle-security.pdf

Write Better SQL Using Regular Expressions by Alice Rischert for Oracle
http://www.oracle.com/technology/oramag/webcolumns/2003/
techarticles/rischert_regexp_pt1.html

What, Where, When, Why - Selecting Oracle Development Tools by Ken Atkins from
ODTUG 2001
http://www.arrowsent.com/oratip/whatwhere.doc

Getting Fast Results From STATSPACK by Bjorn Engsig for Miracle A/S
http://www.miracleas.dk/tools/Miracle_1_statspack.pdf

SQL Tuning With Statistics by Wolfgang Breitling for Centrex


http://www.centrexcc.com/SQL%20Tuning%20with%20Statistics.pdf

The VARRAY Data Type by Howard Rogers of Dizwell


http://www.dizwell.com/oracle/articles/the_varray.html

SQL In, XML Out by Jonathan Gennick for Oracle Magazine May/June 2003
http://www.oracle.com/technology/oramag/oracle/03-may/o33xml.html

Planning Extents by Steve Adams for Ixora


http://www.ixora.com.au/tips/creation/extents.htm

Oracle Collections: A Definition in Plain English by Lewis R. Cunningham


http://blogs.ittoolbox.com/oracle/guide/archives/005924.asp

Sorry, no Oracle papers from your favourite blogger! :)

// posted by Robert Vollman @ Friday, November 11, 2005 2 comments

Thursday, November 10, 2005


DUAL Table
What is the DUAL table?

The DUAL Dummy table (as it is sometimes called) is an automatically-generated


table assigned to SYS, but accessible to all users. It has a single column "DUMMY" of
type VARCHAR2(1) which has a single row with a value of 'X'.

scott@Robert> SELECT * FROM DUAL;

http://thinkoracle.blogspot.com/2005_11_01_archive.html (6 of 16)1/9/2008 2:49:55 AM


OracleBlog: November 2005

-
X

scott@Robert> DESC DUAL;


Name Null?
Type
-----------------------------------------------------------------------
--------
-------------------------------------------------
DUMMY
VARCHAR2(1)

Warning: Do not modify the DUAL table! Why would you want to anyway? It is part of
the data dictionary, which you shouldn't modify (that's a topic for another day).

What is it used for?

It is useful because it always exists, and has a single row, which is handy for select
statements with constant expressions. You could just as easily do this with any
other table with a single row, but using DUAL makes it portable among all Oracle
installations.

Example:

SELECT 1+1 FROM DUAL;


1+1
----------
2

The other reason to use the DUAL table isn't just portability, but optimization.
According to Tom Kyte, the Oracle Optimizer knows it is a special one row, one
column table. Eddie Awad tested a related assertion recently:
http://awads.net/wp/2005/11/09/dual-behavior-change/

Why is it called "DUAL"?

It was named "DUAL" because the primary intention of this table was to allow users
to create 2 rows for every row in a table by joining it to this system table. Thus
"DUAL". Chuck explained it in the January/February 2002 issue of Oracle Magazine:
http://www.oracle.com/technology/oramag/oracle/02-jan/o12sendmail.html

Of course, you can quite easily use DUAL to create as many rows as you want, using
LEVEL (or CUBE). Just Ask Tom how this is done:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::
F4950_P8_DISPLAYID:40476301944675#40756986348091

Why is it sometimes referred to as a "magic" table?

http://thinkoracle.blogspot.com/2005_11_01_archive.html (7 of 16)1/9/2008 2:49:55 AM


OracleBlog: November 2005

For the answer to this and any remaining questions about DUAL, just Ask Tom:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::
F4950_P8_DISPLAYID:1562813956388#14583959098556

Links

Earlier I made mention of the DUAL table, including an example:


http://thinkoracle.blogspot.com/2005/06/nulls-in-oracle.html

Eddie Awad recently tested Jared Still's assertion of an interesting feature in Oracle
10g. Even if DUAL has more than one row, apparently you can trust it to always
return just a single row. Read more:
http://awads.net/wp/2005/11/08/insert-into-dual/

Selecting from the DUAL table is mentioned in Chapter 8 of the Oracle SQL
Reference Guide:
http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96540.pdf

// posted by Robert Vollman @ Thursday, November 10, 2005 2 comments

Wednesday, November 09, 2005


10,000?
This marks my 60th post since I started in May, and, according to my stat counter I
have had 10,000 hits.

I was expecting 100, and even if 100 was the current total, it would still be
worthwhile for me to share my thoughts. Knowing that my ideas have been read
10,000 times makes me feel more excited about sharing them.

So whoever all of you are, you have my thanks, and I will definitely continue to write
about Oracle for as long as people are willing to read it!

Cheers!

// posted by Robert Vollman @ Wednesday, November 09, 2005 3 comments

Friday, November 04, 2005


Oracle Essays
Recently I recommended "Oracle Insights," a book containing a series of Oracle-
related essays by some of the top authors in our community. For those who are
interested in reading some more essays, consider some of the following samples
from a variety of my favourite authors on a variety of topics. The best part is that
these are free!

http://thinkoracle.blogspot.com/2005_11_01_archive.html (8 of 16)1/9/2008 2:49:55 AM


OracleBlog: November 2005

Re-building Indexes: When, How, Why by Jonathan Lewis


http://www.jlcomp.demon.co.uk/indexes.doc

Programming Humility: Dealing with the Reality of Errors by Steven Feuerstein of


Quest Software
http://www.odtug.com/Handouts_05/Feuerstein.zip

Locking and Concurrency by Tom Kyte


http://www.dbazine.com/oracle/or-articles/kyte1/

Practical Guide to Oracle Data Warehousing by David Aldridge


http://databasejournal.com/features/oracle/article.php/3098791

Query Tuning Using DBMS_STATS by Dave Ensor


http://www.dbazine.com/oracle/or-articles/ensor6

String Aggregation Techniques by Dr. Tim Hall


http://www.oracle-base.com/articles/10g/StringAggregationTechniques.php

Bind Variables Explained by Mark Rittman


http://www.rittman.net/archives/000832.html

The following two articles are also worth mentioning again.

Why a 99%+ Database Buffer Cache Hit Ratio is Not Ok, by Cary Millsap of Hotsos
http://www.oradream.com/pdf/Why%20a%2099%20Cahe%20Hit%20Ratio%20is%
20Not%20OK.pdf

Why I Invented YAPP by Anjo Kolk (Free registration for download)


http://www.oraperf.com/logon.html?rpage=download.php/yapp_anjo_kolk.pdf

While recommending some reading, I'm also including my favourite Oracle


community debates of 2005:

The great Burleson/Kyte debate on "Predictive Reorganization"


http://asktom.oracle.com/pls/ask/f?p=4950:8:8515227363337669542::NO::
F4950_P8_
DISPLAYID,F4950_P8_CRITERIA:35336203098853

The great Dizwell Forum debate: "Natural vs Surrogate keys"


http://www.phpbbserver.com/phpbb/viewtopic.php?
t=189&mforum=dizwellforum&sid=135

The great Burleson/Lewis debate on "Supersizing your PGA"


http://asktom.oracle.com/pls/ask/f?p=4950:8:::::
F4950_P8_DISPLAYID:47466211228419

http://thinkoracle.blogspot.com/2005_11_01_archive.html (9 of 16)1/9/2008 2:49:55 AM


OracleBlog: November 2005

// posted by Robert Vollman @ Friday, November 04, 2005 0 comments

Wednesday, November 02, 2005


Oracle Insights: Tales of the Oak Table
A recent book review of "Oracle Insights: Tales of the Oak Table" by Doug Burns,
combined with the introduction of Mogens Norgaard's new blog motivated me to
finally finish my own review of his book, which has sat incomplete since I first read
it 6 months ago.

Doug Burns' Book Review of "Oracle Insights:"


http://oracledoug.blogspot.com/2005/10/book-review-oracle-insights-tales-of.
html

Mogens Norgaard's new blog:


http://wedonotuse.blogspot.com/

Oracle Insights is a series of essays from a variety of relatively like-minded authors


that together comprise the Oak Table Network. This network includes some of my
favourite authors, a group of individuals who are very excited about their
experiences with Oracle and are eager to both share their insights, and gain even
more.

For more about the Oak Table Network, visit their web site:
http://www.oaktable.net/main.jsp

Oracle Insights is a wonderful collection of essays from a very talented and


enthusiastic bunch of Oracle experts. It starts with a great history of Oracle, and
then is followed by 10 chapters, basically split evenly between the topics of
performance/tuning and collections of war stories of Oracle projects gone bad.

Being a collection of essays, each chapter is stand-alone, linked together only by


Mogens Norgaard's prefaces. In fact, I really enjoyed the prefaces because they were
very casual and personal. Normally I skip prefaces because they're carefully
scripted, bland advertisements for a book you're already reading, but Mogens were
short, and served to put a human face to each of the authors.

Because of the nature of this book, I will briefly review each of the essays before
going into my overall impression of the book. First, you may want to visit Jonathan
Lewis' site, where he has a synopsis on each chapter as well as some anonymous
reviews (with his responses):
http://www.jlcomp.demon.co.uk/book_rev_2.html

Chapter 1: A Brief History of Oracle, by Dave Ensor

Without question, this is the highlight of the book. It is much longer than the other
essays (maybe he should drop "Brief" from the title), and he does tend to go on from
time to time, but this is still the hardest chapter to put down. It is admittedly not a

http://thinkoracle.blogspot.com/2005_11_01_archive.html (10 of 16)1/9/2008 2:49:56 AM


OracleBlog: November 2005

complete history, but it touches on the evolution of Oracle from Ted Codd's original
paper of Relational Databases to what Oracle is today. It organises Oracle's
responses to Codd's 12 Rules, and then some of the other related hot topics over
the years that shaped Oracle into what it is today: e.g. Transactional Integrity,
Isolation Levels, Privileges, Rule Based Optimizers. It then covers Oracle version-by-
version discussing the new features, their motivations, and their consequences,
right up to and including version 10.

I've heard it said that this chapter alone is worth the price of the book, and its hard
to disagree.

Chapter 2: You Probably Don't Tune Right, by Mogens Norgaard

There are at least 5 chapters that focus on performance and tuning, this being the
first and probably the weakest. Let me qualify that. First of all, I mean that more out
of praise to the other essays than an indictment of this one. Indeed, this essay is (at
least in part) a summary (or high-level view) of the others.

Secondly, this chapter's strength is not in "tuning" but rather on the topic of
Instrumentation. I think that would have made a better essay, and that's what makes
it worth reading.

One word on the style. This chapter is more like a narrative, or a conversation that
the author is having with you. I'll be honest, that's not really my style (although its
great for prefaces). For example, sometimes it gets repetitive. ("the Oracle database
is by far the best database around, technically speaking", next page: "Oracle is
technically the best database around.")

Chapter 3: Waste Not, Want Not, by Connor McDonald

Connor McDonald is perhaps the most talented writer in the crowd, and that's
saying a lot. His essay includes examples of inefficient (or "wasteful") applications,
SQL statements and PL/SQL blocks. Even in this short essay, he describes how he
found these wasteful cases, why they were wasteful, and how to correct them.
Those that learn from example will particularly enjoy his lessons.

Chapter 4: Why I Invented YAPP, by Anjo Kolk

The shortest chapter, and now the third on performance. This chapter is only of
interest to those that have already read (and enjoyed) Anjo Kolk's famous (and
awesome) paper on Yet Another Performance Profiling Method. Here is the link to
that paper (after a free registration):
http://www.oraperf.com/logon.html?rpage=download.php/yapp_anjo_kolk.pdf

Chapter 5: Extended SQL Trace Data by Cary Millsap

This one, you can judge for yourself, because this chapter is available on-line right
here:
http://www.oracle.com/technology/books/pdfs/oaktable_ch5.pdf

http://thinkoracle.blogspot.com/2005_11_01_archive.html (11 of 16)1/9/2008 2:49:56 AM


OracleBlog: November 2005

If you want to hear a little bit more about this chapter, I found that it was consistent
with Cary Millsap's other work, about which you can find a review of mine here:
http://thinkoracle.blogspot.com/2005/05/optimizing-oracle-performance-millsap.
html

Chapter 6: Direct Memory Access, by Kyle Hailey

Because of the developer in me, this was one of my favourite chapters. Kyle Hailey
relays a story about having met and worked with an Oracle master named Roger
Sanders and his "m2" application, which could access the memory Oracle was using
directly. Having opened our minds to the possibilities, his story leads into a
discussion on Oracle's SGA (Shared memory) and DMA, leaving you thirsting for
more. A very memorable chapter for fans of the nuts and bolts, and yet is not that
heavy a read.

Chapter 7: Compulsive Tuning Disorder, by Gaja Krishna Vaidyanatha

It is time not only for yet another chapter on performance and tuning, but also for a
comedy break. Don't get me wrong, there is just as much substance as the other
chapters, especially for fans of the Oracle Wait Interface.

The most valuable contribution of this chapter is the so-called "Cure for CTD". It is a
2-pronged methodology that focuses both on the OWI and the OS. It is very clearly
summarized on page 235: photocopy it and pass it around to your team. After
explaining the system in very clear and specific terms, the chapter closes with 2
appropriate examples. Even your junior DBAs can now look like pros.

If they had decided there were far too many chapters on performance and tuning
(which there are), and decided to only keep one, this chapter would have my vote.

Chapter 8: New Releases and Big Projects, by James Morle

This essay deals with one particular Oracle project gone bad. It starts where the
author joined in, describing the mess his predecessors had gotten themselves into,
and then all the problems they had to contend with along the way. A fun read.

Chapter 9: Testing and Risk Management, by David Ruthven

"Poor engineering practises remain the root cause of application failures and there
is usually very little in the way of contingency planning to avoid and minimise the
impact of such failures." - David Ruthven.

In this chapter, David Ruthven breaks a database application project down, dividing
it into types and levels, and identifies where they often go wrong. He includes
something for everyone, for example I enjoyed his summary on the ingredients to
an effective development environment. He even helps quench the thirst for more on
Instrumentation that was first whetted in Chapter 2.

The second half of his chapter focuses on testing. He touches on functionality tests,
white box and black box tests, regression tests, automated tests, scalability tests -

http://thinkoracle.blogspot.com/2005_11_01_archive.html (12 of 16)1/9/2008 2:49:56 AM


OracleBlog: November 2005

everything you wish your manager had read about.

Chapter 10: Design Disasters, by Jonathan Lewis

More war stories, for fans of Chapter 8! "Now prepare yourself to read all about 'The
World's Worst Oracle Project.'" - Jonathan Lewis.

This chapter describes some of the most common mistakes in development Oracle
database applications. You'll certainly recognise some of them, because so many
people stubbornly cling to certain beliefs. I know I like to bring up several of his
points when I get into common arguments like these:
1. We want our application to be "Database Independent."
2. We will check data integrity at the application level instead of taking advantage of
Oracle's constraint checking abilities.
3. We want to use sequences for our primary keys.

I won't give away too much of this chapter, but its definitely food for thought for
anyone who has ever been (or plans to be) involved in a database application
development project.

Chapter 11: Bad CaRMa, by Tim Gorman

The book closes with another war story. We get a look at Vision, a custom-built
order-entry and customer-service application (a CRM). "This story is about such an
IT project, the most spectacular failure I have ever experienced." - Time Gorman.
(Why do we enjoy the chapters about failures so much?)

Appendix: Join the BAARF Party, by James Morle and Mogens Norgaard

This is a rant against Raid-5. Check out their web site for more:
http://www.baarf.com/

Overall Impression:
This book has been fairly widely praised throughout the Oracle community. It
received 4.5 out of 5 stars on Amazon.com and even PSOUG's Dan Morgan gave it a
very high recommendation:
http://www.psoug.org/bookrev.html

Personally I would love to see many more books like these. I certainly hope there is
a sequel coming up with even more essays from the most gifted and enthusiastic
authors in the Oracle community. I would even love to see more of these essays
expanded into books. This book is a very fun read, and I guarantee every Oracle
specialist will find several essays within that they will enjoy. High recommendation.

// posted by Robert Vollman @ Wednesday, November 02, 2005 2 comments

http://thinkoracle.blogspot.com/2005_11_01_archive.html (13 of 16)1/9/2008 2:49:56 AM


OracleBlog: November 2005

About Me
Name: Robert Vollman
Location: Calgary, Alberta, Canada

I was born and raised in Ottawa, and have lived in Calgary since 1991. I like
playing sports (hockey, soccer, ultimate, basketball, you name it) and military
board games. I also enjoy reading, walking, and playing with my 2 cats Lilly and Brutus. I'm a
database application specialist, whatever that is.

View my complete profile

Best Links
● Ask Tom Kyte
● Oracle Docs
● Dan Morgan and PSOUG
● Steven Feuerstein
● Jonathan Lewis
● FAQ
● Connor McDonald
● The Oak Table
● Cary Millsap and Hotsos
● Steve Adams and Ixora
● Anjo Kolk and OraPerf
● Dizwell Oracle Wiki
● My Personal Blog

Aggregators
Brian Duff's OraBlogs

❍ Eddie Awad's OracleNA


❍ Pete Finnigan's Aggregator
❍ Oracle's Bloglist
❍ Oracle Base Aggregator

Top Blogs
❍ Oracle's Ask Tom Kyte
❍ Oracle Guru Jonathan Lewis
❍ Blogger of the Year Eddie Awad
❍ Data Warehouser David Aldridge

http://thinkoracle.blogspot.com/2005_11_01_archive.html (14 of 16)1/9/2008 2:49:56 AM


OracleBlog: November 2005

❍ Oracle Geek Lewis Cunningham


❍ Database Expert James Koopmann
❍ Dizwell's Howard Rogers
❍ Oracle Master Laurent Schneider
❍ Security Expert Pete Finnigan
❍ Oracle Award Winner Mark Rittman
❍ Doug Burns
❍ Oracle ACE of the Year Dr. Tim Hall
❍ UKOUG's Andrew (Arfur C.) Clarke
❍ Newbie DBA Lisa Dobson
❍ Coffee-Drinking DBA Jon Emmons
❍ Chris Foot
❍ The Pythian DBA Team Blog
❍ DBA Don Seiler
❍ DBA Coskan Gundogar
❍ Oracle WTF

ARCHIVES
❍ LIST ALL ARTICLES
❍ May 2005
❍ June 2005
❍ July 2005
❍ August 2005
❍ September 2005
❍ October 2005
❍ November 2005
❍ December 2005
❍ January 2006
❍ February 2006
❍ March 2006
❍ April 2006
❍ May 2006
❍ June 2006
❍ July 2006
❍ August 2006
❍ September 2006
❍ October 2006
❍ November 2006
❍ December 2006
❍ January 2007
❍ February 2007
❍ March 2007
❍ April 2007
❍ May 2007

http://thinkoracle.blogspot.com/2005_11_01_archive.html (15 of 16)1/9/2008 2:49:56 AM


OracleBlog: November 2005

❍ June 2007
❍ October 2007

❍ Current Posts

http://thinkoracle.blogspot.com/2005_11_01_archive.html (16 of 16)1/9/2008 2:49:56 AM


OracleBlog: December 2005

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Wednesday, December 21, 2005


Best Of OracleBlog
I got named in ComputerWorld's "Best IT Blogs on the Net." Granted, only
in the "buffer overflow" section, but still - that's pretty cool!

http://www.computerworld.com/blogs/node/1466?source=nlt_blg

Maybe it is another consequence of the Thomas Kyte Effect?

http://thinkoracle.blogspot.com/2005/12/thomas-kyte-effect.html

Anyway, I feel very fortunate for having this new audience, but I feel bad
for having nothing really intelligent to say. So I thought I would link to
some of my favourite earlier posts, and some of my most popular "hits",
to give you an idea of what I like to chat about.

To my more frequent visitors like Doug, Eddie, Laurent, Gary, Peter,


David, William, and so on, as well as any lurkers, I would appreciate
hearing your picks, too.

Here is the brief list of my highlights:

1. NULL

I posted a few articles on this, because there are quite a few errors
casual database programmers may make in their misunderstanding of
NULL and how its treated in Oracle. To put it bluntly, NULL is NOT
nothing! If ever I write a proper article for publication, it will likely be on

http://thinkoracle.blogspot.com/2005_12_01_archive.html (1 of 14)1/9/2008 2:50:00 AM


OracleBlog: December 2005

this topic.

NULL vs Nothing:
http://thinkoracle.blogspot.com/2005/05/null-vs-nothing.html
NULLs in Oracle:
http://thinkoracle.blogspot.com/2005/06/nulls-in-oracle.html
Using NULL to exploit the COUNT/NULL feature:
http://thinkoracle.blogspot.com/2005/10/using-decode-to-exploit-
countnull.html

2. Best Practises

I like to blog a lot on what I feel are best practises for database
programming. Please allow me to pick three of the most general of the
bunch, where I have promoted Views, Constraints and Packages:

Use Views:
http://thinkoracle.blogspot.com/2005/07/use-views.html
Use Constraints:
http://thinkoracle.blogspot.com/2005/07/use-constraints.html
Oracle Packages:
http://thinkoracle.blogspot.com/2005/10/oracle-packages.html

3. Advanced Concepts

Occasionally I blog on a technique that would only come to the attention


of someone who has used Oracle to solve a more complex problem. Here
is one example of that.

Pivot and Crosstab Queries:


http://thinkoracle.blogspot.com/2005/09/pivot-and-crosstab-queries.
html

4. High-Hit Posts

There were two posts that, for various reasons, seem to have higher hit-
counts than the others. Here they are:

Analyzing Query Performance:


http://thinkoracle.blogspot.com/2005/09/analyzing-query-
performance.html
UTL_HTTP:
http://thinkoracle.blogspot.com/2005/08/utlhttp.html

http://thinkoracle.blogspot.com/2005_12_01_archive.html (2 of 14)1/9/2008 2:50:00 AM


OracleBlog: December 2005

5. Putting it all together

In "Oracle by Example" I brought together many concepts into one.


http://thinkoracle.blogspot.com/2005/07/oracle-by-example.html

Throughout my blog you'll also see book reviews, top 20 lists, and lots
of little tips and tricks I discover. As you'll note, I appreciate any
feedback, and I get an email if you leave a comment even on an old post,
so please feel free to do so.

I would also like to direct my new visitors to the blogs I enjoy the most.
You can see the list on the right-hand side, but other than Tom Kyte's,
which you have surely already visited (http://tkyte.blogspot.com), I
would like to draw particular attention to these two:

Doug Burns: http://oracledoug.blogspot.com


Eddie Awad: http://awads.net/wp

I enjoy ALL those blogs, but if you only have time for a couple, please
check those out.

Warning to Doug and Eddie: You might experience the first ever Robert
Vollman Effect!

// posted by Robert Vollman @ Wednesday, December 21, 2005 2 comments

Tuesday, December 20, 2005


The Thomas Kyte Effect
Good grief!

I saw a spike in my statcounter and I checked it out to see if I got


spammed. Instead I am the newest beneficiary of the "Thomas Kyte
Effect."

Well, strictly speaking, the Thomas Kyte Effect is when your blog is
referenced in a blog article of his, but in my case I was simply added to
his list of links. And then bam - several hundred hits today.

With all due respect to Doug, Lisa and Eddie, in one day I've got more
referrals from his blog than everyone else put together.

http://thinkoracle.blogspot.com/2005_12_01_archive.html (3 of 14)1/9/2008 2:50:00 AM


OracleBlog: December 2005

I told Tom we could "cash in" on the "Thomas Kyte Effect" with a few well-
chosen ads, but sadly he wouldn't go for it.

Well, as long as you're all here, I would like to say two things:
1. Welcome to my blog!
2. Please look through my archives, some of my more interesting reads
are in July/August.

Comments are very welcome, even on older posts (I get auto-emailed


when someone posts something).

Also, I like to provide something useful in every post, so here it is: a link
to an article by Steven Feuerstein about how to hide your code:
http://htmldb.oracle.com/pls/otn/f?p=2853:4:6669219410898182474::
NO::P4_QA_ID:4102

// posted by Robert Vollman @ Tuesday, December 20, 2005 1 comments

20 Beginner Oracle Questions


Continuing in my newfound tradition for lists of 20, here is a "cheat
sheet" of 20 common beginner Oracle questions.

Before we begin, one simple warning. Very few of these are complete
answers, consider them pointers or starting points or else the
incomplete understanding could be dangerous.

Edit: This has been highly edited since its original version.

Oracle General:

1. What are the key environment variables?


Among many others, your home and instance:
export ORACLE_HOME=oracle_home_dir
export ORACLE_SID=instance_name

2. How do you shut down or start up an Oracle instance?


Must log on as a sys user:
sqlplus sys/***@instance as sysdba
Then:
shutdown
or
startup

http://thinkoracle.blogspot.com/2005_12_01_archive.html (4 of 14)1/9/2008 2:50:00 AM


OracleBlog: December 2005

3. How do you start and stop a listener?


lsnrctl status
lsnrctl start
lsnrctl stop
http://www.psoug.org/reference/listener.html

4. What are the key Oracle files?


They are in network/admin folder.
tnsnames.ora: list of database connection information (client/server)
sqlnet.ora: communication parameters setup
listener.ora: list of databases to listen for on this machine

5. How do you connect to the database to execute queries?


sqlplus user/password@server_instance
On a default system, sometimes you can use scott/tiger.

6. How do you see the errors from your recently created view/procedure?
show errors;

SQL and PL/SQL:

7. How do you output a line from PL/SQL?


DBMS_OUTPUT.PUT_LINE('Hello.');

8. How do you get the current date?


SELECT sysdate FROM dual;
SELECT systimestamp FROM dual;

9. What are some other syntax considerations?


Commands must end with a semi-colon;
Strings must be single-quoted

SQLPlus:

10. How do you show the structure of a table?


desc table

11. How do I re-execute the most recent query/command?


/

12. How do I see my most recent query?


l (for "list")

13. How do I see the PL/SQL procedure output?

http://thinkoracle.blogspot.com/2005_12_01_archive.html (5 of 14)1/9/2008 2:50:00 AM


OracleBlog: December 2005

SET SERVEROUTPUT ON;

14. How do I execute a SQL file?


@filename.sql

More Advanced:

15. How do I see who is currently connected?


SELECT username, program FROM v$session WHERE username IS NOT
NULL;

Or, courtesy of a colleague of mine, something like this:

SELECT p.SPID "OS_PID", to_char(s.SID,'999') SID, s.serial#,


SUBSTR(p.USERNAME,1,10) "OS_USER", SUBSTR(s.USERNAME,1,16)
"ORACLE_USER",
SUBSTR(TO_CHAR(s.logon_time, 'DD Month YY "at" HH:MI:SS'),1,30)
"LOGON TIME", s.program, s.machine
FROM v$process p, v$session s
WHERE s.PADDR=p.ADDR
AND s.username IS NOT NULL
ORDER BY s.logon_time;

16. How do I find all invalid objects?


Query dba_objects for status = 'INVALID', something like this:
SELECT owner, decode(object_type,'PACKAGE BODY','PACKAGE',
object_type) OBJECT_TYPE, count(object_name)
FROM dba_objects WHERE status = 'INVALID' GROUP BY owner,
object_type;

17. How do I recompile invalid objects?


Must be logged in with privileges, and use this:
@?/rdbms/admin/utlrp.sql

18. How do I compute table and index statistics for a schema?


Answer from Steve Ensslen:
10g: Don't, it can be set up to analyze itself.
Pre-10g: Must be logged in with privileges:
execute DBMS_STATS.GATHER_SCHEMA_STATS('SCOTT');

19. How do I analyze the performance of a query/procedure (query


plans, index choice, etc)?
Many ways, one way is SQL Trace with TKPROF, which I have explained
here:
http://thinkoracle.blogspot.com/2005/09/analyzing-query-

http://thinkoracle.blogspot.com/2005_12_01_archive.html (6 of 14)1/9/2008 2:50:00 AM


OracleBlog: December 2005

performance.html

20. How do I tell which database am I in?


select name from v$database;
or
select instance_name, host_name from v$instance;
or
SELECT SYS_CONTEXT(‘USERENV’,’DB_NAME’) FROM DUAL;
http://thinkoracle.blogspot.com/2005/07/which-instance-am-i-in.html

Bonus:

21. How do I set up an Oracle client?


http://thinkoracle.blogspot.com/2005/06/oracle-client.html

22. How do I get data into and out of Oracle?


http://thinkoracle.blogspot.com/2005/08/import-export.html

// posted by Robert Vollman @ Tuesday, December 20, 2005 12 comments

Monday, December 19, 2005


20 PL/SQL Coding Tips
Gary pointed me to a recent AskTom thread that contained a list of PL/
SQL Coding Practises. The ensuing discussion added a few more, and I'd
like to throw in a few of my own as well. I also think most of these tips
are useful for other languages, but this is first and foremost an Oracle
developer's blog.

Here they are, with the order and wording slightly revised in some cases
(removed the biblical undertones for politically correct reasons), and my
comments after each one. Each of these could be a separate blog on
their own, but I restrained myself to only brief comments.

Design (Pre-Coding):

1. Ask Why

A popular philosophy in the Oracle blogging community, and


championed by Tom Kyte, is the notion of asking why. Why is this code
being written, why is it being done the way that it is, etc.

From Tom Kyte's Blog: http://tkyte.blogspot.com/2005/05/why.html

http://thinkoracle.blogspot.com/2005_12_01_archive.html (7 of 14)1/9/2008 2:50:00 AM


OracleBlog: December 2005

2. Gather requirements thoroughly

Based on the experiences of many, gather all the requirements and do


not begin anything until all parties have agreed on what the end result
will have to be in order to be considered successful.

3. Design, including for scalability and security, first.

With the exception of quasi-prototypes and small proofs of concept, no


coding should begin until it has been designed. This is the time to think
about scalability and security. Those aren't issues to tackle after the fact.

4. Set up proper testing/development/debugging environment

I find that developers are far more effective if they have a reliable,
accurate and convenient environment for testing and debugging. Also, it
is usually better to set that up first, rather than patching something
together on the fly.

5. Use source control

"Consider source control non-optional, and a factor on which your job


depends." - a former director of mine. That simplifies your decision,
doesn't it?

6. Choose the right tools

Notepad and SQL*Plus might work for you now, but for a larger project
you might want to consider a different IDE. You'll also want to look at
source control systems, and code libraries.

7. Write test cases before coding

It seems like many people agree on this rule, but consider it a fantasy
because how often do you see this done in practise? Ideally you would do
this right after #2 (gather requirements thoroughly). That way you can
say "when these tests pass, you are done."

Coding:

8. Check and handle errors

Up front, decide a common way of handling errors in the EXCEPTIONS


block. You can figure out what works best, customer error types, an
error table, an error file, whatever works as long as you are checking and

http://thinkoracle.blogspot.com/2005_12_01_archive.html (8 of 14)1/9/2008 2:50:00 AM


OracleBlog: December 2005

handling all errors.

For starters, check Chapter 7 of the PL/SQL User's Guide and Reference:
Handling PL/SQL Errors:
http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/
a96624.pdf

9. Comment your code

This one resulted in a lot of debate on the thread. No, commenting your
code is not a substitute for making your code readable, but then again,
neither is making your code readable a substitute for commenting.
Indeed, I agree with the one suggestion that you should write your
comments BEFORE you write the code!

10. Use proper indexes

11. Maximise SQL and minimise PL/SQL

There are books written on the efficiency gain of preferring SQL over PL/
SQL.

12. Instrument your code for debugging

Choose your favourite method: debug statements judiciously places


throughout your code, or perhaps using DBMS_PROFILE (that is definitely
a topic I'll do soon), or something else entirely. As long as you have a
way to troubleshoot bugs and performance issues later on.

13. Make use of bulk processing

14. Minimise client code and maximise server code.

Generally servers are more powerful and built for this type of work. You
also want to minimise trips back and forth to the server.

15. Use bind variables, not concatenation

Not just for performance reasons, but also for security (thwart SQL
injection). I think Tom Kyte made his living off this topic for awhile.

I blogged about bind variables once: http://thinkoracle.blogspot.


com/2005/06/bind-variables-in-plsql.html

16. Think in sets.

http://thinkoracle.blogspot.com/2005_12_01_archive.html (9 of 14)1/9/2008 2:50:00 AM


OracleBlog: December 2005

17. Use procedures/functions to name and modularize your code for


reuse

Don't just create one big massive function that does many, specific
things. Best to break it out into specific tasks, which can be optimized
and reused. Also makes you think more about your detailed design.

18. Use unique and meaningful names

Unique names can be found easier in the code with "Find". Meaningful
names make your code easier to understand. If you can't think of a
meaningful name for a procedure/variable, maybe you don't have a clear
idea on its purpose and you need to re-think your design.

Coding and Afterwards:

19. Stress test your code with significant data, and benchmark it

Doesn't matter how much time you spent thinking about performance
and bottlenecks during the design and implementation, you might still
have missed a few things.

20. Perform a code review with your peers.

Code reviews are good to find mistakes, but also for knowledge transfer.
I also think you take more pride in your work when you have the
opportunity to share it, rather than just hide in a cubicle as an
anonymous coder.

Comments are welcome, but I also encourage you to visit the thread and
follow up to the wider audience there:
http://asktom.oracle.com/pls/ask/f?
p=4950:8:18231831513891656743::NO::F4950_P8_DISPLAYID,
F4950_P8_CRITERIA:51960184066540

Steven Feuerstein is also one of my favourite champions on good PL/SQL


programming. Here is a previous blog on one of his articles on
refactoring (the link to which is within):
http://thinkoracle.blogspot.com/2005/05/steven-feuerstein-on-
refactoring.html

// posted by Robert Vollman @ Monday, December 19, 2005 5 comments

http://thinkoracle.blogspot.com/2005_12_01_archive.html (10 of 14)1/9/2008 2:50:00 AM


OracleBlog: December 2005

Thursday, December 15, 2005


Oracle and Perl
I work with several different databases for several different clients on
several different operating systems, often with only remote access to a
shell (as opposed to a desktop). Therefore I like to become familiar with
very common and simple technologies, like vi, sqlplus (for Oracle) and
Perl.

Writing my useful tools in Perl is very handy because I can run them
anywhere, and they can work for all databases just by having a switch on
the connection string. But of course today's example will focus on
Oracle. Perl is also very good at handling and manipulating data: perfect
for database utility scripts.

There are many different ways to write code in Perl. Some refer to Perl as
a write-only language because it is a lot easier to write than it is to read.
But I'll keep my sample simple.

#!/usr/local/perl
use DBI;
# Get a database handle by connecting to the database
$dbh = DBI->connect("dbi:Oracle:host=servername;sid=dbname",
'scott','tiger', {RaiseError => 1, AutoCommit => 1})
or die "Can't connect to database $DBI::errstr\n";
# Put together your query string
my $sql = 'SELECT * FROM emp';
# Instead you could do $dbh->do($sql) or execute
$sth = $dbh->prepare($sql);
while (@rows = $sth->fetchrow_array()) {

# You can access a specific field like this: $rows[0];


print "@rows\t";
}
print "\n";
$sth->finish();
# If you did an update, you could $dbh->commit()
# or $dbh->rollback() before disconnecting
$dbh->disconnect();

For more information, here is a quick and dirty FAQ:

http://thinkoracle.blogspot.com/2005_12_01_archive.html (11 of 14)1/9/2008 2:50:00 AM


OracleBlog: December 2005

http://www.orafaq.com/faqperl.htm

Here are some really good on-line samples


http://www.cri.univ-rennes1.fr/documentations/DBDOracle.html

There is a book on Oracle and Perl that described a bunch of Oracle DBA
utilities written in Perl. I have not read it myself, so check it out before
purchasing (and let me know what you thought).
"Perl for Oracle DBAs" by Andy Duncan and Jared Still
http://www.amazon.com/gp/product/0596002106/002-3253639-
8672853?v=glance&n=283155

// posted by Robert Vollman @ Thursday, December 15, 2005 0 comments

About Me
Name: Robert Vollman
Location: Calgary, Alberta, Canada

I was born and raised in Ottawa, and have lived in Calgary since 1991. I
like playing sports (hockey, soccer, ultimate, basketball, you name it)
and military board games. I also enjoy reading, walking, and playing with my 2 cats
Lilly and Brutus. I'm a database application specialist, whatever that is.

View my complete profile

Best Links
● Ask Tom Kyte
● Oracle Docs
● Dan Morgan and PSOUG
● Steven Feuerstein
● Jonathan Lewis
● FAQ
● Connor McDonald

http://thinkoracle.blogspot.com/2005_12_01_archive.html (12 of 14)1/9/2008 2:50:00 AM


OracleBlog: December 2005

The Oak Table


● Cary Millsap and Hotsos


● Steve Adams and Ixora
● Anjo Kolk and OraPerf
● Dizwell Oracle Wiki
● My Personal Blog

Aggregators
Brian Duff's OraBlogs

❍ Eddie Awad's OracleNA


❍ Pete Finnigan's Aggregator
❍ Oracle's Bloglist
❍ Oracle Base Aggregator

Top Blogs
❍ Oracle's Ask Tom Kyte
❍ Oracle Guru Jonathan Lewis
❍ Blogger of the Year Eddie Awad
❍ Data Warehouser David Aldridge
❍ Oracle Geek Lewis Cunningham
❍ Database Expert James Koopmann
❍ Dizwell's Howard Rogers
❍ Oracle Master Laurent Schneider
❍ Security Expert Pete Finnigan
❍ Oracle Award Winner Mark Rittman
❍ Doug Burns
❍ Oracle ACE of the Year Dr. Tim Hall
❍ UKOUG's Andrew (Arfur C.) Clarke
❍ Newbie DBA Lisa Dobson
❍ Coffee-Drinking DBA Jon Emmons
❍ Chris Foot
❍ The Pythian DBA Team Blog
❍ DBA Don Seiler
❍ DBA Coskan Gundogar
❍ Oracle WTF

ARCHIVES
❍ LIST ALL ARTICLES

http://thinkoracle.blogspot.com/2005_12_01_archive.html (13 of 14)1/9/2008 2:50:00 AM


OracleBlog: December 2005

❍ May 2005
❍ June 2005
❍ July 2005
❍ August 2005
❍ September 2005
❍ October 2005
❍ November 2005
❍ December 2005
❍ January 2006
❍ February 2006
❍ March 2006
❍ April 2006
❍ May 2006
❍ June 2006
❍ July 2006
❍ August 2006
❍ September 2006
❍ October 2006
❍ November 2006
❍ December 2006
❍ January 2007
❍ February 2007
❍ March 2007
❍ April 2007
❍ May 2007
❍ June 2007
❍ October 2007

❍ Current Posts

http://thinkoracle.blogspot.com/2005_12_01_archive.html (14 of 14)1/9/2008 2:50:00 AM


OracleBlog: January 2006

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Tuesday, January 24, 2006


Gathering Requirements
I wanted to briefly follow up on Tip #2 on my recent post about PL/
SQL Coding.
http://thinkoracle.blogspot.com/2005/12/20-plsql-coding-tips.html

I am not intending to convince anyone WHY they should spend time


gathering requirements, but rather simply HOW to do it. However, let
it be known that there are people whose careers are entirely based
on the requirements gathering process, that there are volumes of
books on the subject, and there exists methods much more
sophisticated and involved that what I am going to describe here.

This post is understandably technology-independent, which is good


because it is based on my experience along with some articles I've
read recently, which has involved a variety of industries and
technologies.

Step 1: State Your Vision

Before prattling off a list of what the software must do, you should
start by naming some clear, concise key objectives. The basic idea is
that all the requirements you are about to list match these key
objectives.

Ideally I like to mention in this brief opening statement how the


stakeholder's needs can be fulfilled, pain reduced, and/or gain
received.

http://thinkoracle.blogspot.com/2006_01_01_archive.html (1 of 17)1/9/2008 2:50:04 AM


OracleBlog: January 2006

What Are Requirements?

A requirement is based on a specific business-driven need that is


necessary to accomplish the stated project vision. Each requirement
should be enumerated (or otherwise identifiable), and should only
describe WHAT should be provided, not HOW, and should thus not
necessarily discuss implementation details. A requirement should
also be testable/verifiable, and mention how that is planned to be
done.

As I alluded to in Tip #1, my conviction is that the rationale behind a


requirement is a necessary step. By explaining WHY something is
necessary we can help keep the requirements complete, clear,
concise, consistent and maybe some other things that start with c.

Depending on the application, requirements can be related to the


functionality, the business interaction (with users), or the technical
requirements (eg: time, space, performance, scalability, security,
disaster recovery).

For example, requirements can include anything from business rules,


the budget, the interface (web-based vs desktop), reporting abilities,
performance (number of concurrent users), completion date/
schedule, security needs, hardware, software, error/fault-tolerance,
user technical level, system maintenance requirements, and so on.

How to Gather Requirements

Is this a brand new product, or is it meant to either replace or


compete with another product? If the latter, you should evaluate what
that product does, and how it can be improved.

Identify all the stakeholders, such as users, management and the


nerds (technical folk). Talk to them either one-on-one or in groups.

Techniques

In my experience, I simply write a document. For more sophisticated


approaches, you can look into use-case models, unified modeling
language (UML), automatic requirements generation tools,
prototypes, storyboard, agile software development or any other host
of techniques.

One word about prototypes. Go ahead and use prototypes to help

http://thinkoracle.blogspot.com/2006_01_01_archive.html (2 of 17)1/9/2008 2:50:04 AM


OracleBlog: January 2006

users express their needs. But when you're done, throw the prototype
away. Tell management that a quality product will take time to
develop, and working with hastily-thrown together prototype code is
just going to wind up with a real mess. Trust me: Chuck it!

Common Requirements Errors

Based on some research articles, the most common types of errors


when writing requirements are (in order):
1. Incorrect assumptions
2. Omitted requirements
3. Inconsistent requirements
4. Ambiguous requirements

What's Next?

Remember that requirements gathering is a cyclical process. Despite


having a single author responsible for this document, there should
be several stakeholders conducting several rounds of reviews and
inspections. In fact, you should have a way to track the history of the
requirements document, and it should be possible to revise it, even
after it is finalized (this is the real world, after all).

Prioritize your requirements. You may even want to move some


requirements to a "future release" section.

In my requirements document, I als like to add the following sections:


1. A list of all the assumptions that were made during the
requirements gathering process, and why.
2. A list of constraints on either the software, the design, or the
development process
3. A reference to any industry standards to which you want the
software to conform (eg: ANSI SQL), and why.
4. A summary of how we expect the system to be used: how many
concurrent users, transactions per day, etc.
5. Project-specific details, like the manpower, time, skill sets,
deadlines, licenses, equipment that will be needed.
6. A project glossary of terms used in this application, including
acronyms.

Granted this was just one man's very basic look at requirements
gathering, but for many small to mid-sized projects, that should get
us started in the right direction.

http://thinkoracle.blogspot.com/2006_01_01_archive.html (3 of 17)1/9/2008 2:50:04 AM


OracleBlog: January 2006

// posted by Robert Vollman @ Tuesday, January 24, 2006 2 comments

Friday, January 20, 2006


Odds and Ends
PL/SQL vs J2EE, Part 2

I knew there was going to be some discussion following up my


previous post on using stored procedures instead of embedding SQL
in your J2EE application. Some of it you can read in the comments,
others you can find on other people's blogs.

Original Article
Tim Hall's Response (and Here).
Harry Boswell's Response
Dizwell Discussion: Database Independence

I also saw a similar discussion that had taken place over a year ago.
Check out these posts by Mark Rittman and Dave Warnock for a
Point-Counterpoint on the debate.

Mark Rittman
Dave Warnock's Response

Gary Myers and Harold Ramis Separated At Birth

Gary Myers

http://thinkoracle.blogspot.com/2006_01_01_archive.html (4 of 17)1/9/2008 2:50:04 AM


OracleBlog: January 2006

Harold Ramis

In seriousness, I've enjoyed Gary Myers' blog for quite some time, but
I particularly enjoyed his recent series of blogs on the 12 SELECTs of
Christmas, so I thought I would highlight it for you to enjoy again.
12 Selects of Christmas, Part I
12 Selects of Christmas, Part II
12 Selects of Christmas, Part III
12 Selects of Christmas, Part IV

Neat Tricks

Some time ago I posted an article on UTL_HTTP that gave Pete


Finnigan a security-related heart attack. Just when he was
recovering, Doug Burns posted a neat little trick that will give him
another stroke. Apparently within SQL*Plus you can execute an SQL
script somewhere on the Internet. Try it!

UTL_HTTP Post
Pete Finnigan
Doug Burns

Blog Updates

I've noticed Tony Andrews, whose blog I quoted in my last post, has
some new content including an interesting So Doku Solver in PL/SQL.
Check it out here, and hope he continues to post:
Tony Andrews PL/SQL So Doku Solver

Another new Oracle blog to check out is Yas'. I've enjoyed several of
his postings recently, so its hard to pick just one to highlight, but

http://thinkoracle.blogspot.com/2006_01_01_archive.html (5 of 17)1/9/2008 2:50:04 AM


OracleBlog: January 2006

given its similarity to my recent post on Bulk Binding and FORALL,


here is one on BULK COLLECT.
My FORALL
Yas' BULK COLLECT

Ask Tom

I spend a fair bit of my Oracle web-surfing time over on AskTom. If


you ask many of us, we'll say its an invaluable source of information,
and also houses some very interesting discussions. Here are three
samples of discussions I've been following recently.

Driving Tables
Introduction to Analytical Functions
Batch Processing

Old Post Updates

The original intention of this blog was to have a place to organise my


thoughts on things that I have learned about Oracle. Therefore,
generally a post here is merely one of the early stages of my
exploration on a particular topic. I usually continue my exploration,
and doubtlessly continue to find interesting articles on the same
topics. Here are two examples.

You may have noticed that I talk a lot about NULL, how funny it is,
and how misunderstandings lead to errors. I mentioned recently that
if I were to write an article it would probably be about NULLs. I was
flipping through an Oracle magazine I had missed from last Summer
and saw that Lex de Haan and Jonathan Gennick had beaten me to it.
Nulls: Nothing to Worry About

Last Fall I blogged on using ROWNUM and ROWID, and I just recently
found an awesome post on AMIS to demonstrate the power of using
ROWNUM to improve performance.
Original Post on ROWNUM
Alex Nuijten on ROWNUM

Finally

My final order of business is related to Oracle only in that it involves


one of our favourite PL/SQL experts, Steven Feuerstein. Steven
recently started a personal blog, and even posted an article in
response to a questionable comment I left on Eddie's Blog.

http://thinkoracle.blogspot.com/2006_01_01_archive.html (6 of 17)1/9/2008 2:50:04 AM


OracleBlog: January 2006

Eddie Awad
Steven Feuerstein is a nut?

But rather than talk about nuts, I would really like to highlight just
how much Steven Feuerstein's work has helped me, and how it can
help others. You can see my blog is littered with examples, here is
another, about how to hide your code:

Steven Feuerstein Q&A: Hiding PL/SQL


My Article about Steven Feuerstein on Refactoring

// posted by Robert Vollman @ Friday, January 20, 2006 0 comments

Wednesday, January 18, 2006


PL/SQL vs J2EE
Let's say you're designing an enterprise-wide OLTP Web Application
with Data Warehousing, Reporting and multiple interfaces to various
external systems for large volumes of data. Where do you put your
business logic? Do you embed your SQL into your Java code, or do
you keep your SQL in the database, and write stored procedures?

Regardless of your answer, you are wandering into one of the older
and more heated arguments in this community. (Classic examples of
one: here and here) I don't mean to re-ignite it, but I do want to
understand it.

"It is a religious war though, they cannot be won by reason or


objectivity." - Tom Kyte

It would appear like Java programmers hate stored procedures. They


are viewed as hard to maintain, and not scalable. To them, scalability
means spreading out the workload, running on several small
machines.

Some don't even like to write the SQL themselves, instead preferring
to use a framework like Hybernate or TopLink do it, and then rest
their heads on their pillows at night dreaming of fewer errors/
portability issues and better performance. But even if they can't
achieve the better performance the database guys keep bragging
about, they're more than happy to accept greater ease of
development and maintainability in exchange.

http://thinkoracle.blogspot.com/2006_01_01_archive.html (7 of 17)1/9/2008 2:50:04 AM


OracleBlog: January 2006

Plus, Java programmers love choices. Lots of tools, unit testing


packages, libraries - all open source - not to mention a huge
community. They wouldn't want to get attached to any database
vendor, especially one that is expensive and proprietary.

"If you want portability keep logic out of SQL." - Martin Fowler

At the other end of the spectrum are the database specialists. They
walk around with print-outs of all the horrible SQL statements Java
programmers have written that are choking the database, with
serialization and loads of parsing. "Leave the SQL to us!" they plead
in vain, "it's too hard for you, especially with this crappy database
design!" They may secretly admire the Java progammers ability to
write procedural or object-oriented code, but they believe that they
lack the key to unlocking database performance: "set-based"
mentality.

They look at a Java application and all they can see if multiple
database trips where the SQL could have been combined into a single
stored procedure making one trip. They examine their EJB containers
and then lecture the programmers on recognising and understanding
the difference between read-write and read-only situations.

The database specialist isn't as impressed by the Java programmer's


triumphant removal from database dependence, for if you aren't
tying yourself to a database you are losing out on all its power.

Where does that leave us?

The fundamental question is where the business logic should be.

The Java programmer, who sometimes refers to it as domain logic,


wants business logic out of the database, often in the name of
database independence. Even without this argument, they see live or
non-relational data, in different formats, much of it transient and
with complex rules ... why write piles of unmaintainable PL/SQL for
that? They may concede that some validation constraints are OK, but
even that isn't for sure.

Here is an argument on avoiding putting your Domain Logic into SQL,


from none other than Martin Fowler:
http://www.martinfowler.com/articles/dblogic.html

"Do not use stored procedures to implement business logic. This

http://thinkoracle.blogspot.com/2006_01_01_archive.html (8 of 17)1/9/2008 2:50:04 AM


OracleBlog: January 2006

should be done in Java business objects." - Rod Johnson

The database specialist views business rules as data rules and thus
belongs close to the data. If there are some business rules or
business relationships between various entities, well that should be
enforced in the same place where the data is stored: the database.
You've bought expensive, sophisticated software capable of
managing your data in a fast, reliable, scaleable way: use it!

Consider a very simple argument put forward by database specialist


Tony Andrews about putting the business logic in the database:
http://tonyandrews.blogspot.com/2005/04/business-logic-apis.html

Here is an article about a database-centric approach to J2EE


application development:
http://www.oracle.com/technology/pub/articles/odtug_award.pdf

A Final Plea

I don't think there really is a right answer and a wrong answer in


general terms. But armed with an awareness of the debate, its basic
framework and a few starting points, we can make the decisions that
make sense on a project-by-project basis.

Note: This is one of the first times I've put up a non-technical post,
so I'll be curious if there is any demand for more.

// posted by Robert Vollman @ Wednesday, January 18, 2006 15 comments

Tuesday, January 17, 2006


Bulk Binding: FORALL
When writing your PL/SQL stored procedure bear in mind that SQL
statements are still sent to the SQL Engine as opposed to the PL/SQL
Engine. Therefore in cases where you are executing several SQL
statements in a loop, the resulting context switches could cause a
noticeable performance problem.

One solution to this performance solution is the use of "bulk


binding." What is that? Well first, you may recall that binding
variables allows you to tie the current value of a variable into an SQL
statement.
http://thinkoracle.blogspot.com/2005/06/bind-variables-in-plsql.

http://thinkoracle.blogspot.com/2006_01_01_archive.html (9 of 17)1/9/2008 2:50:04 AM


OracleBlog: January 2006

html

"Bulk Binding" refers to a process whereby you can tie the current
values of all the elements in an entire collection into a single
operation. By using bulk binds, only one context switch is made
between the PL/SQL and SQL Engines, to pass the entire collection,
thus avoiding those performance issues.

So how is this done? In this case, using FORALL.

Let's look at an example from the Oracle documentation of how you


might do something without any knowledge of bulk binding:

DECLARE
TYPE NumList IS VARRAY(20) OF NUMBER;
depts NumList := NumList(10,30,70);
BEGIN
FOR i IN depts.FIRST..depts.LAST LOOP
UPDATE emp SET sal = sal + 100 WHERE deptno = depts(i);
END LOOP;
END;

Using timing techniques I've explained before, here is what I came up


with:
http://thinkoracle.blogspot.com/2005/09/analyzing-query-
performance.html

call count cpu elapsed disk query


------- ------ -------- ---------- ---------- ----------
Parse 1 0.00 0.00 0
0
Execute 3 0.01 0.00 0
9
Fetch 0 0.00 0.00 0
0
------- ------ -------- ---------- ----------
----------
total 4 0.01 0.00 0
9

Instead, we can use FORALL like this:

http://thinkoracle.blogspot.com/2006_01_01_archive.html (10 of 17)1/9/2008 2:50:04 AM


OracleBlog: January 2006

DECLARE
TYPE NumList IS VARRAY(20) OF NUMBER;
depts NumList := NumList(10,30,70);
BEGIN
FORALL i IN depts.FIRST..depts.LAST
UPDATE emp SET sal = sal + 100 WHERE deptno = depts(i);
END;

And get this:

call count cpu elapsed disk query


------- ------ -------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0
Execute 1 0.00 0.01 0 9
Fetch 0 0.00 0.00 0 0
------- ------ -------- ---------- ---------- ----------
total 2 0.00 0.01 0 9

Notice 1 execute instead of 3. Of course we won't see any


performance difference on a small sample size, but here I am just
illustrating the point.

You may notice the absense of the keyword "LOOP" in the FORALL
example. That is because despite its similar appearances and syntax
in this example, FORALL is not a loop. It takes a single SQL
statement, and the index i can be used only as an index into the
collection.

You can find more information about FORALL in the PL/SQL User's
Guide and Reference: http://download-west.oracle.com/docs/cd/
B10501_01/appdev.920/a96624.pdf

Another useful trick is the use of SQL%BULK_ROWCOUNT (SQL is the


implicit cursor used by the SQL engine for DML operations). It can be
indexed the same way as the collection.

DECLARE
TYPE NumList IS VARRAY(20) OF NUMBER;
depts NumList := NumList(10,30,70);
BEGIN
FORALL i IN depts.FIRST..depts.LAST
UPDATE emp SET sal = sal + 100 WHERE deptno = depts(i);

http://thinkoracle.blogspot.com/2006_01_01_archive.html (11 of 17)1/9/2008 2:50:04 AM


OracleBlog: January 2006

FOR i IN depts.FIRST..depts.LAST LOOP


DBMS_OUTPUT.PUT_LINE('Affected Rows for ' || depts(i) || ' is ' || SQL%
BULK_ROWCOUNT(i));
END LOOP;
END;

Affected Rows for 10 is 3


Affected Rows for 30 is 6
Affected Rows for 70 is 0

The only error I can foresee getting with FORALL is this one:
ORA-22160: element at index does not exist
And you will only get that if you are somehow binding to an index
that does not exist.

You may also get complaints if you use the index in an expression,
which is not supported:
PLS-00430: FORALL iteration variable i is not allowed in this context

Now that I've spoken about avoiding unnecessary context switches


executing SQL statements, what about unnecessary context switches
in getting information FROM the SQL engine? Are those avoidable?
Yes, using BULK COLLECT. I'll write more about that shortly.

Links:
Dan Morgan has more than just a reference on this topic, he has lots
of really good examples: http://www.psoug.org/reference/
bulk_collect.html

There is also a short but good write-up on bulk binding in the


Application Developer's Guide: Fundamentals, look under Chapter 9:
http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/
a96590.pdf

Dr. Tim Hall has some several good write-ups with good examples:
http://www.oracle-base.com/articles/8i/BulkBinds8i.php

// posted by Robert Vollman @ Tuesday, January 17, 2006 1 comments

Sunday, January 15, 2006


Oracle DO NOTs
http://thinkoracle.blogspot.com/2006_01_01_archive.html (12 of 17)1/9/2008 2:50:04 AM
OracleBlog: January 2006

Here is another interesting discussion taking place on AskTom about


Oracle DO NOTs:

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::
F4950_P8_DISPLAYID:53901314988148

After Tom responded, a lot of people got into it. I had some ideas
myself, but decided not to make one of my famous Top 20 Lists after
all, since it wound up similar to this one:

http://thinkoracle.blogspot.com/2005/12/20-plsql-coding-tips.html

For those of you who are curious, here is more or less what was
covered by Tom or his guests:

Tom:
1. Don't accept string literals from end users and concatenate them
into your SQL. In other words, use binds. This isn't just for efficiency,
its more to prevent execution of malicious code. Yes, I know I did
this one when demonstrating DBMS_PIPE.http://thinkoracle.blogspot.
com/2005/11/dbmspipe.html

2. Don't test on an empty or near-empty database (you need real


volumes)

3. Don't test with a single user (you'll miss scalability issues)

4. Don't forget to use a source control system.

5. Don't wing it as you go along, design in advance.

One responded (our buddy Bill) that you shouldn't do anything


without a spec.

6. Don't take advice from experts without testing to see if it applies


to you.

7. Don't optimize by hypothesize. Test!

From Others:

8. Don't reinvent the wheel, use built-in packages

9. Don't ignore the Oracle documentation, there is a wealth of


information there.

http://thinkoracle.blogspot.com/2006_01_01_archive.html (13 of 17)1/9/2008 2:50:04 AM


OracleBlog: January 2006

10. Don't use technologies because they are cool.

11. Don't hesitate to throw away bad code, rewriting can be better
than refactoring.

This actually resulted in some debate. Sometimes you want to let


sleeping dogs lie. That is, if the code works, don't spend days re-
factoring it unless you need to.

12. Don't write code without documentation/comments

Here is a great language-neutral link: http://tlug.up.ac.za/old/


htwuc/unmain.html

13. Don't name variables arbitrarily.

14. Don't skip your unit-testing

15. Don't comment your SQL to override the optimizer plan unless
you are sure.

16. Don't forget to update comments when you update code.

17. Don't forget to instrument your code.

What is instrumentation? Well, read Mogens Norgaard, or start with


this link:
http://tkyte.blogspot.com/2005/06/instrumentation.html

18. Don't forget to mention dependencies when commenting code.

19. Don't expect the same database on two different hosts to work
exactly the same.

20. Don't modify init.ora parameters without documenting the


originals.

21. Don't neglect to collect histogram data when you run stats.

Well this may have turned into a Top 20 (well, 21) list, but none of
these are my own. If you find this interesting, the link to the
discussion is at the top.

// posted by Robert Vollman @ Sunday, January 15, 2006 0 comments

http://thinkoracle.blogspot.com/2006_01_01_archive.html (14 of 17)1/9/2008 2:50:04 AM


OracleBlog: January 2006

About Me
Name: Robert Vollman
Location: Calgary, Alberta, Canada

I was born and raised in Ottawa, and have lived in Calgary since 1991. I
like playing sports (hockey, soccer, ultimate, basketball, you name it)
and military board games. I also enjoy reading, walking, and playing with my 2 cats
Lilly and Brutus. I'm a database application specialist, whatever that is.

View my complete profile

Best Links
● Ask Tom Kyte
● Oracle Docs
● Dan Morgan and PSOUG
● Steven Feuerstein
● Jonathan Lewis
● FAQ
● Connor McDonald
● The Oak Table
● Cary Millsap and Hotsos
● Steve Adams and Ixora
● Anjo Kolk and OraPerf
● Dizwell Oracle Wiki
● My Personal Blog

Aggregators
❍ Brian Duff's OraBlogs
❍ Eddie Awad's OracleNA
❍ Pete Finnigan's Aggregator

http://thinkoracle.blogspot.com/2006_01_01_archive.html (15 of 17)1/9/2008 2:50:04 AM


OracleBlog: January 2006

❍Oracle's Bloglist
❍ Oracle Base Aggregator

Top Blogs
❍ Oracle's Ask Tom Kyte
❍ Oracle Guru Jonathan Lewis
❍ Blogger of the Year Eddie Awad
❍ Data Warehouser David Aldridge
❍ Oracle Geek Lewis Cunningham
❍ Database Expert James Koopmann
❍ Dizwell's Howard Rogers
❍ Oracle Master Laurent Schneider
❍ Security Expert Pete Finnigan
❍ Oracle Award Winner Mark Rittman
❍ Doug Burns
❍ Oracle ACE of the Year Dr. Tim Hall
❍ UKOUG's Andrew (Arfur C.) Clarke
❍ Newbie DBA Lisa Dobson
❍ Coffee-Drinking DBA Jon Emmons
❍ Chris Foot
❍ The Pythian DBA Team Blog
❍ DBA Don Seiler
❍ DBA Coskan Gundogar
❍ Oracle WTF

ARCHIVES
❍ LIST ALL ARTICLES
❍ May 2005
❍ June 2005
❍ July 2005
❍ August 2005
❍ September 2005
❍ October 2005
❍ November 2005
❍ December 2005
❍ January 2006
❍ February 2006
❍ March 2006
❍ April 2006
❍ May 2006

http://thinkoracle.blogspot.com/2006_01_01_archive.html (16 of 17)1/9/2008 2:50:04 AM


OracleBlog: January 2006

❍ June 2006
❍ July 2006
❍ August 2006
❍ September 2006
❍ October 2006
❍ November 2006
❍ December 2006
❍ January 2007
❍ February 2007
❍ March 2007
❍ April 2007
❍ May 2007
❍ June 2007
❍ October 2007

❍ Current Posts

http://thinkoracle.blogspot.com/2006_01_01_archive.html (17 of 17)1/9/2008 2:50:04 AM


OracleBlog: March 2006

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be complicated,
but it is the most powerful tool when it comes to data. That's why when I think data, I think Oracle. I
also enjoy writing, so I use this format to organise my thoughts. Please feel free to discuss any
thoughts you may have on the same topics, even old ones (I will see and respond to such comments).
You may want to start with "LIST ALL ARTICLES" under Archives.

Wednesday, March 29, 2006


About Me
Optimizer Name: Robert
There is a great debate in the database application Vollman
development community. I have encountered many Location: Calgary,
developers who prefer putting all their business logic in Alberta, Canada
the application code and using the database only as a
glorified file system. I was born and raised in Ottawa,
and have lived in Calgary since
You pick your battles carefully with these developers. I
1991. I like playing sports
always thought the "line of last defense" was data
(hockey, soccer, ultimate,
integrity rules. When I encountered a particularly
basketball, you name it) and
stubborn developer, I decided that I would focus on
military board games. I also
convincing him to, at the very least, use his expensive
enjoy reading, walking, and
RDBMS to protect his data's integrity (through use of
playing with my 2 cats Lilly and
constraints and keys).
Brutus. I'm a database
However, I have learned that there is actually a whole application specialist, whatever
other battlefield to my rear. I just came across a that is.
database application that overrides the optimizer. Every
database query this application ever executes includes a View my complete profile
forced index.

What do I mean? Why does that bother me? Let me take a


short step back to explain what I mean.
Best Links
● Ask Tom Kyte
Think about when you execute a query to access some ● Oracle Docs
data. That data you are requesting could be from several ● Dan Morgan and PSOUG
tables, spread all over the disk. The optimizer does many ● Steven Feuerstein
things, among them to choose how every query is ● Jonathan Lewis
executed. That means, for instance, it selects in which ● FAQ
order the tables will be joined, and which indexes will be ● Connor McDonald
used to access the data. ● The Oak Table
Cary Millsap and Hotsos
In the past, presumably when this application was

written, Oracle used a rule-based optimizer (RBO), which ● Steve Adams and Ixora

http://thinkoracle.blogspot.com/2006_03_01_archive.html (1 of 15)1/9/2008 2:50:08 AM


OracleBlog: March 2006

used a set of rules to determine how to access the data. ● Anjo Kolk and OraPerf
The RBO did not always make ideal choices. Neither did ● Dizwell Oracle Wiki
the early versions of the cost-based optimizer (CBO). ● My Personal Blog
That is why many developers took advantage of their
ability to override the optimizers and tell it (for example)

Aggregators
which join order or indexes to use.

But that's the past. Let's talk about the present.


Brian Duff's OraBlogs

For several years now, I've never experienced a ❍ Eddie Awad's OracleNA
legitimate need to override the optimizer. Usually re- ❍ Pete Finnigan's Aggregator
generating my DBMS_STATS is all I need to do in order to ❍ Oracle's Bloglist
guarantee good choices. ❍ Oracle Base Aggregator

As Jonathan Lewis describes in his latest book Cost-


Based Oracle Fundamentals, the CBO has come a long
Top Blogs
Oracle's Ask Tom Kyte
way. You are doing yourself a great disservice when you

Oracle Guru Jonathan Lewis


aren't updating your applications to take advantage of it.

❍ Blogger of the Year Eddie Awad


Both his book, and Oracle's Database Performance and ❍ Data Warehouser David Aldridge
Tuning Guide describe the optimizer in more detail, and ❍ Oracle Geek Lewis Cunningham
present the various ways you can leverage its power. I ❍ Database Expert James Koopmann
really can't think of any reason why we still need to fight ❍ Dizwell's Howard Rogers
these battles with even the most stubborn of developers. ❍ Oracle Master Laurent Schneider
❍ Security Expert Pete Finnigan
// posted by Robert Vollman @ Wednesday, March 29, 2006 5 ❍ Oracle Award Winner Mark
Rittman
comments
❍ Doug Burns
❍ Oracle ACE of the Year Dr. Tim
Tuesday, March 28, 2006 Hall
UKOUG's Andrew (Arfur C.) Clarke
Bookmark This Page ❍

Newbie DBA Lisa Dobson


To ease the task of browsing my archives, I've put

together an organised list of my previous posts. ❍ Coffee-Drinking DBA Jon Emmons


Bookmark this, because I will keep it up to date. I will ❍ Chris Foot
also include a link to this post under Archives. ❍ The Pythian DBA Team Blog
❍ DBA Don Seiler
Note: If you comment on an older article, I will get an ❍ DBA Coskan Gundogar
automatic email. So I will see it and I will respond to it, ❍ Oracle WTF
so please feel free to do so!

For Newbies:
ARCHIVES
❍ LIST ALL ARTICLES
Tuesday, December 20, 2005 ❍ May 2005
20 Beginner Oracle Questions ❍ June 2005
❍ July 2005
Friday, June 17, 2005 ❍ August 2005
Asking For Help - Tips on where to go and how to do it.
❍ September 2005
October 2005
Wednesday, July 19, 2006

http://thinkoracle.blogspot.com/2006_03_01_archive.html (2 of 15)1/9/2008 2:50:08 AM


OracleBlog: March 2006

Finding Information - How do you find answers to other ❍ November 2005


questions? ❍ December 2005
❍ January 2006
Thursday, July 14, 2005 ❍ February 2006
Oracle Docs - For when people tell you to RTFM! ❍ March 2006
April 2006
Best Practises:

❍ May 2006
Thursday, October 19, 2006 ❍ June 2006
3 Easy Ways to Improve Your PL/SQL - Improving your ❍ July 2006
code through instrumentation and bulk processing. ❍ August 2006
❍ September 2006
Friday, March 09, 2007 ❍ October 2006
40 Tips From Tom (Kyte) ❍ November 2006
❍ December 2006
Tuesday, June 14, 2005
January 2007
Bind Variables in PL/SQL - Short answer: PL/SQL binds

February 2007
all variables (with some exceptions like dynamic SQL)

❍ March 2007
Tuesday, January 24, 2006 ❍ April 2007
Gathering Requirements ❍ May 2007
❍ June 2007
Wednesday, March 01, 2006 ❍ October 2007
Handling exceptions - A how-to guide.
❍ Current Posts
Friday, March 10, 2006
Handling Performance Issues

Wednesday, August 17, 2005


Keeping Tables Small - In terms of number of rows, not
columns. Improve performance.

Monday, October 31, 2005


Oracle Packages - And why/how you should use them.

Monday, July 11, 2005


Specifying INSERT Columns - Why it's a good habit.

Wednesday, May 18, 2005


Steven Feuerstein on Refactoring

Tuesday, July 26, 2005


Use Constraints - A how-to guide for people to whom I
BEG to let the database handle the data's integrity.

Monday, July 25, 2005


Use Views - Why they're handy.

Tuesday, September 12, 2006


Using Numerical Fields - Don't use them for fields that

http://thinkoracle.blogspot.com/2006_03_01_archive.html (3 of 15)1/9/2008 2:50:08 AM


OracleBlog: March 2006

aren't real numbers.

Oracle Packages:

Wednesday, October 12, 2005


DBMS_OUTPUT.PUT_LINE

Thursday, November 24, 2005


DBMS_PIPE - For communication between sessions

Sunday, August 14, 2005


UTL_HTTP - Including an example of how to get a stock
quote from the Internet.

Top 20 Lists:

Sunday, January 15, 2006


Oracle DO NOTs - From AskTom

Tuesday, December 20, 2005


20 Beginner Oracle Questions

Monday, September 12, 2005


20 Oracle Lessons - After my first few months of
blogging.

Monday, December 19, 2005


20 PL/SQL Coding Tips - Inspired by an AskTom thread

Tuesday, October 17, 2006


Software Vendor Customer Support - How to improve
your luck when dealing with support (ok there are only
14)

Book Reviews:

Wednesday, June 22, 2005


Expert One-on-One - A couple of mistakes from my
favourite Oracle book.

Monday, May 16, 2005


Optimizing Oracle Performance (Millsap, Holt)

Wednesday, November 02, 2005


Oracle Insights: Tales of the Oak Table

Thursday, June 23, 2005


PL/SQL Books - A list of my three favourite PL/SQL books

Templates:

http://thinkoracle.blogspot.com/2006_03_01_archive.html (4 of 15)1/9/2008 2:50:08 AM


OracleBlog: March 2006

Thursday, June 30, 2005


OOP in PL/SQL? Yep

Wednesday, July 13, 2005


Stored Procedure template

Great Debates:

Tuesday, June 21, 2005


Natural vs Synthetic keys - Choosing primary keys.

Wednesday, March 29, 2006


Optimizer - Should we be overriding it in our application?

Monday, September 19, 2005


PL/SQL Code Storage: Files vs In-DB Packages

Wednesday, January 18, 2006


PL/SQL vs J2EE - Where should you put the business
logic?

NULLs:

Friday, September 09, 2005


NULLs in COUNT - Why counting on a column might get
you a different total.

Friday, June 10, 2005


NULLs in Oracle

Tuesday, May 17, 2005


NULL vs Nothing - ANSI SQL is unlike programming
languages because NULL is not nothing.

Gotchas!

Monday, June 13, 2005


Blank Lines and SQLPlus

Friday, May 20, 2005


Multiple Foreign Keys on the Same ID

Monday, July 04, 2005


SQLCODE and SQLERRM in INSERTs

How-To Guides:

Wednesday, September 14, 2005


Analyzing Query Performance - using SQLTRACE and

http://thinkoracle.blogspot.com/2006_03_01_archive.html (5 of 15)1/9/2008 2:50:08 AM


OracleBlog: March 2006

TKPROF

Friday, May 04, 2007


ANSI Joins - Or do you want to stick with the old school
style?

Tuesday, February 14, 2006


BPEL - For SOA

Tuesday, January 17, 2006


Bulk Binding: FORALL - Improve performance of bulk
updates.

Thursday, September 22, 2005


Column Name as a Variable

Thursday, June 16, 2005


Common Table Column Types - Two tables with columns
on the same type, but not actually related.

Wednesday, August 24, 2005


COMPUTE - How to emulate a feature found in other
languages

Saturday, June 18, 2005


Connect By - Heirarchical queries, something you need
to know.

Monday, June 20, 2005


Decode - CASE's precursor.

Thursday, November 10, 2005


DUAL Table - You've seen it, what is it?

Thursday, May 19, 2005


Dynamically assigning size of varchar2 - You do it in
other languages, can you do it in PL/SQL (and how)?

Wednesday, May 25, 2005


ENUM in Oracle - Emulating a common programming
feature in PL/SQL.

Friday, July 01, 2005


Extra Columns in a GROUP BY

Tuesday, May 09, 2006


Finding Nearby Rows. Three methods of solving similar
requirements.

Monday, August 01, 2005

http://thinkoracle.blogspot.com/2006_03_01_archive.html (6 of 15)1/9/2008 2:50:08 AM


OracleBlog: March 2006

Import Export

Monday, May 28, 2007


Multirow Inserts - Does Oracle support the ANSI SQL
standard of inserting multiple rows? No. But here's how
you can fake it.

Thursday, May 26, 2005


NOCOPY Hint - Improve performance by changing how
variables are passed to PL/SQL procedures.

Saturday, July 23, 2005


Oracle BOOLEAN - PL/SQL has BOOLEAN, here's how to
emulate it in Oracle's SQL

Friday, July 29, 2005


Oracle By Example - Bringing several concepts together
to solve a problem.

Friday, June 24, 2005


Oracle Client - How to install

Tuesday, July 04, 2006


Oracle and Java

Monday, October 30, 2006


Oracle Passwords - Answering your common questions

Thursday, December 15, 2005


Oracle and Perl

Thursday, February 02, 2006


Oracle and SOA - Covers Oracle's Service-Oriented
Architecture at a high level

Wednesday, February 22, 2006


Oracle Sequences - This is the one Oracle carried on its
main page

Thursday, September 01, 2005


Pivot and Crosstab Queries - A very useful technique for
turning rows into columns, and vice versa

Monday, April 03, 2006


Pivot Queries Using Variable Number of Columns - Part 2
on pivot queries, when you don't know how many
columns you need in advance.

Friday, September 30, 2005


PL/SQL Procedure Call Overhead - Is there one?

http://thinkoracle.blogspot.com/2006_03_01_archive.html (7 of 15)1/9/2008 2:50:08 AM


OracleBlog: March 2006

Friday, August 11, 2006


PL/SQL Procedure Call Overhead Re-visited - By Zsolt
Lajosfalvi

Saturday, September 02, 2006


Protecting PL/SQL Code - Using wrap.

Tuesday, May 24, 2005


Random Numbers - How to generate them.

Monday, November 21, 2005


RAW Datatype

Tuesday, June 27, 2006


Recursion vs Iteration - What are they, what are the
advantages of each one?

Tuesday, June 13, 2006


Refreshing Data - A High-level picture of the flow and
what to keep in mind when designing your data import
strategy

Thursday, October 06, 2005


ROWNUM and ROWID - And how they're used to solve
various issues, and improve retrieval times.

Tuesday, February 07, 2006


TRANSLATE - What it is, how to use it.

Wednesday, August 10, 2005


UNION ALL - How and when to avoid performance hits

Monday, April 17, 2006


Updating Views - Can you do it, and if so, when.

Monday, June 27, 2005


Using Bad Names in Oracle

Tuesday, October 04, 2005


Using DECODE to exploit COUNT/NULL feature -
Applying DECODE and our knowledge of COUNT/NULL
together in a little trick to speed up a query.

Wednesday, June 15, 2005


Variable Constraints - Can you use variables in
constraints? How?

Friday, November 10, 2006


View Constraints - Can you manage integrity using views?

http://thinkoracle.blogspot.com/2006_03_01_archive.html (8 of 15)1/9/2008 2:50:08 AM


OracleBlog: March 2006

Monday, July 18, 2005


Which instance am I in?

Tuesday, May 30, 2006


Windowing Clauses - How they are used to empower
your analytic functions.

Other:

Monday, February 26, 2007


Fun With Tom Kyte - Get a laugh out of Oracle's king of
wit

Thursday, April 05, 2007


Oracle Beefs - Here are mine. What are yours?

Tuesday, October 31, 2006


Oracle Gurus - What makes an Oracle guru?

Tuesday, February 21, 2006


Oracle Interview Questions - How to come up with useful
ones.

Sunday, June 03, 2007


SQL Interview Questions - Here's what I ask. Prepare for
your interviews.

Friday, May 25, 2007


What Makes a Great Oracle Blog?

// posted by Robert Vollman @ Tuesday, March 28, 2006 1 comments

Friday, March 10, 2006


Handling Performance Issues
Typically performance issues are handled by looking for
common symptoms and trying common solutions. Given
a sufficient level of experience, this is successful quite
often with minimal effort. But there are times where this
does not work and you need a more systematic approach.

Let's take a look at one approach, bearing in mind:


1. This is a rough, first, high-level pass
2. It is NOT Oracle (or even database) specific
3. I am not including the details on the HOW

Also, some people may notice Cary Millsap's influence in

http://thinkoracle.blogspot.com/2006_03_01_archive.html (9 of 15)1/9/2008 2:50:08 AM


OracleBlog: March 2006

this approach.

1. Rank the most significant performance issues, by


specific application, from the business user's perspective.

2. Carefully measure the total time currently taken for


each of these specific applications.

3. Determine exactly how fast the application would


need to run in order to meet the business user's needs.

Now, for each business application in order of


importance, perform steps starting at 4-9:

4. Break down the specific application into tasks.

5. Carefully measure how often each task is currently


being executed, how long each execution currently
takes, and from that, how much total time it currenty
takes and what % of total time each task represents.

Now, for each specific task in order of total % of time


taken, perform steps 6-9:

6. If you COMPLETELY ELIMINATED the time taken by this


task and all tasks below it, would the performance goal
be met?
YES: Continue, with step 7-9
NO: Stop until the situation changes. Continue to the
next application, steps 4-9.

7. Predict how to reduce time spent for this task, either


by:
a) Reducing the number of times this task is being done
OR
b) Reducing the time it takes to execute a task once

Note: If required, recursively perform steps 4-9 by


breaking the task down further into sub-tasks.

8. Perform a cost-benefit analysis of your plan in step 7.


Is it worthwhile? If so, do it.

9. Have you reached the performance goal of this


application?
YES: Proceed to the next application and perform steps
4-9.
NO: Proceed to the next task and repeat steps 6-9.

Notes:
1. By doing things in order of business importance

http://thinkoracle.blogspot.com/2006_03_01_archive.html (10 of 15)1/9/2008 2:50:08 AM


OracleBlog: March 2006

a) the users are most likely to experience results


b) anything we "harm" is, by definition, less important
2. By addressing tasks in order of time spent
a) we get the best results first
b) adverse results will only affect tasks that take less time
3. By defining success up front, and performing a cost-
benefit analysis before taking action, we can avoid
wasting time by stopping either
a) when the goal is met
b) when the goal is proven to be impossible.

Since this is a rough sketch, I especially invite people's


thoughts.

// posted by Robert Vollman @ Friday, March 10, 2006 4 comments

Wednesday, March 01, 2006


Handling exceptions
I've got a checklist of tasks I like to complete before
beginning a new project. One important item on my list
is to decide on how my exceptions are going to be
handled.

By deciding in advance, I can save time by implementing


exception handling only once, and also have much more
consistent code. I also find that once I begin a project,
I'm focusing on the logic and can easily miss handling
exceptions properly, so my code is much more robust
thinking about it in advance.

So what is an exception?

Well an exception is more about what it represents


rather than what it IS. The existence of an exception
means that something unexpected has failed in the run-
time execution of your code. It also means that this
execution has stopped.

Actually, I am slightly oversimplying the case, because


you can actually create and raise an exception yourself
without an unexpected failure, but generally you are only
going to do this if you have either found something
wrong, or you want to infuriate whoever is maintaining
your code.

Ok, so you've got an exception. Now what?

Good question. Your first choice is to do nothing. That

http://thinkoracle.blogspot.com/2006_03_01_archive.html (11 of 15)1/9/2008 2:50:08 AM


OracleBlog: March 2006

will cause your code block to fail, giving whatever


executed this block an opportunity to do something. If
you executed the block from SQL*Plus, (edit) all the (non-
COMMITed) work in your block and all (non-
autonomous) sub-blocks will be rolled back by the
database.

Your other option is to do something. Your only


opportunity to do this is in the EXCEPTION section of
your block. In this section you can examine the type of
exception, and handle it however you please.

Briefly, it looks like this:

EXCEPTION
WHEN ONE_KIND_OF_ERROR THEN
-- Do something here
WHEN OTHERS THEN
-- Handle all left over cases here
END

Once you're in there, you can get information about your


error by looking at SQLCODE and SQLERRM, which
contain the number and a text message for the latest
exception. Oddly enough (here's a little "gotcha") you
can't just insert these values to a table, for reasons I
discovered last July.

Incidentally, here is what the "do nothing" (edit or "hide


the error") option looks like:

EXCEPTION WHEN OTHERS THEN NULL;

Edit: Read Tom Kyte's comments to learn why some


people will strangle you with their bare hands if you ever
do this.

I want to do something. Uhh ... what should I do?

That's an even better question, and one that not a lot of


books or articles actually focus on. That's because you
have to figure out for yourself what you want to do when
something goes wrong. Do you want to write a message
to a table that you can query later? Are there some
business-specific steps you want to do? Do you want to
email yourself? Do you want to write to a log? Do you
want to send a text message to output?

http://thinkoracle.blogspot.com/2006_03_01_archive.html (12 of 15)1/9/2008 2:50:08 AM


OracleBlog: March 2006

Whatever you decide to do, don't forget to do any clean


up, because this is your only chance. Like I said,
execution of your code block is over, and there is no
avoiding that, so if you have something to do, do it now!

What if I don't want the execution to stop?

Too bad! The only way around that is to decide what


code falls into this category, and wrap it in its own,
nested block. Let me explain (and demonstrate).

Let's say you have several tasks to perform, and


regardless of whether the first one succeeds or not, you
want to continue to do the other tasks. Since execution
stops the moment you get an exception, this is a case
where you should wrap the first task in its own block,
and handle the exception there. It doesn't even have to
be a separate function/procedure, you can just create an
anonymous block right then and there, like this:

BEGIN
BEGIN
-- Do task one.
EXCEPTION
-- Handle it!
END
-- Do task two
-- Do task three ...
EXCEPTION
-- Handle exceptions from task two, three, ...
END

Don't forget to actually handle the exception in your


nested block! As I said before, unhandled exceptions
stop the execution of whatever called your block, too.

Incidentally, in some cases you actually want to stop the


execution of the calling block, but you still want to do
something right now in your current, failed block. But if
you handle it, then the exception is gone, and the calling
block will therefore just continue its execution. In that
case, you can re-raise the exception. The only caveat is
that whatever called your block will think that the
exception came from your exception handling code, not
the original point of failure. Keep that in mind.

Good stuff. So what do you do?

http://thinkoracle.blogspot.com/2006_03_01_archive.html (13 of 15)1/9/2008 2:50:08 AM


OracleBlog: March 2006

Personally, I like to define an exception package.

There I can do a few things. I like to define my own


exceptions (including number and text message) using
PRAGMA EXCEPTION_INIT. Then I can throw my custom
exceptions around.

But more importantly I can write a few different


procedures that can handle exceptions in standard ways,
and then all I have to do in my exception blocks is
choose which way I want to handle an error, and then
send the required information (usually SQLCODE and
SQLERRM) to these standard procedures.

Needless to say, I can put these packages together quite


quickly by re-using tested, trusted code from previous
projects.

A word on rollback

I mentioned previously that if you don't handle your


exceptions, SQL*Plus will rollback your work. It is
probably better for you if you decide what gets
committed, and what gets rolled back, and when.
Therefore you should be sure to include COMMIT
(preferably with SAVEPOINTs) and ROLLBACK
appropriately in your code. And while ROLLBACK is a
topic for another day, I should at least tell you to be
aware of autonomous transactions, which are special
blocks that will commit its work right away, regardless of
whether its calling block rolled back or not.

Whew, anything else?

Yeah, one more thing. Exceptions in the DECLARE block


can't be caught in the same block, but rather by the
calling block. Keep that in mind in your EXCEPTION block
when your block calls blocks with a DECLARE section.

In closing, it's important to note that this is a huge topic,


and I can't do it justice in one page. Fortunately Oracle
has a great write-up on handling PL/SQL Errors in the PL/
SQL User's Guide and Reference, see Chapter 7. It even
includes a list of pre-defined exceptions and what they
mean.

But the true master of PL/SQL Exception Handling is


doubtlessly Steven Feuerstein. I urge you to buy his book
on Oracle PL/SQL Programming, and check out Chapter 8
on exception handling. If at all possible, attend one of

http://thinkoracle.blogspot.com/2006_03_01_archive.html (14 of 15)1/9/2008 2:50:08 AM


OracleBlog: March 2006

his live presentations.

// posted by Robert Vollman @ Wednesday, March 01, 2006 10

comments

http://thinkoracle.blogspot.com/2006_03_01_archive.html (15 of 15)1/9/2008 2:50:08 AM


OracleBlog: April 2006

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be complicated, but it is the
most powerful tool when it comes to data. That's why when I think data, I think Oracle. I also enjoy writing, so I
use this format to organise my thoughts. Please feel free to discuss any thoughts you may have on the same
topics, even old ones (I will see and respond to such comments). You may want to start with "LIST ALL
ARTICLES" under Archives.

Monday, April 17, 2006


Updating Views
I was recently asked by a former colleague "Can you insert data in an Oracle table through a
View?"

In some cases, yes you can, and it actually serves as a handy technique to manage security on
your data. Here's what I mean: you can restrict access to a base table, and then create a view
containing only rows and columns that you wish to be accessible. That is just one of the many
handy uses of views. Quick hint: read up on the WITH CHECK OPTION to prevent changes to
base table rows to which you're trying to restrict access.

Now why did I say "in some cases?" Because inserting/updating data in a View depends on the
View. Why? Well a View is just a stored query against some base tables. When you're executing
DML operations on a View, Oracle actually executes those DML operations appropriately on
the base tables. And there are some cases where it is impossible for Oracle to do that. Let's
look at one simple example.

-- Create our data


CREATE TABLE BaseTable (field1 NUMBER(8), field2 NUMBER(8));
INSERT INTO BaseTable (field1, field2) VALUES (5, 10);
CREATE OR REPLACE VIEW UpdateViewYes
AS SELECT field1, field2 FROM BaseTable;
CREATE OR REPLACE VIEW UpdateViewNo
AS SELECT field1 + field2 addfield FROM BaseTable;
-- This won't work
SQL> UPDATE UpdateViewNo SET addfield = 16;
UPDATE UpdateViewNo SET addfield = 16
*
ERROR at line 1:
ORA-01733: virtual column not allowed here
-- This should work
UPDATE UpdateViewYes SET field1 = 6 WHERE field1 = 5;
SQL> UPDATE UpdateViewYes SET field1 = 6 WHERE field1 = 5;
1 row updated.
-- Look at our data now
SQL> SELECT * FROM BaseTable;
FIELD1 FIELD2
---------- ----------
6 10

http://thinkoracle.blogspot.com/2006_04_01_archive.html (1 of 8)1/9/2008 2:50:12 AM


OracleBlog: April 2006

In this example, UpdateViewNo.addfield is the addition of two columns. How would Oracle
know how to divide the new value we assigned? This argument would hold for any situation
where the View had a pseudocolumn or expression column, like this example, or perhaps one
created through the use of DECODE. Of course, these rows could still be deleted.

The Oracle SQL Reference details other situations where your View couldn't be updated. For
example, and along the same lines of reasoning, if the View contains a SET, DISTINCT, GROUP
BY, GROUP, ORDER BY, CONNECT BY, START WITH, then Oracle can't perform any update or
insert operations on the View. Same goes if you have a collection expression or a subquery in
a SELECT list.

USER_UPDATABALE_COLUMNS

Not sure if your View can be updated or not? Well you can simply try and see, but there is
another way. Find your View in the USER_UPDATABLE_COLUMNS table and see for yourself.

SQL> SELECT table_name, column_name, updatable


2 FROM user_updatable_columns
3 WHERE table_name LIKE 'UPDATEVIEW%';
TABLE_NAME COLUMN_NAME UPD
------------------------- ------------------------- ---
UPDATEVIEWNO ADDFIELD NO
UPDATEVIEWYES FIELD1 YES
UPDATEVIEWYES FIELD2 YES

WITH READ ONLY

What if you don't want anyone to update obase tables using your View? You can explicitly
prevent users from modifying the base table through your View by creating it with the WITH
READ ONLY clause. That signals to Oracle that your View is meant for querying only.

Join Views

Thus far I've been talking only about cases where the View is based on a single base table.
What about when the View joins one or more base tables? This is referred to as a Join View.

Updating join views is a whole different ball of wax. Simply put, you may be able to update
one base table through the view, provided your join clause uses a unique index. Otherwise,
there are workarounds. To learn more on this, read Norman Dunbar's article in Jonathan
Lewis' Oracle User's Co-Operative FAQ.

Briefly put, you can create a update trigger on that view to update the data in the base tables
appropriately. There is also an example on Building Complex Updatable Views Using Triggers
in the Application Developer's Guide, Chapter 15.

For more information on Views, including a list of what disqualifies a view from being
updateable, a description of Join Views, details of the WITH READ ONLY clause, examples and
much more, consult the Oracle SQL Reference, Chapter 16.

http://thinkoracle.blogspot.com/2006_04_01_archive.html (2 of 8)1/9/2008 2:50:12 AM


OracleBlog: April 2006

// posted by Robert Vollman @ Monday, April 17, 2006 3 comments

Monday, April 03, 2006


Pivot Queries Using Variable Number of Columns
Pivot queries (also known as crosstab queries) are a special kind of query that can turn rows
into columns for special reporting needs. For example, if you have a table/view with three
columns (employee name, year, and salary), and you need a view that shows employee name
and salary over the years (as a single row), then a pivot query is what you want. Essentially,
you want to "pivot" the year column from being rows to being a column.

I presented a simple, introductory example last September that used Canadian Football
League teams and their points per season as an example. That example worked fine at the
time, but what happened at the end of the CFL season? You entered some new rows of data to
reflect the results of the 2005 season, but the query is hard-coded to show only 2002-2004
seasons. What should you do now? Re-write your query after every season? Fortunately, there
is a better way. That is why today I would like to expand on this example to show you how to
write a pivot query in the common case where you have an undefined number of columns (in
this case, seasons/years).

First of all, let's add the 2005 season to our data. Also remember why I like to name my
columns when I insert (or call stored procedures):
INSERT INTO CFL (season, team, points) VALUES (2005, 'Argonauts', 22);
INSERT INTO CFL (season, team, points) VALUES (2005, 'Alouettes', 20);
INSERT INTO CFL (season, team, points) VALUES (2005, 'Renegades', 14);
INSERT INTO CFL (season, team, points) VALUES (2005, 'Tiger-Cats', 10);

Our problem is that we don't know how many columns we need when we write the query. We
only know how many columns we'll need at the time the query is executed. That sounds like a
job for dynamic SQL which, along with REF CURSORs, can build an appropriate query at the
time we call it. That technique is described in detail by Tom Kyte in his book Expert One-on-
One Oracle, in Chapter 12 on Analytic Functions. I will apply this technique to our specific
problem in an upcoming article.

Tom describes another way to get around this issue on his famous AskTom website. You can
leave the seasons as rows (allowing you to have as few or as many as you need), and pivot the
non-season columns instead. His solution leads us to another way of tackling this "I don't
know how many columns I'll need" problem. Make season/points a single column.

Solution #1: Leave Seasons as rows and pivot the Team column.

CREATE OR REPLACE TYPE Teams AS OBJECT


(team VARCHAR2(16), points NUMBER(3));

CREATE OR REPLACE TYPE Seasons AS TABLE OF Teams;

SELECT c1.season,
CAST(MULTISET(SELECT c2.team, sum(c2.points) tot_points
FROM CFL c2 WHERE c1.season = c2.season
GROUP BY c2.team) AS Seasons) Standings
FROM CFL c1
GROUP BY season;

SEASON

http://thinkoracle.blogspot.com/2006_04_01_archive.html (3 of 8)1/9/2008 2:50:12 AM


OracleBlog: April 2006

----------
STANDINGS(TEAM, POINTS)
--------------------------------------------------------------------------------
2002
SEASONS(TEAMS('Alouettes', 27), TEAMS('Argonauts', 16), TEAMS('Renegades', 10), TEAMS
('Tiger-Cats', 15))

2003
SEASONS(TEAMS('Alouettes', 26), TEAMS('Argonauts', 18), TEAMS('Renegades', 14), TEAMS
('Tiger-Cats', 2))

2004

SEASON
----------
STANDINGS(TEAM, POINTS)
--------------------------------------------------------------------------------
SEASONS(TEAMS('Alouettes', 28), TEAMS('Argonauts', 21), TEAMS('Renegades', 10), TEAMS
('Tiger-Cats', 19))

2005
SEASONS(TEAMS('Alouettes', 20), TEAMS('Argonauts', 22), TEAMS('Renegades', 14), TEAMS
('Tiger-Cats', 10))

Solution #2: Pivot Seasons, just like we did before, and create an array for seasons and points.

CREATE OR REPLACE TYPE SeasonResult AS OBJECT


(season NUMBER(4), points NUMBER(3));

CREATE OR REPLACE TYPE TeamResult AS TABLE OF SeasonResult;

SELECT c1.team,
CAST(MULTISET(SELECT c2.season, sum(c2.points) tot_points
FROM CFL c2 WHERE c1.team = c2.team
GROUP BY c2.season) AS TeamResult) Results
FROM CFL c1
GROUP BY team;

TEAM
----------------
RESULTS(SEASON, POINTS)
--------------------------------------------------------------------------------
Alouettes
TEAMRESULT(SEASONRESULT(2002, 27), SEASONRESULT(2003, 26), SEASONRESULT(2004, 28),
SEASONRESULT(2005, 20))

Argonauts
TEAMRESULT(SEASONRESULT(2002, 16), SEASONRESULT(2003, 18), SEASONRESULT(2004, 21),
SEASONRESULT(2005, 22))

Renegades

TEAM
----------------
RESULTS(SEASON, POINTS)
--------------------------------------------------------------------------------

http://thinkoracle.blogspot.com/2006_04_01_archive.html (4 of 8)1/9/2008 2:50:12 AM


OracleBlog: April 2006

TEAMRESULT(SEASONRESULT(2002, 10), SEASONRESULT(2003, 14), SEASONRESULT(2004, 10),


SEASONRESULT(2005, 14))

Tiger-Cats
TEAMRESULT(SEASONRESULT(2002, 15), SEASONRESULT(2003, 2), SEASONRESULT(2004, 19),
SEASONRESULT(2005, 10))

There are two consequences of this approach that are less than ideal. The query itself is a
little bit complicated, involves creating types and, secondly, if we made a view from this
query, its harder to use. (Example: Query that view to get me the season record for each
team). Fortunately there is a simple change we can make that gives us a query as simple as
our original example, and where we can create a view that can be more easily used for other
queries.

Before I tell you what it is, observe one thing about Tom's solution (#1). In the simpler
example where we knew how many columns (seasons) we'd need, we pivoted the seasons. In
this example, where we didn't know how many seasons we had, we pivoted the other columns
(team, points).

We are in the fortunate position where we know how many teams we have. Why not pivot
"team" column, and then do it largely like our simpler example?

CREATE OR REPLACE VIEW CFLBySeason AS


SELECT season,
MAX(DECODE(team, 'Argonauts', points, NULL)) Argonauts,
MAX(DECODE(team, 'Alouettes', points, NULL)) Alouettes,
MAX(DECODE(team, 'Renegades', points, NULL)) Renegades,
MAX(DECODE(team, 'Tiger-Cats', points, NULL)) TigerCats
FROM CFL
GROUP BY season;

SELECT * FROM CFLBySeason;

SEASON ARGONAUTS ALOUETTES RENEGADES TIGERCATS


---------- ---------- ---------- ---------- ----------
2002 16 27 10 15
2003 18 26 14 2
2004 21 28 10 19
2005 22 20 14 10

Not only do we have a simpler query, but we can leverage the power of views to keep things
simple. By turning this query into a view (called, for example, CFLBySeason), we can address
other requirements very easily.

Example:
1. Show me the most points any team has had in any one season. And it would be simple
enough to change this example to show total and/or average season performance as well.

SELECT MAX(Argonauts) Argonauts,


MAX(Alouettes) Alouettes,
MAX(Renegades) Renegades,
MAX(TigerCats) TigerCats
FROM CFLBySeason;

http://thinkoracle.blogspot.com/2006_04_01_archive.html (5 of 8)1/9/2008 2:50:12 AM


OracleBlog: April 2006

2. Show me how lopsided the division was each season

SELECT Season,
(Argonauts + Alouettes) TorMtl,
(Renegades + TigerCats) OttHam
FROM CFLBySeason;

3. I only care about Toronto. I want to see their season-by-season point totals.

SELECT Season, Argonauts FROM CFLBySeason;

I will admit that pivot queries can get complicated, but given how often they are the easiest
solution to complex requirements, it is worth the investment to understand them.

// posted by Robert Vollman @ Monday, April 03, 2006 0 comments

About Me
Name: Robert Vollman
Location: Calgary, Alberta, Canada

I was born and raised in Ottawa, and have lived in Calgary since 1991. I like playing sports
(hockey, soccer, ultimate, basketball, you name it) and military board games. I also enjoy
reading, walking, and playing with my 2 cats Lilly and Brutus. I'm a database application specialist,
whatever that is.

View my complete profile

Best Links
● Ask Tom Kyte
● Oracle Docs
● Dan Morgan and PSOUG
● Steven Feuerstein
● Jonathan Lewis
● FAQ
● Connor McDonald
● The Oak Table
● Cary Millsap and Hotsos
● Steve Adams and Ixora
● Anjo Kolk and OraPerf
● Dizwell Oracle Wiki
● My Personal Blog

http://thinkoracle.blogspot.com/2006_04_01_archive.html (6 of 8)1/9/2008 2:50:12 AM


OracleBlog: April 2006

Aggregators
Brian Duff's OraBlogs

❍ Eddie Awad's OracleNA


❍ Pete Finnigan's Aggregator
❍ Oracle's Bloglist
❍ Oracle Base Aggregator

Top Blogs
❍ Oracle's Ask Tom Kyte
❍ Oracle Guru Jonathan Lewis
❍ Blogger of the Year Eddie Awad
❍ Data Warehouser David Aldridge
❍ Oracle Geek Lewis Cunningham
❍ Database Expert James Koopmann
❍ Dizwell's Howard Rogers
❍ Oracle Master Laurent Schneider
❍ Security Expert Pete Finnigan
❍ Oracle Award Winner Mark Rittman
❍ Doug Burns
❍ Oracle ACE of the Year Dr. Tim Hall
❍ UKOUG's Andrew (Arfur C.) Clarke
❍ Newbie DBA Lisa Dobson
❍ Coffee-Drinking DBA Jon Emmons
❍ Chris Foot
❍ The Pythian DBA Team Blog
❍ DBA Don Seiler
❍ DBA Coskan Gundogar
❍ Oracle WTF

ARCHIVES
❍ LIST ALL ARTICLES
❍ May 2005
❍ June 2005
❍ July 2005
❍ August 2005
❍ September 2005
❍ October 2005
❍ November 2005
❍ December 2005
❍ January 2006
❍ February 2006
❍ March 2006
❍ April 2006
❍ May 2006
❍ June 2006
❍ July 2006
❍ August 2006
❍ September 2006

http://thinkoracle.blogspot.com/2006_04_01_archive.html (7 of 8)1/9/2008 2:50:12 AM


OracleBlog: April 2006

❍ October 2006
❍ November 2006
❍ December 2006
❍ January 2007
❍ February 2007
❍ March 2007
❍ April 2007
❍ May 2007
❍ June 2007
❍ October 2007

❍ Current Posts

http://thinkoracle.blogspot.com/2006_04_01_archive.html (8 of 8)1/9/2008 2:50:12 AM


OracleBlog: May 2006

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics, even
old ones (I will see and respond to such comments). You may want to start with "LIST ALL
ARTICLES" under Archives.

Tuesday, May 30, 2006


Windowing Clauses
Answer: "Analytic Functions"

Question: "I have become quite comfortable, perhaps even adept, with
basic SQL queries. I am ready to learn how to do more with my data. What
do you recommend I study?"

Given how often I write about analytic functions, my answer may not come
as a surprise. To those who have been studying along with me, I would
like to add one more tool to our toolbelts. Following up on my recent
article about finding nearby rows, I would like to touch on windowing
clauses.

Life Without Windowing Clauses

Quick, find me the average of a value for all rows in a table. No problem,
right? Use the analytic function AVG.

Note: Sample data can be found at the end of the article.

SELECT AVG(votes) FROM elections;

AVG(VOTES)
----------------------
357315.2307692307692307692307692307692308

Great. Now, find me that average only for a certain range of data, say from

http://thinkoracle.blogspot.com/2006_05_01_archive.html (1 of 13)1/9/2008 2:50:16 AM


OracleBlog: May 2006

elections in 1990s only. Again, no problem.

SELECT AVG(votes) FROM elections WHERE election BETWEEN 1990 and


1999;

AVG(VOTES)
----------------------
461947.5

Ok. Now, for each row, find me the average from a 10 year range before
and after.

Um... errr...

How about the simply the average including the preceding and succeeding
rows?

Um ... errr ... what was the link to your article on finding nearby rows
again?

To the Rescue

Well you can relax. I am about to show you how to answer these
questions, and others like it. We'll answer these questions using
windowing clauses, which are the integral part of analytic functions that
define the set of rows you wish to work with.

First let's review analytic functions. You can go read Chapter 6 of the SQL
Reference, but generally, an analytic function comes in the following form:

ANALYTIC FUNCTION (ARGUMENT) OVER (QUERY PARTITION CLAUSE,


ORDER BY CLAUSE, WINDOWING CLAUSE);

Using windowing clauses, you can define which row to start with, which
row to end with including, if you wish, in reference to a specific row
(either by a range, or row number).

Now to let you off the hook. Here is an example of how to use windowing
clauses to determine the average of a column for a 10-year range, and an
average including the rows immediately before and after.

SELECT election, leader, votes,


CEIL(AVG(votes) OVER (ORDER BY election RANGE BETWEEN 10 preceding
AND 10 following)) ten_year,
CEIL(AVG(votes) OVER (ORDER BY election ROWS BETWEEN 1 preceding

http://thinkoracle.blogspot.com/2006_05_01_archive.html (2 of 13)1/9/2008 2:50:16 AM


OracleBlog: May 2006

AND 1 following)) before_after


FROM elections;

ELECTION LEADER VOTES TEN_YEAR


BEFORE_AFTER
-------- ------------ ------------ ------------
-------------
1959 Kirby 98730 93184
75004
1963 Harradance 51278 144122
93184
1967 Lougheed 129544 189250
159252
1971 Lougheed 296934 251124
265414
1975 Lougheed 369764 358565
358265
1979 Lougheed 408097 399552
455449
1982 Lougheed 588485 420075
454455
1986 Getty 366783 434118
440838
1989 Getty 367244 442418
391336
1993 Klein 439981 457035
430380
1997 Klein 483914 467097
517049
2001 Klein 627252 492060
509420
2004 Klein 417092 509420 522172

Armed with the knowledge of the windowing clause, we are finally


beginning to unleash the full power of analytic functions. With that in
mind, a closer look at the other two types of clauses are in order.

Query Partition Clause

Strictly speaking, the windowing clause is not the only way to define the
set of rows you wish to work with. The query partition clause can achieve
that same goal by grouping your data on a single, specific value (or set of

http://thinkoracle.blogspot.com/2006_05_01_archive.html (3 of 13)1/9/2008 2:50:16 AM


OracleBlog: May 2006

values).

For example, say we wanted the average number of votes by leader. No


problem using GROUP BY, right?

SELECT leader, AVG(votes) avg_votes FROM elections GROUP BY leader;

LEADER AVG_VOTES
-------------------------------- ----------------------
Getty 367013.5
Harradance 51278
Kirby 98730
Klein 492059.75
Lougheed 358564.8

By using the partitioning clause we can achieve the same result, but use it
in other ways. For example, to compare the average to every row.

SELECT election, leader, votes,


CEIL(votes - AVG (votes) OVER (PARTITION BY leader)) diff
FROM elections ORDER BY diff desc;

ELECTION LEADER VOTES DIFF


-------- ------------- --------- ---------
1982 Lougheed 588485 229921
2001 Klein 627252 135193
1979 Lougheed 408097 49533
1975 Lougheed 369764 11200
1989 Getty 367244 231
1963 Harradance 51278 0
1959 Kirby 98730 0
1986 Getty 366783 -230
1997 Klein 483914 -8145
1993 Klein 439981 -52078
1971 Lougheed 296934 -61630
2004 Klein 417092 -74967
1967 Lougheed 129544 -229020

Putting the partitioning clause and the windowing clause together is like
mixing chocolate and peanut butter. Alone, they're great, together they're

http://thinkoracle.blogspot.com/2006_05_01_archive.html (4 of 13)1/9/2008 2:50:16 AM


OracleBlog: May 2006

even better. We could solve such complex problems as "For each row,
show me the average that includes the immediately preceding and
succeeding rows that share the same id."

Further Reading

Other than the SQL Reference, and Chapter 19 "SQL for Analysis" of the
Data Warehousing Guide, my primary sources include Chapter 12 of Tom
Kyte's "Expert One-on-One Oracle" and Daniel Morgan's on-line reference.

Beyond that, there are a lot of fine articles on specific applications. For
beginners, I would review an anonymous contribution to Howard Rogers'
wiki introduction to analytic functions, which also includes a great
example.

I will close with the final ingredient to analytic functions, the order by
clause.

Creating Rolling Averages

By using the order by clause within the context of the analytic function,
we can create rolling averages.

SELECT election, leader, votes,


CEIL(AVG (votes) OVER (ORDER BY election)) rolling_avg
FROM elections;

ELECTION LEADER VOTES ROLLING_AVG


-------- ------------- ---------- -------------
1959 Kirby 98730 98730
1963 Harradance 51278 75004
1967 Lougheed 129544 93184
1971 Lougheed 296934 144122
1975 Lougheed 369764 189250
1979 Lougheed 408097 225725
1982 Lougheed 588485 277548
1986 Getty 366783 288702
1989 Getty 367244 297429
1993 Klein 439981 311684
1997 Klein 483914 327342
2001 Klein 627252 352334
2004 Klein 417092 357316

http://thinkoracle.blogspot.com/2006_05_01_archive.html (5 of 13)1/9/2008 2:50:16 AM


OracleBlog: May 2006

--

Sample data used in this article:

CREATE TABLE elections (election NUMBER(4), party VARCHAR2(32), leader


VARCHAR2(32), seats NUMBER(2), votes NUMBER(7), tot_seats NUMBER(2),
tot_votes NUMBER(7));

INSERT INTO elections VALUES (2004, 'PC', 'Klein', 61, 417092, 83,
890700);
INSERT INTO elections VALUES (2001, 'PC', 'Klein', 74, 627252, 83,
1013152);
INSERT INTO elections VALUES (1997, 'PC', 'Klein', 63, 483914, 83,
845713);
INSERT INTO elections VALUES (1993, 'PC', 'Klein', 51, 439981, 83,
989025);
INSERT INTO elections VALUES (1989, 'PC', 'Getty', 59, 367244, 83,
829189);
INSERT INTO elections VALUES (1986, 'PC', 'Getty', 61, 366783, 83,
713654);
INSERT INTO elections VALUES (1982, 'PC', 'Lougheed', 75, 588485, 79,
944936);
INSERT INTO elections VALUES (1979, 'PC', 'Lougheed', 74, 408097, 79,
710963);
INSERT INTO elections VALUES (1975, 'PC', 'Lougheed', 69, 369764, 75,
590200);
INSERT INTO elections VALUES (1971, 'PC', 'Lougheed', 49, 296934, 75,
639862);
INSERT INTO elections VALUES (1967, 'PC', 'Lougheed', 6, 129544, 65,
498351);
INSERT INTO elections VALUES (1963, 'PC', 'Harradance', 0, 51278, 63,
403444);
INSERT INTO elections VALUES (1959, 'PC', 'Kirby', 1, 98730, 65, 413516);

// posted by Robert Vollman @ Tuesday, May 30, 2006 0 comments

Tuesday, May 09, 2006


Finding Nearby Rows
Today's question is how do you find rows that have values nearest the
value of a given row?

http://thinkoracle.blogspot.com/2006_05_01_archive.html (6 of 13)1/9/2008 2:50:16 AM


OracleBlog: May 2006

Although there are many different variations on this central theme, in


order to solve problems of this nature, you'll need to know:

1. The given column's value for the given row


2. The difference between each row's value and the value of the given row
3. That row's difference's relationship to all the other rows.

Step 1 is easy, 2 and 3 are more difficult.

For starters, let's say my requirement is to find the 2 battles that started
nearest the beginning of the battle of Batoche. Here's how I first attacked
that problem.
Note: You can find my test data at the end of this blog if you want to try it
for yourself.

SELECT loc, difference FROM


(SELECT a.loc, ABS(a.start_date - b.start_date) difference
FROM battles a,
(SELECT start_date FROM battles WHERE loc = 'BATOCHE') b
ORDER BY difference)
WHERE rownum < 3;

LOC DIFFERENCE
-------------------- ----------------------
BATOCHE 0
CUT KNIFE 7
FISH CREEK 15

Despite my use of ROWNUM to get just the two closest rows, I will admit
that my result is not satisfying, because I don't like going through the
same data more than once. Once to find the value of the given row, and
another to figure out the differences. Blech!

I do have a better solution, but first let's say my requirements are a little
tougher, to the point where this solution won't even work. For example:

1. In the above example, the two nearest rows both happened to be prior
to the given row. Let's say my requirements are to find the rows
immediately preceding the given row, and the rows immediately
succeeding it.

AND let's also say

http://thinkoracle.blogspot.com/2006_05_01_archive.html (7 of 13)1/9/2008 2:50:16 AM


OracleBlog: May 2006

2. I want the TWO rows immediately before and immediately after instead
of just one.

What then?

RANK

For starters, we can use the analytic function RANK instead of ROWNUM
for an easier way to get the order in which the rows are presented.

Once again, the 'b' query gives us the rank of our given row, and now the
'a' query will get a list of all the locations and their respective RANK. Now
we can take as many rows as we want from that centrepoint.

SELECT loc FROM


(SELECT a.loc, ABS(a.battle_num - b.battle_num) distance FROM
(SELECT loc, RANK() OVER (ORDER BY start_date) battle_num FROM battles)
a,
(SELECT loc, RANK() OVER (ORDER BY start_date) battle_num FROM battles)
b
WHERE b.loc = 'BATOCHE')
WHERE distance BETWEEN 1 AND 2;

LOC
--------------------
FISH CREEK
CUT KNIFE
FRENCHMAN'S BUTTE
LOON LAKE

I'm still annoyed about the inelegance of the solution, because we're still
going through my data more than once. Is there a better way?

LEAD and LAG

With LEAD and LAG you can access multiple rows without a self-join
(joining a table to itself). With that, we can do all sorts of fancy things,
such as figure out how many days have passed since the last battle
started, and how long until the next one began.

SELECT loc, start_date,


start_date - LAG(start_date, 1, NULL) OVER (ORDER BY start_date) AS

http://thinkoracle.blogspot.com/2006_05_01_archive.html (8 of 13)1/9/2008 2:50:16 AM


OracleBlog: May 2006

last_battle,
LEAD(start_date, 1, NULL) OVER (ORDER BY start_date) - start_date AS
next_battle
FROM battles;

Back to the task at hand, armed with LAG and LEAD, we can create a list of
all rows including the value of the previous row, and the value of the next
one. From that, its pretty trivial to select the rows we want.

SELECT loc FROM (SELECT loc,


LAG(loc, 1, NULL) OVER (ORDER BY start_date) previous_battle,
LEAD(loc, 1, NULL) OVER (ORDER BY start_date) next_battle
FROM battles)
WHERE previous_battle = 'BATOCHE' OR next_battle = 'BATOCHE';

LOC
--------------------
CUT KNIFE
FRENCHMAN'S BUTTE

That's very nice! But what about the requirement to get the TWO rows
immediately preceding and succeeding the given row, can we still do that
with LAG and LEAD?

The SQL Reference describes how to use LAG and LEAD, under Chapter 6,
Functions. There it is explained that the second parameter to LAG and
LEAD is the number of rows to look. So we can look 2 battles before and
after Batoche, and use DECODE to make it a single column.

SELECT loc FROM


(SELECT loc, DECODE(LAG(loc, 1, NULL) OVER (ORDER BY start_date),
'BATOCHE', 1, 0) +
DECODE(LAG(loc, 2, NULL) OVER (ORDER BY start_date), 'BATOCHE', 1, 0) +
DECODE(LEAD(loc, 1, NULL) OVER (ORDER BY start_date), 'BATOCHE', 1, 0)
+
DECODE(LEAD(loc, 2, NULL) OVER (ORDER BY start_date), 'BATOCHE', 1, 0)
near_batoche
FROM battles)
WHERE near_batoche > 0;

LOC
--------------------

http://thinkoracle.blogspot.com/2006_05_01_archive.html (9 of 13)1/9/2008 2:50:16 AM


OracleBlog: May 2006

FISH CREEK
CUT KNIFE
FRENCHMAN'S BUTTE
LOON LAKE

Depending how many rows you want, this query will get bigger and uglier,
so you may want to revert to using the RANK example instead. If you like
the looks of LAG and LEAD, Tim Hall has a good introduction article worth
reviewing.

Performance

I guess the big question is related to the performance implications of each


approach. Granted I have a small amount of data, but here are the
differences I observed

ROWNUM example, 2 nearest rows:


Slowest of the three, had more parse, executes and queries than the other
two combined. The query came in three pieces, the first two of which had
full table accesses, the last of which having a nested loop with a table
access, a sort, and a view.

RANK example, looking 1 or 2 rows:


No real difference between 1 or 2 rows. Slower than LAG/LEAD with
double the parse/execute/fetch. Came in two pieces, the first of which
had a full access, the second of which had 2 nested loops, 2 full accesses,
and 2 sorts, including one that was cartesian (49 rows).

LAG/LEAD example, looking 1 or 2 rows:


No real difference between 1 or 2 rows. Faster of the three, lowest parse/
execute/fetch. Came in two pieces, both of which had a full access, but
the second of which also had a sort and a view.

In terms of performance, it looks like LAG/LEAD wins, on this sample


data.

Sample data:
CREATE TABLE battles (loc VARCHAR2(20), start_date DATE, canadian
VARCHAR2(20), rebel VARCHAR2(20));
INSERT INTO battles VALUES ('DUCK LAKE', '26-March-1885', 'Crozier',
'Dumont');
INSERT INTO battles VALUES ('FORT PITT', '15-April-1885', 'Dickens', 'Big

http://thinkoracle.blogspot.com/2006_05_01_archive.html (10 of 13)1/9/2008 2:50:16 AM


OracleBlog: May 2006

Bear');
INSERT INTO battles VALUES ('FISH CREEK', '24-April-1885', 'Middleton',
'Dumont');
INSERT INTO battles VALUES ('CUT KNIFE', '2-May-1885', 'Otter',
'Poundmaker');
INSERT INTO battles VALUES ('BATOCHE', '9-May-1885', 'Middleton',
'Dumont');
INSERT INTO battles VALUES ('FRENCHMAN''S BUTTE', '28-May-1885',
'Strange', 'Wandering Spirit');
INSERT INTO battles VALUES ('LOON LAKE', '3-June-1885', 'Steele',
'Wandering Spirit');

Bonus: My favourite recent blog article was James Koopmann's recent


write-up on storing Word Documents in Oracle.

// posted by Robert Vollman @ Tuesday, May 09, 2006 2 comments

About Me
Name: Robert Vollman
Location: Calgary, Alberta, Canada

I was born and raised in Ottawa, and have lived in Calgary since 1991. I
like playing sports (hockey, soccer, ultimate, basketball, you name it)
and military board games. I also enjoy reading, walking, and playing with my 2 cats
Lilly and Brutus. I'm a database application specialist, whatever that is.

View my complete profile

Best Links
● Ask Tom Kyte
● Oracle Docs
● Dan Morgan and PSOUG
● Steven Feuerstein
● Jonathan Lewis

http://thinkoracle.blogspot.com/2006_05_01_archive.html (11 of 13)1/9/2008 2:50:16 AM


OracleBlog: May 2006

● FAQ
● Connor McDonald
● The Oak Table
● Cary Millsap and Hotsos
● Steve Adams and Ixora
● Anjo Kolk and OraPerf
● Dizwell Oracle Wiki
● My Personal Blog

Aggregators
Brian Duff's OraBlogs

❍ Eddie Awad's OracleNA


❍ Pete Finnigan's Aggregator
❍ Oracle's Bloglist
❍ Oracle Base Aggregator

Top Blogs
❍ Oracle's Ask Tom Kyte
❍ Oracle Guru Jonathan Lewis
❍ Blogger of the Year Eddie Awad
❍ Data Warehouser David Aldridge
❍ Oracle Geek Lewis Cunningham
❍ Database Expert James Koopmann
❍ Dizwell's Howard Rogers
❍ Oracle Master Laurent Schneider
❍ Security Expert Pete Finnigan
❍ Oracle Award Winner Mark Rittman
❍ Doug Burns
❍ Oracle ACE of the Year Dr. Tim Hall
❍ UKOUG's Andrew (Arfur C.) Clarke
❍ Newbie DBA Lisa Dobson
❍ Coffee-Drinking DBA Jon Emmons
❍ Chris Foot
❍ The Pythian DBA Team Blog
❍ DBA Don Seiler
❍ DBA Coskan Gundogar
❍ Oracle WTF

http://thinkoracle.blogspot.com/2006_05_01_archive.html (12 of 13)1/9/2008 2:50:16 AM


OracleBlog: May 2006

ARCHIVES
❍ LIST ALL ARTICLES
❍ May 2005
❍ June 2005
❍ July 2005
❍ August 2005
❍ September 2005
❍ October 2005
❍ November 2005
❍ December 2005
❍ January 2006
❍ February 2006
❍ March 2006
❍ April 2006
❍ May 2006
❍ June 2006
❍ July 2006
❍ August 2006
❍ September 2006
❍ October 2006
❍ November 2006
❍ December 2006
❍ January 2007
❍ February 2007
❍ March 2007
❍ April 2007
❍ May 2007
❍ June 2007
❍ October 2007

❍ Current Posts

http://thinkoracle.blogspot.com/2006_05_01_archive.html (13 of 13)1/9/2008 2:50:16 AM


OracleBlog: June 2006

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Tuesday, June 27, 2006


About Me
Recursion vs Iteration Name: Robert
When writing code to do repetitive tasks, the Vollman
two primary approaches are iteration and Location: Calgary,
recursion. Generally you can use either one Alberta, Canada
interchangeably, but potentially with different
performance and complexity.
I was born and raised in Ottawa,
A recursive function calls itself (possibly more and have lived in Calgary since
than once), with different parameters, and 1991. I like playing sports
defines an exit clause that is guaranteed to be (hockey, soccer, ultimate,
reached. basketball, you name it) and
military board games. I also
CREATE OR REPLACE FUNCTION enjoy reading, walking, and
FIBONACCI_REC (in_number IN NUMBER) playing with my 2 cats Lilly and
RETURN NUMBER DETERMINISTIC Brutus. I'm a database
AS application specialist, whatever
BEGIN that is.
CASE
WHEN in_number = 1 THEN RETURN 1; View my complete profile
WHEN in_number = 2 THEN RETURN 1;
ELSE RETURN (FIBONACCI_REC (in_number -
1) + FIBONACCI_REC (in_number - 2));
END CASE;
Best Links
Ask Tom Kyte
END;

● Oracle Docs
An iterative function includes a loop, which ● Dan Morgan and PSOUG

http://thinkoracle.blogspot.com/2006_06_01_archive.html (1 of 10)1/9/2008 2:50:20 AM


OracleBlog: June 2006

iterates a pre-determined number of times, ● Steven Feuerstein


or checks for an exit clause every time ● Jonathan Lewis
through. ● FAQ
● Connor McDonald
CREATE OR REPLACE FUNCTION FIBONACCI_IT
The Oak Table
(in_number IN NUMBER)

Cary Millsap and Hotsos


RETURN NUMBER DETERMINISTIC

Steve Adams and Ixora


AS ●

fib1 NUMBER := 1; ● Anjo Kolk and OraPerf


fib2 NUMBER := 1; ● Dizwell Oracle Wiki
fib3 NUMBER := 1; ● My Personal Blog
fib4 NUMBER;
BEGIN
FOR fib4 IN 3 .. in_number
LOOP Aggregators
fib3 := fib1 + fib2; Brian Duff's OraBlogs

fib1 := fib2; Eddie Awad's OracleNA
fib2 := fib3;

Pete Finnigan's Aggregator


END LOOP;

Oracle's Bloglist
RETURN fib3;

Oracle Base Aggregator


END; ❍

The advantages and disadvantages of the two Top Blogs


are not always obvious, and you should really ❍ Oracle's Ask Tom Kyte
take it on a case-by-case basis. When in ❍ Oracle Guru Jonathan Lewis
doubt: test it. But generally: ❍ Blogger of the Year Eddie Awad
Data Warehouser David Aldridge
1. Recursion may be slower, and use greater

Oracle Geek Lewis Cunningham


resources, because of the extra function calls.

❍ Database Expert James Koopmann


2. Recursion may lead to simpler, shorter, ❍ Dizwell's Howard Rogers
easier-to-understand functions, especially for ❍ Oracle Master Laurent Schneider
mathematicians who are comfortable with ❍ Security Expert Pete Finnigan
induction formulae. ❍ Oracle Award Winner Mark
Rittman
Either way, one of the most critical aspects of Doug Burns
writing either a recursive or an iterative

Oracle ACE of the Year Dr. Tim


function is to have an exit clause (or "base

Hall
case" for recursions) that is checked at every
UKOUG's Andrew (Arfur C.) Clarke
recursion/iteration and is guaranteed to be

reached at some finite point, given any input. ❍ Newbie DBA Lisa Dobson
Otherwise you will get either: ❍ Coffee-Drinking DBA Jon Emmons
❍ Chris Foot
Infinite Recursion: More and more functions ❍ The Pythian DBA Team Blog

http://thinkoracle.blogspot.com/2006_06_01_archive.html (2 of 10)1/9/2008 2:50:20 AM


OracleBlog: June 2006

being spawned, never closing, using up DBA Don Seiler


resources until there are none left, possibly ❍ DBA Coskan Gundogar
crashing the system. ❍ Oracle WTF

Infinite loop: A loop that cycles forever,


burning CPU and never completing.
ARCHIVES
❍ LIST ALL ARTICLES
I can illustrate this point with my recursive ❍ May 2005
example above. Do NOT try this, but if you ❍ June 2005
inserted a negative number, what do you ❍ July 2005
think would happen? Infinite recursion. ❍ August 2005
September 2005
Now you have not only the basics on iteration

October 2005
and recursion, but, based on the topic I chose

November 2005
for the sample code, knowledge that I saw "Da ❍

Vinci Code" recently. ❍ December 2005


❍ January 2006
// posted by Robert Vollman @ Tuesday, June 27, ❍ February 2006
❍ March 2006
2006 13 comments
❍ April 2006
❍ May 2006
❍ June 2006
Sunday, June 18, 2006
July 2006
Meeting Tom Kyte

August 2006
"You have redeemed my faith, after last year's

September 2006
presentation, which was such a

October 2006
disappointment."- One of Tom Kyte's biggest

fans in COUG ❍ November 2006


❍ December 2006
❍ January 2007
❍ February 2007
❍ March 2007
❍ April 2007
❍ May 2007
❍ June 2007
❍ October 2007

❍ Current Posts

Renowned Oracle expert and author of highly

http://thinkoracle.blogspot.com/2006_06_01_archive.html (3 of 10)1/9/2008 2:50:20 AM


OracleBlog: June 2006

popular blog, pictured here with Tom Kyte.

I first met Tom Kyte about twenty minutes


before his presentation about his favourite
features in Oracle 10g. When I went up to
introduce myself, I figured he was putting the
final touches on his presentation, but he was
actually answering questions for his AskTom
web site. I guess you have to find the time for
that somewhere!

Due in part to his reputation for fine speeches


(his biggest fan notwithstanding), there were
quite a few people in attendance. Tom reports
having answered 33,000 different Oracle-
related questions. I wonder how many people
were there hoping they could find that one
question that pushed him over the edge.
Sadly, no such luck.

I enjoyed the presentation myself, despite still


being on Oracle 9. Based on some of the
features, including DBMS_SQLTUNE which
uses SQL Profiles to find patterns in your data
that can help speed up queries, I wonder how
long before he comes to town announcing
that the next release of Oracle is sentient.

I was a little surprised to hear his excitement


about DBMS_ADVANCED_REWRITE, which
allows you to tell Oracle "listen, when I write
this query, what I REALLY want is this
completely different query." I can't believe I'm
going to have to learn to start typing
"FOR_REAL" after all my queries. Maybe in
Oracle 11 we'll need
"NO_SERIOUSLY_I_MEAN_IT".

On a more serious note, it sounds like Oracle


10 has a lot more bells and whistles
ultimately aimed to speed things up. Take PL/
SQL compilation for example. When you
"CREATE OR REPLACE" it will check whether a
recompilation is really necessary, and will also

http://thinkoracle.blogspot.com/2006_06_01_archive.html (4 of 10)1/9/2008 2:50:20 AM


OracleBlog: June 2006

look for optimizations within your code. I


guess the end result is a little bit more
overhead to check for things, but faster
results, especially for inexperienced
programmers.

Afterwards we all retired to Bottlescrew Bill's


for COUG's annual social, where I enjoyed
Tom's stories almost as much as his
presentation. In contrast to the light-hearted
ribbing with which I began this post, virtually
everyone ranks him as one of the very best
Oracle speakers. I'm really glad he paid us a
visit, and look forward to hearing him again.

// posted by Robert Vollman @ Sunday, June 18, 2006 0

comments

Tuesday, June 13, 2006


Refreshing Data
Moving data from one database to another is
a very common task for a database
administrator. So common, in fact, that I have
never bothered to write about it, because
most DBAs already have their own preferred
method.

http://thinkoracle.blogspot.com/2006_06_01_archive.html (5 of 10)1/9/2008 2:50:20 AM


OracleBlog: June 2006

If you haven't chosen your approach yet, allow


me to show you the general flow, some points
to keep in mind, and some of the decisions
you'll have to make based upon the nature of
your data and the tools at your disposal.

1. Lose Your Integrity

What do you do when you have one tables


that relies on another, through a foreign key?
In order to avoid having your import fail, you
would need to have the tables loaded in the
right order. Or, you could just disable all
constraints.

Why all constraints? Why not just the foreign


keys? Well, checking constraints takes time.
Presumably this is data you're grabbing from
an environment where these constraints have
already been checked, why check them again?
If you don't trust that data, don't worry, you'll
catch the errors when you try to re-enable the
constraints later on.

You may want to disable triggers while you're


at it. Presumably those have already fired
when the data was first entered, and those
can be time consuming as well.

While you're in the disabling mood, drop your


indexes. It will just take time to update them
with every row you insert. Just drop them now
and re-create them when you're done. Much
faster over-all.

One more thing, you want to do these and all


subsequent steps with logging turned off.
Why keep a redo log of each transaction?
That's just taking time and space. Chances
are your mentality is that either all the data
gets in, or all of it doesn't.

2. Wipe Out Your Data

http://thinkoracle.blogspot.com/2006_06_01_archive.html (6 of 10)1/9/2008 2:50:20 AM


OracleBlog: June 2006

You may already have data in the target


database that you want to replace. You could
insert your data in such a way that it checks if
the data already exists before adding it. But
that takes time and effort. Instead, you may
just want to wipe out and re-insert all your
data.

What is the best way to eliminate your data?


Don't use "delete." Delete is for selectively
deleting a subset of rows, or if you want to be
able to rollback your work. Instead, in this
case, truncate your data. No logging: much
faster.

By the way, when you're truncating, you'll be


glad that you disabled your foreign key
constraints. Otherwise you'd have to be very
careful in the order you truncated your tables.

You may want to consider using "reuse


storage" which will keep the space reserved
for the data. Since you're probably going to
be inserting a roughly equal or superior
amount of data, this will save you from having
to expand your extents during the import.

An alternative to all this is to drop all the


tables and then have your import process re-
create the tables with the data involved. That
option is only appealing if you're not 100%
confident the table structure is the same,
otherwise I don't see the point.

Before you wipe out your data, I'm assuming


either you already have a backup, or you don't
care about this data. Otherwise, you should
have done this first:

3. Dump Your Data

Which is outside the scope of this article. :)

4. Copy Your Dump

http://thinkoracle.blogspot.com/2006_06_01_archive.html (7 of 10)1/9/2008 2:50:20 AM


OracleBlog: June 2006

5. Import the Data

There are many different tools you can use to


import your data, and each one has many
different methods and options. Here is a brief
list of your choices which, of course, depend
on how you dumped your data.

SQL*Loader/SQLLDR (Check the Oracle Server


Utilities Guide, Part 2)
IMP utility
Oracle 10g Data Pump Export and Import
(DBMS_DATAPUMP)
Oracle Data Manager (Oracle Enterprise
Manager Console)
Your own custom application (possibly using
Oracle Call Interface/OCI).

If your data import is still ridiculously slow,


ask yourself if you're using RAID 5. Are you?
RAID 5 is slow, man. No getting around that,
that's the nature of the beast.

6. Restore Your Integrity

Now that the job is done, it is time to restore


your integrity (and lose your faith in man). Re-
enable your constraints, and triggers, and
restore your indexes. This may take some
time, so get a coffee.

7. Recalculate Statistics

In order for the optimizer to work effectively


you'll need to re-calculate your statistics
(DBMS_STATS.GATHER_SCHEMA_STATISTICS).
If it knows how big the tables are, the
optimizer will be able to make the best
choices in query plans. You can import the
statistics, if they were kept up-to-date in
your production system, but might as well
gather them now.

http://thinkoracle.blogspot.com/2006_06_01_archive.html (8 of 10)1/9/2008 2:50:20 AM


OracleBlog: June 2006

That's it!

This was by no means meant to be a


comprehensive step-by-step guide with an
exhaustive list of everything to consider. But
at least now I've made an attempt to draw out
the basic flow, and some of the things you
should keep in mind. Hopefully this will help
you design a solution of your own, most
appropriate for your data and how you use it.

// posted by Robert Vollman @ Tuesday, June 13, 2006 3

comments

Wednesday, June 07, 2006


Call For Topics
This morning I read that fellow Oracle blogger
Tim Hall is looking for Oracle topics on which
to base his next article. It occurs to me that
since changing positions a few months ago
that I have dealt with Oracle a lot less than
previously, and am open to hearing some
ideas.

Virtually all my articles are based on


questions I get from customers or colleagues,
or problems I have to solve in my day-to-day
work. There are times when that stream is a
trickle, and times when its a raging river.

Right now its a trickle. But I'd like to keep up


the momentum rather than have this blog go
the way of my Sybase blog.

And don't confine your questions to my area


of interest (development), because I happen
to know that several other excellent bloggers
like Eddie Awad, Gary Myers, Tom Kyte, Doug
Burns and others may also pick up on any
ideas you leave in my comments.

Well maybe not Tom, I think he gets enough

http://thinkoracle.blogspot.com/2006_06_01_archive.html (9 of 10)1/9/2008 2:50:20 AM


OracleBlog: June 2006

questions. :)

// posted by Robert Vollman @ Wednesday, June 07,

2006 2 comments

http://thinkoracle.blogspot.com/2006_06_01_archive.html (10 of 10)1/9/2008 2:50:20 AM


OracleBlog: July 2006

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Tuesday, July 25, 2006


About Me
Ask Tom Name: Robert
In keeping with the theme of my most recent Vollman
post, I just couldn't stop laughing at Tom's Location: Calgary,
most recent response to a question about Alberta, Canada
recursive sql.
I was born and raised in Ottawa,
// posted by Robert Vollman @ Tuesday, July 25, 2006 4
and have lived in Calgary since
comments 1991. I like playing sports
(hockey, soccer, ultimate,
basketball, you name it) and
Wednesday, July 19, 2006 military board games. I also
enjoy reading, walking, and
Finding Information playing with my 2 cats Lilly and
QUESTION Brutus. I'm a database
application specialist, whatever
Hi Robert,
that is.
I don't understand the meaning of any of the
items on the query plan. View my complete profile

Is there some document that would explain


what they are? If there is, where can I get it? Best Links
Thanks. ● Ask Tom Kyte
● Oracle Docs
ANSWER ● Dan Morgan and PSOUG

http://thinkoracle.blogspot.com/2006_07_01_archive.html (1 of 7)1/9/2008 2:50:23 AM


OracleBlog: July 2006

That's the best kind of question. Instead of ● Steven Feuerstein


sending me a query plan and asking me to ● Jonathan Lewis
interpret it for you, you're asking me for the ● FAQ
means to do it yourself. Which is good ● Connor McDonald
because there is so much I don't understand ● The Oak Table
about Oracle that I would have to study up to ● Cary Millsap and Hotsos
help you anyway.
● Steve Adams and Ixora
Oracle Documentation ● Anjo Kolk and OraPerf
● Dizwell Oracle Wiki
I love Oracle documentation. I can usually find ● My Personal Blog
what I want in there, complete with examples
and explanations. So let's start there.

Once you have navigated to Oracle's


documentation page, you'll want to select
Aggregators
Brian Duff's OraBlogs

"View Library" and then go thorugh the ❍ Eddie Awad's OracleNA
searching page. ❍ Pete Finnigan's Aggregator
Choosing the right phrase can be tricky. In ❍ Oracle's Bloglist
this case, try TKPROF, Query Plan, Execution ❍ Oracle Base Aggregator
Plan.
Top Blogs
❍ Oracle's Ask Tom Kyte
❍ Oracle Guru Jonathan Lewis
❍ Blogger of the Year Eddie Awad
❍ Data Warehouser David Aldridge
❍ Oracle Geek Lewis Cunningham
❍ Database Expert James Koopmann
❍ Dizwell's Howard Rogers
❍ Oracle Master Laurent Schneider
❍ Security Expert Pete Finnigan
❍ Oracle Award Winner Mark
Rittman
❍ Doug Burns
❍ Oracle ACE of the Year Dr. Tim
Hall
Searching with any of these three phrases ❍ UKOUG's Andrew (Arfur C.) Clarke
points rather conclusively at the Oracle
❍ Newbie DBA Lisa Dobson
Performance Tuning Guide and Reference. ❍ Coffee-Drinking DBA Jon Emmons
Taking a look through it, it seems to have lots ❍ Chris Foot
of information to get you started on how to
❍ The Pythian DBA Team Blog

http://thinkoracle.blogspot.com/2006_07_01_archive.html (2 of 7)1/9/2008 2:50:23 AM


OracleBlog: July 2006

understand the execution plans you see in the DBA Don Seiler

TKPROF output. ❍ DBA Coskan Gundogar


❍ Oracle WTF
Ask Tom

The second thing I like to do is Ask Tom. He


ARCHIVES
has answered 33,000 questions, meaning that ❍ LIST ALL ARTICLES
in any case, my question was probably ❍ May 2005
already asked. Sometimes his answers include ❍ June 2005
links to other information. ❍ July 2005
❍ August 2005
❍ September 2005
❍ October 2005
❍ November 2005
❍ December 2005
❍ January 2006
❍ February 2006
❍ March 2006
❍ April 2006
❍ May 2006
❍ June 2006
❍ July 2006
❍ August 2006
❍ September 2006
❍ October 2006
❍ November 2006
Searching our three chosen phrases points to ❍ December 2006
one Ask Tom article in particular that might ❍ January 2007
be helpful. ❍ February 2007
March 2007
Google

❍ April 2007
Sometimes I can google around to find ❍ May 2007
articles on a topic. Normally I favour sources I ❍ June 2007
trust, like Jonathan Lewis or something. In ❍ October 2007
this case, googling found me this article:
❍ Current Posts
Use EXPLAIN PLAN and TKRPOF To Tune Your
Applications, by Roger Schrag

Still Stuck?

If you've gone through these sources and you

http://thinkoracle.blogspot.com/2006_07_01_archive.html (3 of 7)1/9/2008 2:50:23 AM


OracleBlog: July 2006

still haven't found the information you're


looking for, it's time for a degree of
intrepidity.

I would certainly want to contact my fellow


Oracle specialists. But rather than contact one
individually with an open-ended question, I
would post a message to a forum or message
board, making sure to highlight what I had
already looked for, what I had already found,
and specifically how it came up short.

It is possible that the information I'm looking


for has never been written. If so, that would
be a great opportunity for me to do some
research and make my own, new contribution
to the Oracle community.

// posted by Robert Vollman @ Wednesday, July 19,

2006 2 comments

Tuesday, July 04, 2006


Oracle and Java
Last December I wrote about how to create a
simple Perl application that connected to your
Oracle database, it is high time that I showed
you how to do the same in Java.

What You'll Need

1. An Oracle database. Make sure you can


tnsping your ORACLE_SID. Better yet, make
sure you can connect with sqlplus.

2. Java. It's a free download from Sun. I'm


using 1.5, but I've tested this on several
versions.

3. You don't need the client installed because


we're using the thin client. If you want to use
OCI but don't want to install the full Oracle
client, download the instant client.

http://thinkoracle.blogspot.com/2006_07_01_archive.html (4 of 7)1/9/2008 2:50:23 AM


OracleBlog: July 2006

Set your PATH

As part of your Java installation, you must


have set the path to your jdk\bin. Make sure
that's there and add it if not.

Set your CLASSPATH

If you're using Java 1.4 or greater, then


ojdbc14.jar contains the classes you need.
You'll find it in ORACLE_HOME/jdbc/lib.

And more information on this? You can unzip


the jar file and look at the files inside with
some Java tools, search the Internet or, best
yet, check out ORACLE_HOME/jdbc/doc/
javadoc.tar. That's a complete API: all the
classes and their parameters.

If you're using an older version, you'll want


something like classes12.jar instead. Follow
the installation instructions. But do NOT
include this if you're on 1.4 or greater. You
want one or the other, not both.

There is also one thing that seems to always


get me when I start a java project. I always
forget to add the local directory to the
CLASSPATH. Save yourself the 20 wasted
minutes and put it first.

C:\temp>echo %CLASSPATH%
.;c:\oracle\product\10.1.0\db\jdbc\lib
\ojdbc14.jar

Include Your Classes

Though you may want others, here are the


main classes you'll need to import. The
former should be part of your Java SDK, the
latter is in the aforementioned ojdbc14.jar.

import java.sql.*;
import oracle.jdbc.pool.OracleDataSource;

http://thinkoracle.blogspot.com/2006_07_01_archive.html (5 of 7)1/9/2008 2:50:23 AM


OracleBlog: July 2006

Create an OracleDataSource

Once you've created an OracleDataSource,


you'll be free to write your SQL calls. My
example below shows the syntax for a default
installation, you'll need to modify that second
line as appropriate.

OracleDataSource ods = new


OracleDataSource();
ods.setURL("jdbc:oracle:thin:scott/
tiger@localhost:1521:ORCL");
Connection conn = ods.getConnection();

Check the documentation, there are other


ways of doing this.

Query Away!

There are many ways to use your connection


to query your database. Here is one quick
sample I found.

Statement stmt = conn.createStatement();


ResultSet rset = stmt.executeQuery("select
'Hello World' from dual");
while (rset.next())
System.out.println(rset.getString(1));

Compile and Execute

You'll need to compile your application before


you execute.

javac JdbcVersion.java
java JdbcVersion

If you get this error:

Exception in thread "main" java.lang.


NoClassDefFoundError

Then check your CLASSPATH very carefully.


You can run java with the -verbose option to

http://thinkoracle.blogspot.com/2006_07_01_archive.html (6 of 7)1/9/2008 2:50:23 AM


OracleBlog: July 2006

see if you get more information about what's


missing.

That's it!

For more information, review the


documentation to which the README file
points you:

1. The new technical white paper

2. The online JDBC doc for the most updated


information

3. The revised JDBC FAQ

4. The JDBC Developer's Guide and Reference

// posted by Robert Vollman @ Tuesday, July 04, 2006 1

comments

http://thinkoracle.blogspot.com/2006_07_01_archive.html (7 of 7)1/9/2008 2:50:23 AM


OracleBlog: August 2006

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Friday, August
About Me
11, 2006
Name: Robert Vollman
PL/SQL Location: Calgary, Alberta, Canada
Procedure
Call I was born and raised in Ottawa, and have lived in
Calgary since 1991. I like playing sports (hockey,
Overhead soccer, ultimate, basketball, you name it) and military board games.
Re-visited I also enjoy reading, walking, and playing with my 2 cats Lilly and
Zsolt Lajosfalvi Brutus. I'm a database application specialist, whatever that is.
wrote such an
interesting View my complete profile
comment in
response to
my earlier post
about PL/SQL
Best Links
Ask Tom Kyte
Procedure Call

Oracle Docs
Overhead that

Dan Morgan and PSOUG


I felt it

Steven Feuerstein
deserved its

Jonathan Lewis
own space. ●

● FAQ
What follows is ● Connor McDonald
exclusively the ● The Oak Table
work of Zsolt. ● Cary Millsap and Hotsos
My results ● Steve Adams and Ixora
from verifying ● Anjo Kolk and OraPerf

http://thinkoracle.blogspot.com/2006_08_01_archive.html (1 of 13)1/9/2008 2:50:26 AM


OracleBlog: August 2006

his tests follow ● Dizwell Oracle Wiki


at the end. ● My Personal Blog

Zsolt:

In my
experience the
Aggregators
overhead of Brian Duff's OraBlogs

PLSQL ❍ Eddie Awad's OracleNA


procedure ❍ Pete Finnigan's Aggregator
invocations is ❍ Oracle's Bloglist
so small that ❍ Oracle Base Aggregator
you'll most
probably never
have to think
Top Blogs
Oracle's Ask Tom Kyte
about it. In

Oracle Guru Jonathan Lewis


99.99% of all ❍

cases the "real" ❍ Blogger of the Year Eddie Awad


overhead ❍ Data Warehouser David Aldridge
comes from ❍ Oracle Geek Lewis Cunningham
the way you do ❍ Database Expert James Koopmann
things inside ❍ Dizwell's Howard Rogers
the procedure ❍ Oracle Master Laurent Schneider
(s) and not ❍ Security Expert Pete Finnigan
from the ❍ Oracle Award Winner Mark Rittman
procedure ❍ Doug Burns
invocation
Oracle ACE of the Year Dr. Tim Hall
itself. So

UKOUG's Andrew (Arfur C.) Clarke


putting as

Newbie DBA Lisa Dobson


much code ❍

into a single ❍ Coffee-Drinking DBA Jon Emmons


procedure as ❍ Chris Foot
you can won't ❍ The Pythian DBA Team Blog
help. :-) ❍ DBA Don Seiler
❍ DBA Coskan Gundogar
Let's take a ❍ Oracle WTF
look at a very
basic example.
Run this:
ARCHIVES
❍ LIST ALL ARTICLES
DECLARE ❍ May 2005
nLoops ❍ June 2005
CONSTANT ❍ July 2005
NUMBER := ❍ August 2005

http://thinkoracle.blogspot.com/2006_08_01_archive.html (2 of 13)1/9/2008 2:50:26 AM


OracleBlog: August 2006

10000000; ❍ September 2005


nStart NUMBER; ❍ October 2005
PROCEDURE ❍ November 2005
calculate IS December 2005
BEGIN

January 2006
NULL;

February 2006
END calculate;

March 2006
BEGIN ❍

dbms_output. ❍ April 2006


enable ❍ May 2006
(buffer_size ❍ June 2006
=> 10000); ❍ July 2006
❍ August 2006
nStart := ❍ September 2006
dbms_utility. ❍ October 2006
get_time();
November 2006
FOR i IN 1..

December 2006
nLoops LOOP

January 2007
calculate();

END LOOP; ❍ February 2007


dbms_output. ❍ March 2007
put_line('time: ' ❍ April 2007
|| ROUND ❍ May 2007
((dbms_utility. ❍ June 2007
get_time() - ❍ October 2007
nStart)/100, 3)
|| ' s'); ❍ Current Posts

nStart :=
dbms_utility.
get_time();
FOR i IN 1..
nLoops LOOP
NULL;
END LOOP;
dbms_output.
put_line('time: '
|| ROUND
((dbms_utility.
get_time() -
nStart)/100, 3)
|| ' s');
END;

http://thinkoracle.blogspot.com/2006_08_01_archive.html (3 of 13)1/9/2008 2:50:26 AM


OracleBlog: August 2006

On my server
the output
was:
time: 4.33 s
time: 1.47 s

I ran it around
10 times and
got quite
similiar results
with a very
small
deviation. This
shows that
even in a
magnitude of
10 million
invocations,
the overhead is
minimal (~3s
which is 66% in
this case). Of
course this is
nothing like a
real world
situation. :-)

Let's do some
work in the
procedure.
What if we
pass in a
parameter and
return a value
(make it a
function)?

DECLARE
nLoops
CONSTANT
NUMBER :=
10000000;

http://thinkoracle.blogspot.com/2006_08_01_archive.html (4 of 13)1/9/2008 2:50:26 AM


OracleBlog: August 2006

nStart NUMBER;
nTemp
NUMBER;
FUNCTION
calculate
(nParam IN
NUMBER)
RETURN
NUMBER IS
BEGIN
RETURN
nParam + 1;
END calculate;
BEGIN
dbms_output.
enable
(buffer_size
=> 10000);

nTemp := 0;
nStart :=
dbms_utility.
get_time();
FOR i IN 1..
nLoops LOOP
nTemp :=
calculate
(nTemp);
END LOOP;
dbms_output.
put_line('time: '
|| ROUND
((dbms_utility.
get_time() -
nStart)/100, 3)
|| ' s');

nTemp := 0;
nStart :=
dbms_utility.
get_time();
FOR i IN 1..
nLoops LOOP

http://thinkoracle.blogspot.com/2006_08_01_archive.html (5 of 13)1/9/2008 2:50:26 AM


OracleBlog: August 2006

nTemp :=
nTemp + 1;
END LOOP;
dbms_output.
put_line('time: '
|| ROUND
((dbms_utility.
get_time() -
nStart)/100, 3)
|| ' s');
END;
/

The output is:


time: 12.24 s
time: 3.75 s

The overhead
seems to be
quite "big"
compared to
the previous
test (~8.5s,
which is ~70%
in this case),
however this is
still as much
unrealistic as
the previous
one was. :-)
Generally you
could say that
the more work
you do inside
the function
call (or
procedure), the
less
percentage the
overhead will
be.

Let's do the
test again with

http://thinkoracle.blogspot.com/2006_08_01_archive.html (6 of 13)1/9/2008 2:50:26 AM


OracleBlog: August 2006

a bit more
work inside
the function ...

DECLARE
nLoops
CONSTANT
NUMBER :=
10000000;
nStart NUMBER;
nTemp
NUMBER;
FUNCTION
calculate
(nParam IN
NUMBER)
RETURN
NUMBER IS
BEGIN
RETURN POWER
(nParam + 1,
2) - POWER
(nParam, 2);
END calculate;
BEGIN
dbms_output.
enable
(buffer_size
=> 10000);

nTemp := 0;
nStart :=
dbms_utility.
get_time();
FOR i IN 1..
nLoops LOOP
nTemp :=
calculate
(nTemp);
END LOOP;
dbms_output.
put_line('time: '
|| ROUND

http://thinkoracle.blogspot.com/2006_08_01_archive.html (7 of 13)1/9/2008 2:50:26 AM


OracleBlog: August 2006

((dbms_utility.
get_time() -
nStart)/100, 3)
|| ' s');

nTemp := 0;
nStart :=
dbms_utility.
get_time();
FOR i IN 1..
nLoops LOOP
nTemp :=
POWER(nTemp
+ 1, 2) -
POWER(nTemp,
2);
END LOOP;
dbms_output.
put_line('time: '
|| ROUND
((dbms_utility.
get_time() -
nStart)/100, 3)
|| ' s');
END;
/

time: 47.28 s
time: 31.1 s

Now the
overhead is
~16s which is
~34% of the
total running
time.

All of the
above tests
use very fast,
builtin
arithemtical
functions. Let's
take an

http://thinkoracle.blogspot.com/2006_08_01_archive.html (8 of 13)1/9/2008 2:50:26 AM


OracleBlog: August 2006

example that
is a lot more
realistic ... eg.
we generate
some output
to a browser.
The
procedures in
the SYS.htp
package do a
lot more (and
versatile) work
than any of the
above
examples. I've
split this test
into two parts
to avoid
misleading
results due to
the internal
workings of
the SYS.htp
package. I've
also decreased
the loop count
so the server
won't run out
of memory
(since SYS.htp
maintains an
internal buffer
of all the
strings the you
send to the
output). :-)

DECLARE
nLoops
CONSTANT
NUMBER :=
1000000;
nStart NUMBER;

http://thinkoracle.blogspot.com/2006_08_01_archive.html (9 of 13)1/9/2008 2:50:26 AM


OracleBlog: August 2006

sTemp
VARCHAR2
(200);
PROCEDURE
calculate
(sParam IN
VARCHAR2) IS
BEGIN
htp.p(sParam);
END calculate;
BEGIN
dbms_output.
enable
(buffer_size
=> 10000);
sTemp := LPAD
('a', 200, 'a');

htp.init();
nStart :=
dbms_utility.
get_time();
FOR i IN 1..
nLoops LOOP
calculate
(sTemp);
END LOOP;
dbms_output.
put_line('time: '
|| ROUND
((dbms_utility.
get_time() -
nStart)/100, 3)
|| ' s');

htp.init();
END;
/

And the
procedure-free
version ...

DECLARE

http://thinkoracle.blogspot.com/2006_08_01_archive.html (10 of 13)1/9/2008 2:50:26 AM


OracleBlog: August 2006

nLoops
CONSTANT
NUMBER :=
1000000;
nStart NUMBER;
sTemp
VARCHAR2
(200);
PROCEDURE
calculate
(sParam IN
VARCHAR2) IS
BEGIN
htp.p(sParam);
END calculate;
BEGIN
dbms_output.
enable
(buffer_size
=> 10000);
sTemp := LPAD
('a', 200, 'a');

htp.init();
nStart :=
dbms_utility.
get_time();
FOR i IN 1..
nLoops LOOP
htp.p(sTemp);
END LOOP;
dbms_output.
put_line('time: '
|| ROUND
((dbms_utility.
get_time() -
nStart)/100, 3)
|| ' s');

htp.init();
END;
/

You should run

http://thinkoracle.blogspot.com/2006_08_01_archive.html (11 of 13)1/9/2008 2:50:26 AM


OracleBlog: August 2006

them in two
separate
sessions,
otherwise you
can easily end
up with false
results due to
the package
state of SYS.
htp.

My results
were:
time: 23.7 s
time: 23.27 s

You can see


that the
overhead is
less than 0.5s,
which makes
up less than
2% of the total
running time.

After all these


tests proove
only one thing:
the overhead
seriously
depends on
the number of
parameters,
the type of
parameters,
etc. However
in real-world
situations you
should rarely
worry about
overhead of
procedure
invocations. :-)

http://thinkoracle.blogspot.com/2006_08_01_archive.html (12 of 13)1/9/2008 2:50:26 AM


OracleBlog: August 2006

Robert:
My results
were very
similar to
Zsolt's:

anonymous
block
completed
time: 11.28 s
time: 4.26 s

anonymous
block
completed
time: 51.18 s
time: 43.24 s

anonymous
block
completed
time: 20.37 s

anonymous
block
completed
time: 19.53 s

// posted by
Robert
Vollman @ Friday,
August 11, 2006 2

comments

http://thinkoracle.blogspot.com/2006_08_01_archive.html (13 of 13)1/9/2008 2:50:26 AM


OracleBlog: September 2006

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Wednesday, September 13, 2006


Something To Do Right Now
If you're still using any of the default Oracle username/passwords on
any of your databases, go change it now.

I could blog about this for 1-2 pages, but for two reasons:
1. I think it is an obvious (but oft-neglected) thing to do, and
2. You can use the time you would have spent reading my persuasive
arguments to actually go change your passwords.

So go do it now.

// posted by Robert Vollman @ Wednesday, September 13, 2006 0 comments

Tuesday, September 12, 2006


Using Numerical Fields
What is a number? The definition is one of the longest I've seen, but
generally it refers to a quantity (or sum, total, count) of units.
Quantities can be subjected to all sorts of calculations, such as
addition, subtraction, multiplication and division.

Sometimes numbers are used for ordering, as well. So it makes sense


to compare one number to another, not only as being greater or
lesser than another, but also by what number of units it is greater.

http://thinkoracle.blogspot.com/2006_09_01_archive.html (1 of 8)1/9/2008 2:50:29 AM


OracleBlog: September 2006

Which brings me to my point. I've been asked on more than one


occasion why I sometimes favour the use of VARCHAR2 in situations
where others are using NUMBER. Take, for example, my earlier post
on creating an appropriate Boolean type.

Some developers think I should have used NUMBER(1) as the type,


denote True as 1, False as 0, and have a check to make sure the
value is either 0 or 1.

That solution also works. But there is a reason I don't use it.

It is true that this method has its advantages, not the least of which
is comfort to programmers who are used to that (most programming
languages make that conversion implicitly). They also claim that you
can use multiplication for AND operations, and addition for OR
operations.

Or can you? True * False = False, so ok, multiplication seems to work


fine. But addition? True + True = 2. 2 is not a valid value. And what
about subtraction and division? "Oh those don't apply" Then it's not
an appropriate use of NUMBER, in my mind. What about square root?
What is True to the exponent False? And so on.

I don't mean to pick on this one example. I've seen cases where
NUMBER is used for all sorts of things: dates, credit card numbers,
social insurance/security numbers, street address house numbers,
zip codes, and so on. In some of these cases (though not necessarily
all), it would have been more appropriate to create a type: a
VARCHAR2 restricted to numerical characters, and then use that one
type for all such instances.

No, this is not a critical point. NUMBER will work just fine, and I have
no stories about how people got into trouble by using NUMBER for
something that wasn't. But consider the importance of having
precision and accuracy in your data. Shouldn't we be equally precise
in your description of the data?

That is why I generally prefer using NUMBER only in cases where the
field actually is by definition a number, a quantity of units, and
eligible for all numerical operations. I'd love to hear your thoughts on
this matter too.

// posted by Robert Vollman @ Tuesday, September 12, 2006 8 comments

http://thinkoracle.blogspot.com/2006_09_01_archive.html (2 of 8)1/9/2008 2:50:29 AM


OracleBlog: September 2006

Saturday, September 02, 2006


Protecting PL/SQL Code
There are two broad categories of reasons why PL/SQL programmers
wouldn't want others to read their code:

Reason #1 Protection
The programmers wish to protect their code from theft, misuse or
alteration (among other things).

Reason #2 Malicious Reasons


The code is meant to do harm, or may have some potentially
dangerous errors they wish to cover up.

I don't believe in hidden code, because open code is easier to debug,


reuse, and it is obviously easier to detect (deliberately or
accidentally) harmful code.

But regardless of whether code you have received from a vendor or


contractor is protected or not, you should be testing it thoroughly
before using it anyway. Plus, these methods are already thoroughly
documented in a number of places, not the least of which by expert
Steven Feuerstein and also in Oracle's documentation.

In fact, the example I'm using is from Oracle's documentation.

Normally, after creating a stored procedure, the source code can be


access through a SOURCE table, like so:

SQL> SELECT text FROM USER_SOURCE


SQL> WHERE name = 'WRAPTEST' order by line;

TEXT
-----------------------------------------------------------

PROCEDURE wraptest IS
TYPE emp_tab IS TABLE OF emp%ROWTYPE INDEX BY PLS_INTEGER;
all_emps emp_tab;
BEGIN
SELECT * BULK COLLECT INTO all_emps FROM emp;
FOR i IN 1..10 LOOP
DBMS_OUTPUT.PUT_LINE('Emp Id: ' || all_emps(i).empno);
END LOOP;
END;

http://thinkoracle.blogspot.com/2006_09_01_archive.html (3 of 8)1/9/2008 2:50:29 AM


OracleBlog: September 2006

How can we avoid this?

My first thought is simply not to load the procedure into the


database at all. Leave the procedure as an SQL file on the server, and
execute it remotely. About a year ago, I engaged some Oracle
programmers in such an approach, check that earlier article for a
brief discussion on the advantages and disadvantages of keeping
your code out of the database:
PL/SQL Code Storage: Files vs In-DB Packages

Anyone with access to the server will can still read your code, using
an editor of some kind. But perhaps your server is capable of
restricting access to your satisfaction.

You'll note that those Oracle programmers largely agreed that if your
code is in the database, it should be wrapped and/or part of a
package. First let's look at wrapping.

Wrapping, otherwise known as obfuscation, is a method of changing


your human-readable PL/SQL code into text that is readable only by
Oracle. In that sense, it can be compiled and executed like any other
code, but it is protected in the sense that it won't make sense to
anyone except Oracle.

You can learn how to use the wrap utility from either Dan Morgan, or
Oracle's PL/SQL User's Guide and Reference (Appendix C), but I'll
show you what I mean right now.

1. Put your PL/SQL code in an SQL file.


2. From the command line, issue the wrap command. The syntax is
wrap iname=input_file [oname=output_file]

wrap iname=wraptest.sql oname=wraptest.plb

3. From SQL*Plus, execute the resulting PLB file to load the stored
procedure, and even execute it for verification (omitted here).

SQL> @wraptest.plb

Procedure created.

4. Try to read the code, either by opening the PLB file, or querying a
SOURCE table. PLB is a standard Oracle extension, sometimes
referred to as "PL/SQL Binary." But it isn't binary, it's text: you can go

http://thinkoracle.blogspot.com/2006_09_01_archive.html (4 of 8)1/9/2008 2:50:29 AM


OracleBlog: September 2006

ahead and read it.

SQL> SELECT text FROM USER_SOURCE WHERE name = 'WRAPTEST'


order by line;

(garbage removed)

Now is wrapping a perfect solution? Well no. First of all, Oracle


doesn't claim that it is undecipherable. Edited: In fact, leading Oracle
security expert Pete Finnigan has made a presentation available that
summarizes how to read wrapped code.

It also has a few annoying limitations, none of which I'll prove here,
but they include the fact that you can't wrap triggers (just call a
wrapped proc from your trigger), can't be copied to an earlier
release, and all Oracle comments (--) are deleted.

I hear there may be a superior solution in Oracle 10, as part of the


DBMS_DDL package. That solution doesn't even require a command-
line step, it can be done directly in the database. If you're ahead of
me, and using Oracle 10, give it a try using Dan Morgan's reference
for the syntax.

Speaking of packages, the more important lesson to learn from those


Oracle programmers was to put your code into packages. You can
make the specification public, so everyone can understand them, and
then restrict access (and wrap) the implementation details.

Using packages and wrapping your code is the standard method of


protection. As a closing note, there are plenty of other compelling
reasons to use Oracle packages too. I wrote about that once before,
and also included some links where you can get the finer details on
how to use them:
Oracle Packages - And why/how you should use them.

// posted by Robert Vollman @ Saturday, September 02, 2006 4 comments

About Me
http://thinkoracle.blogspot.com/2006_09_01_archive.html (5 of 8)1/9/2008 2:50:29 AM
OracleBlog: September 2006

Name: Robert Vollman


Location: Calgary, Alberta, Canada

I was born and raised in Ottawa, and have lived in Calgary since 1991. I
like playing sports (hockey, soccer, ultimate, basketball, you name it)
and military board games. I also enjoy reading, walking, and playing with my 2 cats
Lilly and Brutus. I'm a database application specialist, whatever that is.

View my complete profile

Best Links
● Ask Tom Kyte
● Oracle Docs
● Dan Morgan and PSOUG
● Steven Feuerstein
● Jonathan Lewis
● FAQ
● Connor McDonald
● The Oak Table
● Cary Millsap and Hotsos
● Steve Adams and Ixora
● Anjo Kolk and OraPerf
● Dizwell Oracle Wiki
● My Personal Blog

Aggregators
Brian Duff's OraBlogs

❍ Eddie Awad's OracleNA


❍ Pete Finnigan's Aggregator
❍ Oracle's Bloglist
❍ Oracle Base Aggregator

Top Blogs
❍Oracle's Ask Tom Kyte
❍ Oracle Guru Jonathan Lewis
❍ Blogger of the Year Eddie Awad

http://thinkoracle.blogspot.com/2006_09_01_archive.html (6 of 8)1/9/2008 2:50:29 AM


OracleBlog: September 2006

❍ Data Warehouser David Aldridge


❍ Oracle Geek Lewis Cunningham
❍ Database Expert James Koopmann
❍ Dizwell's Howard Rogers
❍ Oracle Master Laurent Schneider
❍ Security Expert Pete Finnigan
❍ Oracle Award Winner Mark Rittman
❍ Doug Burns
❍ Oracle ACE of the Year Dr. Tim Hall
❍ UKOUG's Andrew (Arfur C.) Clarke
❍ Newbie DBA Lisa Dobson
❍ Coffee-Drinking DBA Jon Emmons
❍ Chris Foot
❍ The Pythian DBA Team Blog
❍ DBA Don Seiler
❍ DBA Coskan Gundogar
❍ Oracle WTF

ARCHIVES
❍ LIST ALL ARTICLES
❍ May 2005
❍ June 2005
❍ July 2005
❍ August 2005
❍ September 2005
❍ October 2005
❍ November 2005
❍ December 2005
❍ January 2006
❍ February 2006
❍ March 2006
❍ April 2006
❍ May 2006
❍ June 2006
❍ July 2006
❍ August 2006
❍ September 2006
❍ October 2006
❍ November 2006
❍ December 2006

http://thinkoracle.blogspot.com/2006_09_01_archive.html (7 of 8)1/9/2008 2:50:29 AM


OracleBlog: September 2006

❍ January 2007
❍ February 2007
❍ March 2007
❍ April 2007
❍ May 2007
❍ June 2007
❍ October 2007

❍ Current Posts

http://thinkoracle.blogspot.com/2006_09_01_archive.html (8 of 8)1/9/2008 2:50:29 AM


OracleBlog: October 2006

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Tuesday, October 31,


About Me
2006
Name: Robert Vollman
Oracle Gurus Location: Calgary, Alberta, Canada
"Becoming an Oracle
guru doesn't take I was born and raised in Ottawa, and have
remarkable intelligence lived in Calgary since 1991. I like playing
or a pricey Harvard sports (hockey, soccer, ultimate, basketball, you name it)
degree, but it does take and military board games. I also enjoy reading, walking,
persistence, drive, and a and playing with my 2 cats Lilly and Brutus. I'm a
dedication to database application specialist, whatever that is.
excellence."
- Don Burleson, How to
View my complete profile
become an Oracle Guru

Despite the appearance


of merely trying to Best Links
promote his team (most ● Ask Tom Kyte
notably Steve Karam), ● Oracle Docs
Mr. Burleson actually ● Dan Morgan and PSOUG
raises some interesting ● Steven Feuerstein
points on a thought-
Jonathan Lewis
provoking question.

● FAQ
What Makes an Oracle ● Connor McDonald
Guru? ● The Oak Table
● Cary Millsap and Hotsos
So what does it take to ● Steve Adams and Ixora

http://thinkoracle.blogspot.com/2006_10_01_archive.html (1 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

become an Oracle guru, ● Anjo Kolk and OraPerf


according to him? I'll ● Dizwell Oracle Wiki
group his dozen points ● My Personal Blog
into the underlying
broad categories:

1. Credentials
A stellar education with
Aggregators
prestigious degrees, Brian Duff's OraBlogs

awards, and ❍ Eddie Awad's OracleNA


certifications. ❍ Pete Finnigan's Aggregator
❍ Oracle's Bloglist
2. Communicating Their ❍ Oracle Base Aggregator
Knowledge
Via insightful blogs,
publishing
Top Blogs
Oracle's Ask Tom Kyte
opportunities, and ❍

polished ❍ Oracle Guru Jonathan Lewis


communications skills. ❍ Blogger of the Year Eddie Awad
❍ Data Warehouser David Aldridge
3. Attitude ❍ Oracle Geek Lewis Cunningham
Seeks challenging job ❍ Database Expert James Koopmann
opportunities, and is ❍ Dizwell's Howard Rogers
characterized by a "can ❍ Oracle Master Laurent Schneider
do" attitude.
❍ Security Expert Pete Finnigan
Who Are the Gurus? ❍ Oracle Award Winner Mark Rittman
❍ Doug Burns
Before I can properly ❍ Oracle ACE of the Year Dr. Tim Hall
evaluate Mr. Burleson's ❍ UKOUG's Andrew (Arfur C.) Clarke
assertions, I need to ❍ Newbie DBA Lisa Dobson
know who the Oracle ❍ Coffee-Drinking DBA Jon Emmons
gurus are. So I ❍ Chris Foot
unleashed the "Google The Pythian DBA Team Blog
Guru Wars" (say that five

DBA Don Seiler


times fast). Here are the

DBA Coskan Gundogar


results of this dubious

test: ❍ Oracle WTF

Most popular results for ARCHIVES


"Oracle Guru" on Google ❍ LIST ALL ARTICLES
878 Jonathan Lewis ❍ May 2005
762 Tom Kyte ❍ June 2005
646 Don Burleson ❍ July 2005

http://thinkoracle.blogspot.com/2006_10_01_archive.html (2 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

486 Mike Ault ❍ August 2005


216 Steve Adams ❍ September 2005
3 Robert Vollman :) ❍ October 2005
❍ November 2005
Do they all meet December 2005
Burleson's Three

January 2006
Criteria? Well the criteria

February 2006
are fairly subjective, but

March 2006
from what I know of ❍

these 5, they certainly ❍ April 2006


do. ❍ May 2006
❍ June 2006
But let me ask two ❍ July 2006
questions: ❍ August 2006
1. Is there something ❍ September 2006
MORE to being an Oracle ❍ October 2006
guru?
November 2006
2. Is there something

December 2006
extraneous in Burleson's

January 2007
Requirements? ❍

❍ February 2007
What is a Guru? ❍ March 2007
❍ April 2007
In my experience, guru ❍ May 2007
simply means anyone ❍ June 2007
with a very high level of October 2007
knowledge and

understanding. ❍ Current Posts


Generally I think it is
also implied that they
have a following of some
kind.

Strictly translated, guru


can mean "teacher" -
and in many places like
India and Indonesia I
understand that guru is
generally used in that
sense. Certainly we
picture gurus as having
mentors.

Reviewing Burleson's

http://thinkoracle.blogspot.com/2006_10_01_archive.html (3 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

Three Criteria

With that in mind, let's


take one final pass
through the three
criteria.

1. Credentials

Our first goal must be to


get past the
subjectiveness of this
criteria. After all, who is
to decide which degree
is prestigious enough,
which certifications are
necessary, and which
awards qualify?

That being said, it's fair


to say that an Oracle
guru would certainly be
capable of earning a
post-secondary degree,
Oracle certification, and
an Oracle ACE. But I
would also suppose that
they may not have had
the opportunity nor the
desire to pursue this.
These may be necessary
to PROMOTE oneself as a
guru, but not necessarily
to BE one.

Nevertheless, this is still


a valid criteria. But
instead of tangible
things like degrees,
certifications and
awards, which (if I may
be so bold) would be
possible (though
extremely difficult) to

http://thinkoracle.blogspot.com/2006_10_01_archive.html (4 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

accumulate without
attaining a thorough
understanding of Oracle,
we need to measure it
based upon the actual
understanding.

How do you measure an


actual understanding of
Oracle? I don't have that
answer, but I might
propose to test their
understanding, through
questions and problems.
Then again, I suppose
that's what academic
institutions, award
review boards and
certification exams do ...

2. Communicating Their
Knowledge

I didn't like this criteria


at first because it
excluded some amazing
DBAs with whom I have
had the pleasure to
work. However, given
the definition of a guru I
reviewed, it would seem
like educating others is
a necessary qualification.

Still, I've seen some


people communicate a
relatively mediocre
understanding of Oracle
through numerous
papers and books and
blogs. I've also seen
brilliant writers publish
only a single book (if
any), and an unarguable

http://thinkoracle.blogspot.com/2006_10_01_archive.html (5 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

guru like Jonathan


Lewis, until very
recently, had no blog at
all.

I've seen some people


answer countless
questions on Oracle
forums, and yet never
really impart true insight
or wisdom.

So again, this criteria


suffers from
subjectiveness. How do
we measure how
effectively a potential
guru has communicated
their knowledge?
Number of students?
Questions answered?
The students'
understanding of
Oracle? Some
combination thereof? If
so, how do we test the
understanding of the
students if I've already
conceded above that I
don't know how to
measure someone's
understand of Oracle in
the first place?

3. Attitude

Despite being the most


subjective criteria of the
three, I found the
attitude that Oracle
gurus share to be the
most interesting, and
the one on which I wish
Don Burleson had

http://thinkoracle.blogspot.com/2006_10_01_archive.html (6 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

elaborated further.

I like the way he


describe Oracle gurus as
those that seek
challenges, and have a
"can do" attitude. To me,
those two qualities
perfectly sum up how
I've been able identify
good sources of
mentorship in my
career. Some people
might have fantastic
knowledge and
experience, but like to
stick to what they know,
and are stubbornly
cynical about any
problem that falls
outside their comfort
zone.

Wrapping Up

Sadly, I really don't think


I've answered any
questions or cleared
anything up on this
matter, and I apologise
for that. However, if I
have helped to promote
and advance the
discussion, then I'm glad
I took the time to share
my thoughts with
everyone. I'd love to
hear yours: what makes
an Oracle guru?

// posted by Robert
Vollman @ Tuesday, October

31, 2006 15 comments

http://thinkoracle.blogspot.com/2006_10_01_archive.html (7 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

Monday, October 30,


2006
Oracle
Passwords
Hallowe'en is a time of
fright and mystery, and
some of the most
common, mysterious
Oracle questions I
collect involve
passwords. Here are
some tricks and treats:

How do you change an


Oracle password? ... If
you/the user forgot it?
How are Oracle
passwords stored?
Does it look the same
for two different users
using the same
password?
Do the SQL Trace files
reveal your secret
password?
How do you hide your
password from others
when running scripts?
How do you set/enforce
your password policy in
Oracle?
Which password-related
error messages can you
get in Oracle, and what
do they mean?

The scary truth is that


there is no mystery to
any of the answers. Each

http://thinkoracle.blogspot.com/2006_10_01_archive.html (8 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

answer can be readily


found in either the
Oracle Documentation
(more specifically, the
Oracle Administrator's
Guide), or among the
plentiful resources of
the Internet. It's all in
knowing where to look!
I've collected a few
answers to get you
started.

Changing Your Oracle


Password

If you already know your


Oracle password, you
can change it using an
SQL*Plus session by
simply typing
"password" and
following the
instructions.

If you have the


privileges, you can also
change a password
using ALTER USER.

ALTER USER username


IDENTIFIED BY password;

That is also the trick if


you have lost your
password. Of course,
you must have the
privileges.

Hopefully its not the


privileged user you've
lost the password for,
but if that's the case,
you can always try to the

http://thinkoracle.blogspot.com/2006_10_01_archive.html (9 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

default Oracle
usernames and
passwords (but
presumably you changed
it already). Perhaps you
want to allow more
users SYSDBA privileges?
I'll get to that ...

How Oracle Passwords


Are Stored

You can see the


usernames and
encrypted passwords in
the DBA_USERS table
(assuming you have
privileges).

SELECT username,
password FROM
dba_users WHERE
username = 'SCOTT';

If two users have the


same password, will it
mean they'll have the
same encrypted
password? NO. You can
try it yourself, or just
ask my featured blogger
Steve Callan. Steve also
explains how a DBA
can't determine your
secret password by
reading SQL TRACE of
your session.

Steve also turns us onto


a little trick where we
can save that encrypted
password and re-set it
after it was (accidentally

http://thinkoracle.blogspot.com/2006_10_01_archive.html (10 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

or deliberately) changed
using ALTER USER.

ALTER USER username


IDENTIFIED BY VALUES
'encrypted password';

Check out the Dizwell


wiki for a cleaner
example of restoring an
encrypted password.

Your Oracle Password


Policy

Steve also mentioned a


certain password policy
script, which you should
find here:

$ORACLE_HOME/rdbms/
admin/utlpwdmg.sql

Oracle supports some


fairly sophisticated
password policies, not
just requiring a certain
length or requiring
numerics. I won't
elaborate on the details,
which you can find in
the Oracle Administrator
Guide.

There are plenty of (non-


Oracle-specific) articles
out there on the need
for a strong password
policies. For instance,
according to a fact sheet
from Red Database
Security, changing the
minimum length of a

http://thinkoracle.blogspot.com/2006_10_01_archive.html (11 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

password from 8
characters to 9 can
make the different
between 2 days and 57
for a brute force attack!

Oracle Password Error


Messages

Speaking of Red
Database Security, they
did the job of
summarizing the various
error messages you can
get when you try to log
in, and what they mean.

ORA_28000: The
account is locked
Wait for
PASSWORD_LOCK_TIME
or contact your DBA

ORA-28001: The
password has expired
Change the password or
contact your DBA

ORA-00988: Missing or
invalid password(s)
Use double quotes for
the password (e.g. alter
user scott identified by "!
alex";)

ORA-01017: Invalid
username/password;
logon denied
Contact your DBA if the
problem still persists

The Password File

I mentioned two things

http://thinkoracle.blogspot.com/2006_10_01_archive.html (12 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

above:
1. Your encrypted
passwords are stored in
the database, accessible
through DBA_USERS.
2. You can grant SYSDBA
privileges to other users.

If my first point is
correct, what is the
password file? And what
does the second point
have to do with
anything? Well, put 1
and 2 together. The
password file is how you
grant those SYSDBA
privileges to other users.

How? By using ORAPWD:


The Oracle Password File
Utility. You'll find it in
$ORACLE_HOME/bin,
and you can create the
file like so:

orapwd file=filename
password=syspassword
entries=maxsysdbas
force=Y

You can find more


information in the
Oracle Administrator's
Guide, right at the top.

Speaking of which, here


is another error you
might get: ORA-01996.
In this case, you were
trying to grant SYSDBA
privileges to a user when
you already have
assigned this to the

http://thinkoracle.blogspot.com/2006_10_01_archive.html (13 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

maximum number of
users. Use this utility to
increase your limit.

Finally ...

You wrote a script which


connects to Oracle, and
you're worried that other
users can see the login
credentials you used to
execute the script. What
is the correct way
around this?

Connor McDonald
discusses four ways,
using OS accounts,
internal accounts, /
NOLOG and a last-resort
sqlplus trick.

Alternatively we can do
what we always do when
we want to know
something about Oracle,
we Ask Tom. Or, more
precisely, we assume
someone already has
and find out what he
said. In this case, he
instructs us to use the
'identified externally'
directive.

Normally I make a
reference to Tom Kyte
the final word, but this
time the honour will go
to someone equally
worthy: Jonathan Lewis.
His blog is long overdue,
and you can find his link

http://thinkoracle.blogspot.com/2006_10_01_archive.html (14 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

second from the top,


right next to Tom's
(sorry Eddie).

// posted by Robert
Vollman @ Monday, October

30, 2006 3 comments

Tuesday, October 24,


2006
Oracle
Conferences
If you follow the various
blogs on the right, you'll
see that practically
everybody (except me) is
currently attending
Oracle OpenWorld 2006.
It's an annual convention
held in San Francisco
late in the year. Lasts
about 4 days, and costs
around 2000 USD$.

I'd love to attend Oracle


OpenWorld some day. Or
practically any
conference. I would
especially like to visit
the annual conference
hosted by UKOUG. It
generally takes place
shortly after Oracle
OpenWorld, and its
about the same cost, but
maybe a few hundred
bucks cheaper. Makes
up for the airfare to
Birmingham.

Maybe for a warm-up I'd

http://thinkoracle.blogspot.com/2006_10_01_archive.html (15 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

finally meet up with Dan


Morgan at the Puget
Sound Oracle User's
Group's OracleDay in
Seattle. It's one day, and
I'm pretty sure its cheap
(or free) for members. If
you're not in my area,
check out the calendar I
got from the OTN web
site that lists some of
the local user groups
annual meetings.

Judging from that list,


there are three other
conferences I would
keep my eye on:

1. Oracle Development
Tool Users Group
Kaleidoscope, in June, to
be held in Daytona
Florida next year.
2. The 2nd ever PL/SQL-
specific OPP 2007, for 2
days in February/March
in San Francisco.
3. Oracle Applications
User Group Collaborate
2007 in Las Vegas next
April for 4 days.

If ever I do go to my first
Oracle convention, I'll be
sure to mention it here
and hopefully I can meet
some of you there.

// posted by Robert
Vollman @ Tuesday, October

24, 2006 2 comments

http://thinkoracle.blogspot.com/2006_10_01_archive.html (16 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

Thursday, October 19,


2006
3 Easy Ways to
Improve Your
PL/SQL
Want to know what has
been calling the PL/SQL
Procedure you've written?
Want to know how to tell
how far along your long-
running PL/SQL
Procedure is?
What to know how to
write fast mass insert/
deletes like a pro?

I have found you the


answer for all three,
courtesy of my fine
colleagues featured
among my links. Allow
me to guide you through
these three great articles.

Who Is Calling Your


Procedure?

The answer to our first


question comes courtesy
of Oracle's Blogger of
the Year Eddie Awad.

Eddie won this award


not just by virtue of
being first in an
alphabetical listing, but
also by the sheer volume
of focused articles of
high interest, each one
backed up by references
and proven tests. His
article about OWA_UTIL.

http://thinkoracle.blogspot.com/2006_10_01_archive.html (17 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

WHO_CALLED_ME is no
exception. His article
includes:
1. A working example
you can cut and paste,
2. A link to Oracle's
documentation, and
3. A link to Dan
Morgan's syntax
reference

Thanks to his diligence,


it literally took only
minutes to add this type
of instrumentation to my
existing code. When
something goes wrong, I
know exactly who called
my procedure, and
where. This even works
if the calling code is
wrapped. (Proof
forthcoming)

Given how easy it is, I


plan on testing the
overhead/performance
to see how feasible it
would be to start using
this as a metric by
creating this table and
adding this line:

CREATE TABLE
MyProcCalls
(caller_name VARCHAR2
(100), line_number
NUMBER(8));

INSERT INTO
MyProcCalls
(caller_name,
line_number) VALUES
(caller_name,

http://thinkoracle.blogspot.com/2006_10_01_archive.html (18 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

line_number);

Then I'll start looking


like a pro already.

How Far Along Is My


Procedure?

This answer comes from


my newest featured
blogger Andy Campbell.
He has been an Oracle
DBA for 7 years and, like
me, started a blog to
record the things he
learns and doesn't want
to forget.

Let's take advantage of


Andy's experience on
how to instrument our
PL/SQL code further by
including calls to
DBMS_APPLICATION_INFO
to record our
procedure's on-going
progress.

Andy explains, complete


with examples, how to
use this supplied
package (available as far
back as Oracle 7) to
have your procedure
write information into
session-tracking tables
using SET_MODULE and
then SET_ACTION.

Of course the big pay-


off comes at the end of
his article where he
executes his long-
running procedure and

http://thinkoracle.blogspot.com/2006_10_01_archive.html (19 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

then queries the session-


tracking tables like V
$SESSION to find out
how far along the
procedure is. Brilliant!

Let me supplement his


article with the following
three references:

1. Supplied Packages
References, Chapter 3:
DBMS_APPLICATION_INFO

2. Another one of my
favourite featured
bloggers, Oracle ACE of
the Year Tim Hall, is
reknowned for his great
articles. He also has a
write-up on how to use
DBMS_APPLICATION_INFO
and the V$SESSION
tables.

3. Finally, what list of


mine would be complete
without including Dan
Morgan's reference?

Thanks to Andy's
working example, it
literally took me minutes
to further instrument my
PL/SQL code and fool
people into thinking
they were written by a
true Oracle pro.

How Do I Write Mass


Inserts/Deletes Like a
Pro?

http://thinkoracle.blogspot.com/2006_10_01_archive.html (20 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

If we're going to code


like a pro, we need to
take at least one page
out of Tom Kyte's
playbook. Tom Kyte's
work is beloved for its
passion, dedication,
completeness and
accuracy.

Tom's has a passionate


distaste for bad
practises, including
slow-by-slow
processing.
Programmers unused to
thinking in sets are at a
distinct disadvantage
when programming
database applications.
Why? Because they do
their inserts and deletes
one-by-one in a for
loop.

As database
programmers know, this
approach is completely
unnecessary and
wasteful. They know
instead to look for a
solution that does some
kind of bulk processing
when doing inserts,
deletes or updates on a
large number of records.

Tom illustrates this


point with a specific
case where particularly
bad Oracle code had
been written.

http://thinkoracle.blogspot.com/2006_10_01_archive.html (21 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

The original requirement


was to prune down a list
of employees, removing
duplicate employees by
choosing the one with
the most recent hiring
date.

What did the original


programmer do? First,
created a big master
table of all employees,
then when through them
in a loop, each time
deleting employees that
produced more than one
record when grouped by
employee number.

Study how it was done


by the original
programmer. It might
not look like an
altogether unfamiliar
approach. But what do
you think about this
result?

Well, you may find that


the result was not only
very slow because it
would loop as often as
your most common
duplicate, but potentially
logically incorrect
because it would remove
an employee entirely if it
had duplicate records
with the same hiring
date.

Instead look how a true


pro handles this
situation. Tom handles

http://thinkoracle.blogspot.com/2006_10_01_archive.html (22 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

this case in a single,


efficient SQL statement.

He breaks the problem


down to its simplest
form: we need a list of
each employee with its
data, with only a single
row per employee
representing the most
recent hiring date.

Therefore Tom
populates such a table
by first adding a column
signifying the most
recent hiring date for
each employee (using
PARTITION BY, a
technique we've
discussed many times
before), then by
selecting only the rows
where the hiring date
and this most recent
hiring date match.

I admit this third tip is a


little harder to digest
than the first two,
because you have to
learn how to think like a
pro. Break a problem
down, and approach it
like a database would by
thinking in sets.

Summary

The true secret behind


these three tips is
actually to read. There
are a lot of Oracle
professionals just like

http://thinkoracle.blogspot.com/2006_10_01_archive.html (23 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

you, and we're fortunate


that so many of them
are generous with their
knowledge. Thanks!!!

Looking for more great


articles whenever I'm
quiet? Please bookmark
the links along the side
of the page. And visit
the articles in my
archives: you may have
especially missed some
of the early ones.

// posted by Robert
Vollman @ Thursday, October

19, 2006 0 comments

Tuesday, October 17,


2006
Software
Vendor
Customer
Support
Having worked in
technical support for
software vendors for 4
years, I know a few
strategies that can help
customers get the best
response.

1. Get training
Rely on the assistance of
the software vendor for
as little as possible.
Invest in training your
own people by signing
them up for courses

http://thinkoracle.blogspot.com/2006_10_01_archive.html (24 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

and, more importantly,


giving them the time to
learn the product and
how your company uses
it. Once knowledgeable,
your expert can get the
best results from the
vendor.

2. Avoid customizations
No product is going to
fit your needs exactly,
and it's tempting just to
make little fixes here
and there, but resist the
urge. Just because you
can do something, it
does not necessarily
follow that you should.
Consider leaving the
software as-is and just
changing your process.
Customizations can
cause problems, become
(legitimate or not)
obstacles preventing the
vendor from providing
you assistance, and
make upgrades more
problematic.

3. Stay current, but not


too current
Generally the vendor
offers the best support
for versions immediately
before the latest version.
If your version is too old,
they may have fewer
people that know it and
they may stop
supporting it altogether.
You don't want to stay

http://thinkoracle.blogspot.com/2006_10_01_archive.html (25 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

too current - let the


other customers find the
bugs in the latest
releases. Of course, if
you need the
functionality in the latest
version and the vendor
is prepared to give you
extra support for being
a guinea pig, go for it.

4. Allow for remote


access
Generally you should
never allow the vendors
on to your system, but
sometimes it will be
necessary, so be set up
to make that as easy as
possible.

5. Wait until you have


time
There is no point
opening a ticket with
them until your
resources have the time
to act on whatever they
suggest. Take too long
to respond and your
item will be
downgraded, perhaps
permanently. If
something is low priority
and you just want it "on
the record", then make
sure you say so.

6. Assign the right


priority
Every software vendor
will have standard
definitions where you
define the severity/

http://thinkoracle.blogspot.com/2006_10_01_archive.html (26 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

priority/impact of a
problem. It is tempting
to assign a higher
priority, but once you're
downgraded you may be
given a lower priority
than items that were
opened correctly at this
new downgraded level.
You can also get a
reputation that may
cause truly important
items to get
downgraded in the
future. Any way you slice
it, clearly explain the
business impact of your
problem, regardless of
priority, to avoid any
problems.

7. Answer the standard


questions in advance
Don't wait for them to
ask you the usual
questions: When did this
start, what changed, etc.
Anticipate their
questions and answer
them up front. Look
back at the questions
they usually ask as a
clue.

8. Provide a complete,
independent test case
Doing a little work
beforehand can save a
lot of time later.
Eliminate distractions
and narrow the problem
down to a simple,
reproducible step-by-

http://thinkoracle.blogspot.com/2006_10_01_archive.html (27 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

step description that will


work anywhere. Try to
use default data
wherever possible. A
test case is worth a
thousand words, so this
will save you days or
weeks of back-and-
forth explanations.

9. Provide all logs,


configuration files
Don't wait for them to
ask, go ahead and attach
all relevant configuration
files and logs. Tell them
what you've already tried
(from standard
troubleshooting
techniques in the
manual) and what the
results were for those
tests.

10. Make it as easy as


possible
Try to make your case
look as simple and clear
as possible. Some
vendors measure their
service representatives
by how many items they
close to the customer's
satisfaction. So they like
to pick off the low
hanging fruit. If your
case looks hard, it may
get neglected, or
assigned to someone
not new or skilled
enough to dodge the
tough ones.

11. Open separate tickets

http://thinkoracle.blogspot.com/2006_10_01_archive.html (28 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

Try not to lump


everything into one
ticket, or you risk having
your problem only
partially solved. Why not
open a separate item,
and have them work on
your issues in parallel? If
they're somewhat
related, you can always
say so in your
description. Worse case
scenario, solving one
solves the other and you
can just close both.

12. Escalate when you're


stuck
If you're not getting
anywhere, ask for the
issue to be escalated to
the manager. S/he will
make sure the right
people are working on it,
that there is a resolution
plan, and communicate
that information to you.
Keep going up if you
have to, managers have
managers too.

13. If you need extra,


pay for it.
If, for whatever reason,
you can't do certain
things for yourself, or
you need some extra
help from the software
vendor, offer to pay.
Money talks! You will get
results far faster and
more reliably than if you
just try to threaten or

http://thinkoracle.blogspot.com/2006_10_01_archive.html (29 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

cajole them into it.

14. Make sure the


solution is permanent
Try to keep the focus on
identifying and solving
the root cause, not the
consequence. It is
almost always advisable
to end a resolution with
a documentation
enhancement or a new
item in their solutions
knowledge base.
Volunteer to proof read
it.

Note: I originally wrote


this article in April, but it
was on my personal
blog. It occurs to me
that the Oracle
professionals that read
this blog might be
supporting 3rd-party
Oracle-based
applications, or perhaps
dealing with Oracle
support directly, and
therefore would enjoy
this article too.

Also, given my lack of


material lately, this is
the best way to confirm I
am still alive. :)

// posted by Robert
Vollman @ Tuesday, October

17, 2006 3 comments

http://thinkoracle.blogspot.com/2006_10_01_archive.html (30 of 31)1/9/2008 2:50:33 AM


OracleBlog: October 2006

http://thinkoracle.blogspot.com/2006_10_01_archive.html (31 of 31)1/9/2008 2:50:33 AM


OracleBlog: November 2006

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Tuesday,
About Me
November 14,
Name: Robert Vollman
2006
Location: Calgary, Alberta, Canada
100,000
more? I was born and raised in Ottawa, and have lived in
18 months. Calgary since 1991. I like playing sports (hockey,
107 posts. soccer, ultimate, basketball, you name it) and military board
110,000 reads. games. I also enjoy reading, walking, and playing with my 2 cats
Lilly and Brutus. I'm a database application specialist, whatever
Not too long ago that is.
I reacted with
humble View my complete profile
incredulity that
10,000 people
had read what I
had to say about
Best Links
Oracle. ● Ask Tom Kyte
● Oracle Docs
Here I am, ● Dan Morgan and PSOUG
exactly one year ● Steven Feuerstein
later, and there ● Jonathan Lewis
have been ● FAQ
100,000 more
Connor McDonald
visits. I'm almost

The Oak Table


afraid to

Cary Millsap and Hotsos


continue, will I ●

be talking about ● Steve Adams and Ixora

http://thinkoracle.blogspot.com/2006_11_01_archive.html (1 of 12)1/9/2008 2:50:36 AM


OracleBlog: November 2006

1,000,000 in ● Anjo Kolk and OraPerf


November 2007? ● Dizwell Oracle Wiki
● My Personal Blog
I wonder why
people are
reading my blog
because, despite
how numerous
Aggregators
we are, it seems Brian Duff's OraBlogs

like every other ❍ Eddie Awad's OracleNA


Oracle blogger ❍ Pete Finnigan's Aggregator
knows this ❍ Oracle's Bloglist
material far ❍ Oracle Base Aggregator
better than I. So
I've taken the
time to ask some
Top Blogs
Oracle's Ask Tom Kyte
of you why.

❍ Oracle Guru Jonathan Lewis


Although it ❍ Blogger of the Year Eddie Awad
would be nice if ❍ Data Warehouser David Aldridge
someone did me ❍ Oracle Geek Lewis Cunningham
the compliment ❍ Database Expert James Koopmann
of disputing my ❍ Dizwell's Howard Rogers
claim, instead it ❍ Oracle Master Laurent Schneider
appears that my ❍ Security Expert Pete Finnigan
lack of expertise ❍ Oracle Award Winner Mark Rittman
is part of the
Doug Burns
appeal. It seems

Oracle ACE of the Year Dr. Tim Hall


the average

UKOUG's Andrew (Arfur C.) Clarke


Oracle user out ❍

there is closer to ❍ Newbie DBA Lisa Dobson


my level rather ❍ Coffee-Drinking DBA Jon Emmons
than some ❍ Chris Foot
expert like, say, ❍ The Pythian DBA Team Blog
Laurent ❍ DBA Don Seiler
Schneider or Jeff ❍ DBA Coskan Gundogar
Hunter. ❍ Oracle WTF

Perhaps that
makes my work
ARCHIVES
LIST ALL ARTICLES
more accessible.

May 2005
The complexities

June 2005
of Oracle often

❍ July 2005

http://thinkoracle.blogspot.com/2006_11_01_archive.html (2 of 12)1/9/2008 2:50:36 AM


OracleBlog: November 2006

make you feel ❍ August 2005


dumb, so you ❍ September 2005
can come to me ❍ October 2005
to feel smart November 2005
again. :)

❍ December 2005
In that vein, I'd ❍ January 2006
like to get some ❍ February 2006
of you started on ❍ March 2006
your own blogs. ❍ April 2006
You may feel ❍ May 2006
intimidated ❍ June 2006
because of all ❍ July 2006
the experts out ❍ August 2006
there, but if ❍ September 2006
anything I'm
October 2006
proof that you

November 2006
don't have to be

December 2006
an Oracle guru

January 2007
to make a

contribution. ❍ February 2007


❍ March 2007
I think you'd be ❍ April 2007
surprised at just ❍ May 2007
how warm a ❍ June 2007
reception you'll ❍ October 2007
receive no
matter what level ❍ Current Posts
you're at. If you'd
like to give it a
try, I'm offering
you an audience
on my blog. I'd
be happy to
answer
questions,
review your first
few posts, and
invite others
here to do the
same, until you
have decided
whether or not

http://thinkoracle.blogspot.com/2006_11_01_archive.html (3 of 12)1/9/2008 2:50:36 AM


OracleBlog: November 2006

blogging is for
you.

My contact
information is in
my profile, I look
forward to
hearing from
you! And thanks
for reading!

// posted by Robert
Vollman @ Tuesday,
November 14,
2006 3 comments

Friday,
November 10,
2006
View
Constraints
You have a table
with all your
company's
financial
transactions.
There is another
table which
references a
subset of these
financial
transactions (ie.
transactions with
certain
properties).

Your current
solution to
maintain the
integrity is to set

http://thinkoracle.blogspot.com/2006_11_01_archive.html (4 of 12)1/9/2008 2:50:36 AM


OracleBlog: November 2006

up a foreign key,
referencing the
transactions
table, and then
write a trigger to
make sure that
any records
reference only
transactions that
have the correct
properties.

However, you
were struck with
a brilliant idea to
use views for a
more elegant
solution. You
create a view on
the transactions
table that
contains only the
proper subset,
and then set up
a foreign key to
the view instead.

You create the


view, including
the appropriate
primary key
constraint, and
you're all set to
go. Except when
you create your
table to
reference that
view, you see
this:

ERROR at line 1:
ORA-02270: no
matching unique
or primary key

http://thinkoracle.blogspot.com/2006_11_01_archive.html (5 of 12)1/9/2008 2:50:36 AM


OracleBlog: November 2006

for this column-


list

Have you done


something
wrong?

No. You've come


up with a very
clever solution,
but
unfortunately
one that isn't
supported.
According to
Oracle's SQL
Reference,
"Oracle does not
enforce view
constraints.
However, you
can enforce
constraints on
views through
constraints on
base tables."

Of course,
referencing the
base table
doesn't do you
any good,
because there
are transactions
in there that
aren't valid
references for
your new table.
Quoting Dan
Morgan: "The
point of the
syntax is to
prevent

http://thinkoracle.blogspot.com/2006_11_01_archive.html (6 of 12)1/9/2008 2:50:36 AM


OracleBlog: November 2006

violations when
people do DML
(inserts, updates,
deletes through
the view). It does
not truly serve
the same
purpose as a
"real" primary
key and can not
be used in the
same way."

However,
reading on, both
Table 17-3
(Object Privileges
Available for
Particular
Objects) and this
sentence seems
to offer some
hope that your
solution can be
achieved. "To
create a foreign
key constraint, in
addition, the
parent table or
view must be in
your own
schema, or you
must have the
REFERENCES
privilege on the
columns of the
referenced key in
the parent table
or view."

Alas, the
documentation is
misleading here.

http://thinkoracle.blogspot.com/2006_11_01_archive.html (7 of 12)1/9/2008 2:50:36 AM


OracleBlog: November 2006

It's talking about


the view itself
having a foreign
key, not the
primary. Observe.

SQL> CREATE
TABLE basetable
2 (id VARCHAR2
(32) PRIMARY
KEY, amount
NUMBER(10),
other_columns
VARCHAR2(32));

Table created.

SQL> GRANT
REFERENCES (id)
ON basetable TO
PUBLIC;

Grant succeeded.

SQL> CREATE OR
REPLACE
base_view
2 AS SELECT *
FROM basetable
WHERE amount >
100;

View created.

SQL> ALTER view


base_view ADD
CONSTRAINT
pk_view PRIMARY
KEY (id) RELY
DISABLE
NOVALIDATE;

View altered.

SQL> GRANT

http://thinkoracle.blogspot.com/2006_11_01_archive.html (8 of 12)1/9/2008 2:50:36 AM


OracleBlog: November 2006

REFERENCES (id)
ON base_view TO
PUBLIC;

Grant succeeded.

SQL> CREATE
TABLE referring
(person
VARCHAR2(32)
PRIMARY KEY,
2 base_id
REFERENCES
base_view(id));
CREATE TABLE
referring (person
VARCHAR2(32)
PRIMARY KEY,
*
ERROR at line 1:
ORA-02270: no
matching unique
or primary key
for this column-
list

That is not to say


that there isn't a
more elegant
solution to your
problem. One of
the many things
I've learned
about Oracle is
this: if
something clever
isn't working, re-
examine your
schema.

In fact that is
precisely the
advice that
Oracle ACE

http://thinkoracle.blogspot.com/2006_11_01_archive.html (9 of 12)1/9/2008 2:50:36 AM


OracleBlog: November 2006

Andrew "Arfur
C." Clarke gave
someone in your
exact same
position, who
had wisely
posted his
problem to a
forum (instead of
asking a dummy
like me).

For instance, you


could instead
create a table
representing the
subset of
financial
transactions you
want, and
another
identically-
structured table
for all other
transactions, and
then your
transactions
table could be a
view of both.
That's what one
expert
considered.
However, I'm not
sure that's what
you want:
maintaining two
identical tables.
Plus, now your
financial
transactions
table is a view
and can't be
referenced,

http://thinkoracle.blogspot.com/2006_11_01_archive.html (10 of 12)1/9/2008 2:50:36 AM


OracleBlog: November 2006

putting you in
the same boat
for some other
table.

I didn't intend to
offer a specific
suggestion for
your schema
because it would
require knowing
a lot more about
your business,
these tables, and
what your
requirements
really are. I'm
just saying that
there may be an
elegant solution
if you take a
closer look.

I preach views
because they
serve so many
useful purposes.
Unfortunately,
managing this
type of integrity
constraint
directly isn't one
of them. Stick to
your trigger.

// posted by Robert
Vollman @ Friday,
November 10,
2006 2 comments

http://thinkoracle.blogspot.com/2006_11_01_archive.html (11 of 12)1/9/2008 2:50:36 AM


OracleBlog: November 2006

http://thinkoracle.blogspot.com/2006_11_01_archive.html (12 of 12)1/9/2008 2:50:36 AM


OracleBlog: December 2006

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Monday, December
About Me
04, 2006
Name: Robert Vollman
REGEXP_LIKE Location: Calgary, Alberta, Canada
Recently I invited
anyone who has I was born and raised in Ottawa, and have lived
been considering in Calgary since 1991. I like playing sports
joining the Oracle (hockey, soccer, ultimate, basketball, you name it) and
blogging community military board games. I also enjoy reading, walking, and
to jump right in. playing with my 2 cats Lilly and Brutus. I'm a database
Please, help me application specialist, whatever that is.
encourage John H:
View my complete profile
Robert,

Way cool blog. I


really need to create Best Links
one too. I like to ● Ask Tom Kyte
adhere to best Oracle Docs
practices and love to

Dan Morgan and PSOUG


read stuff from Tom

Steven Feuerstein
K. and Steven F.!

● Jonathan Lewis
I have a question on ● FAQ
regular expression ● Connor McDonald
check constraints ● The Oak Table
and was wondering ● Cary Millsap and Hotsos
if you can help: ● Steve Adams and Ixora

http://thinkoracle.blogspot.com/2006_12_01_archive.html (1 of 6)1/9/2008 2:50:39 AM


OracleBlog: December 2006

● Anjo Kolk and OraPerf


alter table ● Dizwell Oracle Wiki
logical_address ● My Personal Blog
modify (address_ip
check (

regexp_like
(address_ip,'((^([2][0-
Aggregators
5]{2}\.|[2][0-4][0-9] Brian Duff's OraBlogs

\.| ❍ Eddie Awad's OracleNA


([0-1]\d\d)\.|\d\d\.| ❍ Pete Finnigan's Aggregator
\d\.)) ❍ Oracle's Bloglist
([2][0-5]{2}\.|[2][0-4] ❍ Oracle Base Aggregator
[0-9]\.|
([0-1]\d\d)\.|\d\d\.|
\d\.){2})(([2][0-5]{2}
Top Blogs
Oracle's Ask Tom Kyte
$)| ❍

([0-1]\d\d$)|(\d\d$)| ❍ Oracle Guru Jonathan Lewis


(\d$))'))) ❍ Blogger of the Year Eddie Awad
❍ Data Warehouser David Aldridge
Isn't there a better ❍ Oracle Geek Lewis Cunningham
way to write this? ❍ Database Expert James Koopmann
Oh! the pattern ❍ Dizwell's Howard Rogers
works in a Oracle Master Laurent Schneider
regexp_substr but

Security Expert Pete Finnigan


not in the

Oracle Award Winner Mark Rittman


regexp_like. Thanks

Doug Burns
in advance... ❍

❍ Oracle ACE of the Year Dr. Tim Hall


I applaud what John ❍ UKOUG's Andrew (Arfur C.) Clarke
is trying to do: ❍ Newbie DBA Lisa Dobson
manage the integrity ❍ Coffee-Drinking DBA Jon Emmons
of the data in the ❍ Chris Foot
database. His ❍ The Pythian DBA Team Blog
request is a common ❍ DBA Don Seiler
one, and I wish it ❍ DBA Coskan Gundogar
were even more ❍ Oracle WTF
common. Too many
databases are
designed to simply
ARCHIVES
trust that whatever ❍ LIST ALL ARTICLES
application is ❍ May 2005
providing the IP ❍ June 2005
address has already ❍ July 2005

http://thinkoracle.blogspot.com/2006_12_01_archive.html (2 of 6)1/9/2008 2:50:39 AM


OracleBlog: December 2006

checked it. ❍ August 2005


❍ September 2005
Unfortunately, I'm ❍ October 2005
limited in what November 2005
assistance I can

December 2005
provide with regards

January 2006
to regular

February 2006
expressions. Since

March 2006
I'm still using Oracle

April 2006
9, I can't take

advantage of one of ❍ May 2006


the finest features of ❍ June 2006
Oracle 10. I get a lot ❍ July 2006
of questions about ❍ August 2006
REGEXP in the past ❍ September 2006
year and a half, but I ❍ October 2006
can't offer much ❍ November 2006
more than those ❍ December 2006
links to articles and ❍ January 2007
references. ❍ February 2007
Wanting to offer ❍ March 2007
John something of ❍ April 2007
value, I wondered ❍ May 2007
how I would address ❍ June 2007
this issue in Oracle ❍ October 2007
9. I recall coming
across this once ❍ Current Posts
before, but we
actually chose to
store the IP address
as a 32-bit integer
which, by the way, is
the same way our OS
stored it. I wrote a
quick procedure that
would convert that
32-bit integer into a
readable IP address
(or "dotted-quad"
notation). The
specific details are
proprietary to the

http://thinkoracle.blogspot.com/2006_12_01_archive.html (3 of 6)1/9/2008 2:50:39 AM


OracleBlog: December 2006

company for which I


worked at the time,
but it should be easy
enough to reproduce
if you went that
route.

Of course, this
approach didn't
check that the 32-
bit integer was
convertible to an IP
address valid to my
application. That
problem, however, is
a specific case of a
very common
general requirement:
write a constraint to
check the validity of
a string. Briefly, in a
case like this, I
would convert the IP
address to special
coded string using
TRANSLATE, and
then CHECK if that
string matched a set
pattern. Further, in
particular complex
cases, I often resort
to checking the
constraint with a
trigger.

In the end, I
suggested John post
this question in an
Oracle forum. There
are lots of people
there, including
things who are
familiar with REGEXP

http://thinkoracle.blogspot.com/2006_12_01_archive.html (4 of 6)1/9/2008 2:50:39 AM


OracleBlog: December 2006

(unlike me) who can


give him a hand. But
I believe he came up
with a satisfactory
solution on his own.
I'm including it here,
and I know he would
appreciate a critique
if anyone familiar
with REGEXP has
something to offer.

alter table
logical_address
add constraint
la_address_ip_chk
check (
regexp_like(
address_ip,
'((^([2][0-5]{2}\.|[2]
[0-4][0-9]\.|([0-1]\d
\d)\.|\d\d\.|\d\.))([2]
[0-5]'||
'{2}\.|[2][0-4][0-9]\.|
([0-1]\d\d)\.|\d\d\.|
\d\.){2})(([2][0-5]{2}
$)|'||
'([0-1]\d\d$)|(\d\d
$)|(\d$))'
)
);

alter table
logical_address
add constraint
la_address_mac_chk
check (
regexp_like
(address_mac,
'((([0-9]|[A-Z]){2})(:))
{5}([0-9]|[A-Z]){2}|
((([0-9]|[A-Z]){2})(-))
{5}'||

http://thinkoracle.blogspot.com/2006_12_01_archive.html (5 of 6)1/9/2008 2:50:39 AM


OracleBlog: December 2006

'([0-9]|[A-Z]){2}'
)
);

alter table
logical_address
add constraint
la_port_chk
check (
regexp_like
(address_port,'[0! -9]
{5}| [0-9]{4}')
);

// posted by Robert
Vollman @ Monday,
December 04, 2006 2

comments

http://thinkoracle.blogspot.com/2006_12_01_archive.html (6 of 6)1/9/2008 2:50:39 AM


OracleBlog: January 2007

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be complicated, but it
is the most powerful tool when it comes to data. That's why when I think data, I think Oracle. I also enjoy
writing, so I use this format to organise my thoughts. Please feel free to discuss any thoughts you may
have on the same topics, even old ones (I will see and respond to such comments). You may want to
start with "LIST ALL ARTICLES" under Archives.

Thursday, January 25, 2007


About Me
REPOST: Pivot and Crosstab Queries Name: Robert
Here is another advanced concept that will come in useful Vollman
when solving Oracle problems. Location: Calgary,
Alberta, Canada
Imagine you're trying to create a result set where the rows
need to be columns, or vice versa. In essence, you need to
"pivot" rows into columns, or vice versa. That is a very I was born and raised in Ottawa,
common requirement, and this is where you need to look and have lived in Calgary since
at a pivot (or crosstab) query to get the job done. 1991. I like playing sports
(hockey, soccer, ultimate,
As always, when you want to understand something, you basketball, you name it) and
can start by Asking Tom. military board games. I also
enjoy reading, walking, and
A simple pivot query is accomplished by basically doing the playing with my 2 cats Lilly and
following: Brutus. I'm a database
1. Add some kind of count or row number to your query, if application specialist, whatever
necessary for the grouping that is.
2. Then use your (revised) original query as a sub-query
3. Use "decode" to turn rows into columns (ie. a "sparse" View my complete profile
matrix).
4. Use "max" to "squash" the multiple rows you moved to
columns, into single rows. Don't forget to group by.
(Note: it gets more complicated if you don't know how
Best Links
Ask Tom Kyte
many columns you'll need). ●

● Oracle Docs
Here is another one of Ask Tom's examples. It clearly ● Dan Morgan and PSOUG
shows how you use decode to create a "sparse" matrix, and ● Steven Feuerstein
then use max to "squash" it down. ● Jonathan Lewis
● FAQ
Let's look a simple example in slow motion. ● Connor McDonald
The Oak Table
Here's the data

CREATE TABLE CFL (season NUMBER(4), team VARCHAR2 ● Cary Millsap and Hotsos
(16), points NUMBER(3)); ● Steve Adams and Ixora
INSERT INTO CFL (season, team, points) VALUES (2004, ● Anjo Kolk and OraPerf

http://thinkoracle.blogspot.com/2007_01_01_archive.html (1 of 4)1/9/2008 2:50:42 AM


OracleBlog: January 2007

'Argonauts', 21); ● Dizwell Oracle Wiki


INSERT INTO CFL (season, team, points) VALUES (2004, ● My Personal Blog
'Alouettes', 28);
INSERT INTO CFL (season, team, points) VALUES (2004,

Aggregators
'Tiger-Cats', 19);
INSERT INTO CFL (season, team, points) VALUES (2004,
'Renegades', 10);
Brian Duff's OraBlogs
INSERT INTO CFL (season, team, points) VALUES (2003,

Eddie Awad's OracleNA


'Argonauts', 18);

Pete Finnigan's Aggregator


INSERT INTO CFL (season, team, points) VALUES (2003, ❍

'Alouettes', 26); ❍ Oracle's Bloglist


INSERT INTO CFL (season, team, points) VALUES (2003, ❍ Oracle Base Aggregator
'Tiger-Cats', 2);
INSERT INTO CFL (season, team, points) VALUES (2003, Top Blogs
'Renegades', 14); ❍ Oracle's Ask Tom Kyte
INSERT INTO CFL (season, team, points) VALUES (2002, ❍ Oracle Guru Jonathan Lewis
'Argonauts', 16); Blogger of the Year Eddie Awad
INSERT INTO CFL (season, team, points) VALUES (2002,

Data Warehouser David Aldridge


'Alouettes', 27);

Oracle Geek Lewis Cunningham


INSERT INTO CFL (season, team, points) VALUES (2002,

Database Expert James Koopmann


'Tiger-Cats', 15); ❍

INSERT INTO CFL (season, team, points) VALUES (2002, ❍ Dizwell's Howard Rogers
'Renegades', 10); ❍ Oracle Master Laurent Schneider
❍ Security Expert Pete Finnigan
What we want: ❍ Oracle Award Winner Mark
A table showing each of these 4 teams and their point Rittman
tables for these 3 seasons. ❍ Doug Burns
Oracle ACE of the Year Dr. Tim
So what is our pivot row/column? Season.

Hall
Step 1/2: We are using season, so we don't need to create ❍ UKOUG's Andrew (Arfur C.) Clarke
our own grouping field, like count, rownum, or running ❍ Newbie DBA Lisa Dobson
total (sum) for example. That would be easy enough to do, ❍ Coffee-Drinking DBA Jon Emmons
but let's keep this simple. ❍ Chris Foot
❍ The Pythian DBA Team Blog
Step 3: Use "decode" to turn the season row into a column. ❍ DBA Don Seiler
Take a look at our "sparse" matrix. ❍ DBA Coskan Gundogar
Oracle WTF
SELECT team, ❍

DECODE (season, 2002, points, NULL) Yr2002,


DECODE (season, 2003, points, NULL) Yr2003, ARCHIVES
DECODE (season, 2004, points, NULL) Yr2004 ❍ LIST ALL ARTICLES
FROM (SELECT season, team, points FROM CFL); ❍ May 2005
❍ June 2005
TEAM YR2002 YR2003 YR2004 ❍ July 2005
---------------- ---------- ---------- ---------- ❍ August 2005
Argonauts 21 ❍ September 2005
Alouettes 28 ❍ October 2005
Tiger-Cats 19
❍ November 2005
Renegades 10
❍ December 2005
Argonauts 18
❍ January 2006

http://thinkoracle.blogspot.com/2007_01_01_archive.html (2 of 4)1/9/2008 2:50:42 AM


OracleBlog: January 2007

Alouettes 26 ❍ February 2006


Tiger-Cats 2 ❍ March 2006
Renegades 14 ❍ April 2006
Argonauts 16 ❍ May 2006
Alouettes 27 ❍ June 2006
Tiger-Cats 15
❍ July 2006
Renegades 10
❍ August 2006
❍ September 2006
❍ October 2006
Step 4: Now let's use max to "squash" this into single rows. ❍ November 2006
Don't forget GROUP BY. ❍ December 2006
January 2007
SELECT team,

February 2007
MAX (DECODE (season, 2002, points, NULL)) Yr2002,

March 2007
MAX (DECODE (season, 2003, points, NULL)) Yr2003,

April 2007
MAX (DECODE (season, 2004, points, NULL)) Yr2004 ❍

FROM (SELECT season, team, points FROM CFL) ❍ May 2007


GROUP BY team; ❍ June 2007
❍ October 2007
TEAM YR2002 YR2003 YR2004
❍ Current Posts
---------------- ---------- ---------- ----------
Alouettes 27 26 28
Argonauts 16 18 21
Renegades 10 14 10
Tiger-Cats 15 2 19

Pretty cool, eh? Easy, too.

Notice that the key to this is DECODE. If DECODE is not


already part of your toolbelt, I recommend studying up.

Ready for a tougher example? Let's look at another Ask


Tom.

For further study of pivot queries and analytic functions in


general, there is an awesome write-up in Chapter 12 of
Tom Kyte's "Expert One-on-One Oracle." You'd think I'd get
a kickback from Tom Kyte with all the promotion I'm doing,
but the honest truth is that no one explains it as well as he.

So, do you understand pivot queries now? No problems?

If so, now you're ready for one of Ask Tom's more complex
examples.

Pivot Tables

One final word: don't confuse pivot queries with pivot


tables. Pivot tables are a different concept, and have

http://thinkoracle.blogspot.com/2007_01_01_archive.html (3 of 4)1/9/2008 2:50:42 AM


OracleBlog: January 2007

different uses (most typically to fill in missing data). Until I


blog about pivot tables, check out these two links:

Jonathan Gennick Updated


Laurent Schneider

Originally posted September 1, 2005

// posted by Robert Vollman @ Thursday, January 25, 2007 3 comments

http://thinkoracle.blogspot.com/2007_01_01_archive.html (4 of 4)1/9/2008 2:50:42 AM


OracleBlog: February 2007

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Monday, February
About Me
26, 2007
Name: Robert Vollman
Fun With Location: Calgary, Alberta, Canada
Tom Kyte
As devoted I was born and raised in Ottawa, and have lived in
readers may have Calgary since 1991. I like playing sports (hockey,
noticed, my new soccer, ultimate, basketball, you name it) and military board
job doesn't involve games. I also enjoy reading, walking, and playing with my 2
nearly as much cats Lilly and Brutus. I'm a database application specialist,
work with Oracle. I whatever that is.
stay sharp by
reading Ask Tom, View my complete profile
the very site that
has provided me
with 90% of the
answers that I
Best Links
can't find in Oracle ● Ask Tom Kyte
Oracle Docs
documentation or ●

Dan Morgan and PSOUG


figure out on my ●

own. ● Steven Feuerstein


● Jonathan Lewis
Those of you who ● FAQ
may find it nerdly ● Connor McDonald
to spend lunch ● The Oak Table
hours reading ● Cary Millsap and Hotsos
Oracle Q&A are ● Steve Adams and Ixora

http://thinkoracle.blogspot.com/2007_02_01_archive.html (1 of 7)1/9/2008 2:50:45 AM


OracleBlog: February 2007

actually really ● Anjo Kolk and OraPerf


missing out. It's ● Dizwell Oracle Wiki
far more ● My Personal Blog
entertaining than
you may realise.
To prove my
point, just from
posts updated in
Aggregators
Brian Duff's OraBlogs
the past week

Eddie Awad's OracleNA


alone, here are ❍

some little ❍ Pete Finnigan's Aggregator


hilarious ❍ Oracle's Bloglist
comments that ❍ Oracle Base Aggregator

Top Blogs
can only come
from Tom Kyte.
❍ Oracle's Ask Tom Kyte
1. Archiving Huge ❍ Oracle Guru Jonathan Lewis
Database ❍ Blogger of the Year Eddie Awad
Data Warehouser David Aldridge
This question is a

Oracle Geek Lewis Cunningham


tad vague, ❍

ambiguous and ❍ Database Expert James Koopmann


unanswerable. ❍ Dizwell's Howard Rogers
How long is a ❍ Oracle Master Laurent Schneider
piece of string? ❍ Security Expert Pete Finnigan
❍ Oracle Award Winner Mark Rittman
2. ❍ Doug Burns
Internationalization ❍ Oracle ACE of the Year Dr. Tim Hall
UKOUG's Andrew (Arfur C.) Clarke
Translation table

Newbie DBA Lisa Dobson


used for

Coffee-Drinking DBA Jon Emmons


processing input ❍

was: ❍ Chris Foot


❍ The Pythian DBA Team Blog
wud = would ❍ DBA Don Seiler
u = you ❍ DBA Coskan Gundogar
ur = your ❍ Oracle WTF
abt = about

I think your
ARCHIVES
keyboard might be ❍ LIST ALL ARTICLES
on the fritz? ❍ May 2005
Vowels are ❍ June 2005
disappearing left ❍ July 2005

http://thinkoracle.blogspot.com/2007_02_01_archive.html (2 of 7)1/9/2008 2:50:45 AM


OracleBlog: February 2007

and right ❍ August 2005


❍ September 2005
3. SQL Query
❍ October 2005
November 2005
Joins are not evil.

❍ December 2005
Databases were ❍ January 2006
BORN to join. ❍ February 2006
❍ March 2006
Joins are not evil. ❍ April 2006
May 2006
4. Collection

June 2006
Variable Types

❍ July 2006
Your naming ❍ August 2006
convention would ❍ September 2006
drive me utterly ❍ October 2006
nuts ❍ November 2006
❍ December 2006
5. What Don't You ❍ January 2007
Like About Oracle? ❍ February 2007
March 2007
*((char*)0) = "go

April 2007
away";

❍ May 2007
6. Backup Recovery ❍ June 2007
❍ October 2007
You have done it
totally wrong. ❍ Current Posts

Do it right.

Look - there is
one thing and one
thing only a DBA
is not allowed to
mess up. We can
fix everything
EXCEPT a bad
backup.
Everything else is
just a mistake.
Screwing up your
backups is far far

http://thinkoracle.blogspot.com/2007_02_01_archive.html (3 of 7)1/9/2008 2:50:45 AM


OracleBlog: February 2007

beyond a mistake
-- it is grounds
for immediate
"good bye, you are
the weakest link".

Could you, in
theory, perhaps --
maybe -- get
lucky and be able
to use them?
maybe,
sometimes, on
Tuesday when it is
raining.

Is it smart (NOT)
Is it the right way
(NOT)
Is it even a teeny
tiny bit reliable
(NOT)

I fail to see how


your example
even "makes
sense".

BONUS:

Q: TOM you are


not only expert of
Oracle but also
Windows.....
Thanks it worked.

A: I think I've just


been insulted :)

7. Fast Refresh is
Taking Longer
Than Complete
Refresh of
Materialized View

http://thinkoracle.blogspot.com/2007_02_01_archive.html (4 of 7)1/9/2008 2:50:45 AM


OracleBlog: February 2007

Just set:

fast=true

in the init.ora.

Sorry - it is
Monday and my
sense of humor is
just getting
warmed up :)

8. REDO Logs
Generated from
PL/SQL

Allow me to be
blunt. That would
be stupid. 100%.

9. Logminer

Tell the DBA ok

They will hate


themselves for
totally messing up
their lives.

I don't know what


else to say - this
is a horrible idea,
a great way for the
DBA to ensure
they have a job for
life - but a job
that no human
being would
actually want.

10. Designing
Tables

http://thinkoracle.blogspot.com/2007_02_01_archive.html (5 of 7)1/9/2008 2:50:45 AM


OracleBlog: February 2007

Q: How can we
achieve, easier
developer
understanding of
the table design,
without one
explaining the
table design
document / ER
Model.
A: Telepathy I
suppose?

BONUS: The All-


Time Classic

Oracle Database

Q: Dear tom can u


tell me the
meaning of
recursive query?

"U" is not available.

I have never met


this "U" person.

Do you know how


to contact "U" -
they get a lot of
requests, it would
be great if I could
pass the questions
on to them.

May "I" answer the


question?

// posted by Robert
Vollman @ Monday,
February 26, 2007 6

comments

http://thinkoracle.blogspot.com/2007_02_01_archive.html (6 of 7)1/9/2008 2:50:45 AM


OracleBlog: February 2007

http://thinkoracle.blogspot.com/2007_02_01_archive.html (7 of 7)1/9/2008 2:50:45 AM


OracleBlog: March 2007

OracleBlog
I love data. Collecting, storing, manipulating, studying and using data. Oracle may be
complicated, but it is the most powerful tool when it comes to data. That's why when I
think data, I think Oracle. I also enjoy writing, so I use this format to organise my
thoughts. Please feel free to discuss any thoughts you may have on the same topics,
even old ones (I will see and respond to such comments). You may want to start with
"LIST ALL ARTICLES" under Archives.

Friday, March 09,


About Me
2007
Name: Robert Vollman
40 Tips From Location: Calgary, Alberta, Canada
Tom
Everybody learns I was born and raised in Ottawa, and have lived
their lessons, and so in Calgary since 1991. I like playing sports
will you. The only (hockey, soccer, ultimate, basketball, you name it) and
variable is how military board games. I also enjoy reading, walking, and
expensive the lesson playing with my 2 cats Lilly and Brutus. I'm a database
is. While there is no application specialist, whatever that is.
substitute for direct,
first-hand View my complete profile
experience, the
cheapest way to learn
a lesson is to benefit
from the experience
Best Links
of others. ● Ask Tom Kyte
● Oracle Docs
My favourite source ● Dan Morgan and PSOUG
of cheap lessons is ● Steven Feuerstein
Ask Tom. I've ● Jonathan Lewis
compiled a sample ● FAQ
collection of Tom's ● Connor McDonald
Wisdom from just the The Oak Table
articles updated in

Cary Millsap and Hotsos


the past week.

Steve Adams and Ixora


Review this list and

http://thinkoracle.blogspot.com/2007_03_01_archive.html (1 of 10)1/9/2008 2:50:47 AM


OracleBlog: March 2007

consider how many ● Anjo Kolk and OraPerf


free lessons are ● Dizwell Oracle Wiki
contained in the past ● My Personal Blog
7 years of archived
information!

The number next to


every tip has a
Aggregators
hyperlink to the Brian Duff's OraBlogs

appropriate question. ❍ Eddie Awad's OracleNA


I included this ❍ Pete Finnigan's Aggregator
because I remember ❍ Oracle's Bloglist
that Tom's credo is ❍ Oracle Base Aggregator

Top Blogs
"Trust, but Verify."
Trust in Tom's
wisdom, but check Oracle's Ask Tom Kyte
the context of his

Oracle Guru Jonathan Lewis


advice so you can see

Blogger of the Year Eddie Awad


if it applies to your

situation, is still valid ❍ Data Warehouser David Aldridge


today, and that it ❍ Oracle Geek Lewis Cunningham
wasn't one of those ❍ Database Expert James Koopmann
rare cases where he ❍ Dizwell's Howard Rogers
got it wrong. ❍ Oracle Master Laurent Schneider
❍ Security Expert Pete Finnigan
As a bonus for those ❍ Oracle Award Winner Mark Rittman
who enjoyed my last Doug Burns
post about Tom's

Oracle ACE of the Year Dr. Tim Hall


more entertaining

UKOUG's Andrew (Arfur C.) Clarke


side, I've included a

Newbie DBA Lisa Dobson


bit more of his biting ❍

Coffee-Drinking DBA Jon Emmons


humour too.

❍ Chris Foot
1. Row-level locking ❍ The Pythian DBA Team Blog
has no overhead, not ❍ DBA Don Seiler
for 1 lock, not for 1 ❍ DBA Coskan Gundogar
billion locks ❍ Oracle WTF

ARCHIVES
2. Reads are never
blocked, and reads
don't block ❍ LIST ALL ARTICLES
3. The best UI is a ❍ May 2005
command line ❍ June 2005
4. Always use ❍ July 2005

http://thinkoracle.blogspot.com/2007_03_01_archive.html (2 of 10)1/9/2008 2:50:47 AM


OracleBlog: March 2007

packages, for all ❍ August 2005


good, real, ❍ September 2005
production code ❍ October 2005
4a. Never use a ❍ November 2005
standalone procedure ❍ December 2005
except for demos, January 2006
tests and standalone

February 2006
utilities that call

March 2006
nothing and are

called by nothing. ❍ April 2006


4b. Packages break ❍ May 2006
the dependency ❍ June 2006
chain, support ❍ July 2006
encapsulation, ❍ August 2006
increase namespace, ❍ September 2006
support overloading ❍ October 2006
and session ❍ November 2006
variables, and ❍ December 2006
promote overall good ❍ January 2007
coding techniques ❍ February 2007
5. Use the same
❍ March 2007
source control April 2007
techniques for PL/

May 2007
SQL as you would for

June 2007
any other language

(C, Java, VB) ❍ October 2007


6. Use dbms_stats
Current Posts
instead of Analyze

6a. Easier to
automate, the stated/
preferred way of
collecting statistics,
can analyze external
tables, gathers
statistics need for
CBO (and nothing
extra)
7. Serializable does
not imply serial
ordering
8. To be useful, know
more than just the

http://thinkoracle.blogspot.com/2007_03_01_archive.html (3 of 10)1/9/2008 2:50:47 AM


OracleBlog: March 2007

technology, know the


business and the
goals of your
organisation
9. Joins are not evil.
Databases were born
to join.
10. Never compare
strings to dates, and
dates to strings.
Compare dates to
dates, strings to
strings, numbers to
numbers and never
any other
combination.
11. Beware of implicit
conversions of dates
and numbers. Avoid
implicit like the
plague, explicit is
good
12. Never
TO_NUMBER a
number, never
TO_DATE a date
13. Stop using YY in
your date formatting,
now and forever
14. Autonomous
transactions as a
feature was a huge
mistake, they are
rarely used in a
manner that is safe.
15. Never copy online
redolog when your
database is in
archivelog mode
16. Never restore the
online redo log files
17. Rollback is not

http://thinkoracle.blogspot.com/2007_03_01_archive.html (4 of 10)1/9/2008 2:50:47 AM


OracleBlog: March 2007

just for
modifications, this is
fundamental about
Oracle
18. Stop committing
until your transaction
is complete
19. Don't use a loop
when a single query
will do
19a. Use bulk
processing instead of
slow-by-slow
processing
20. For performance
reasons, call PL/SQL
(or worse, Java) from
SQL if and where
there is quite simply
no other way
21. Large databases
are neither slow nor
scary
22. Analytical
functions are for
those who crave,
desire or just
sometimes NEED
speed.
23. The way to
understand is to do
24. Soft parse
percentage? 99% and
above is good.
25. Select only the
columns you need,
not *
26. When designing a
table, put the most
frequently access
columns first, those
most likely to be

http://thinkoracle.blogspot.com/2007_03_01_archive.html (5 of 10)1/9/2008 2:50:47 AM


OracleBlog: March 2007

NULL last, but don't


overnalyse it.
27. Disk is cheap.
Data integrity,
priceless.
28. You cannot put
CPU in the bank and
save it for later. If
you are at 99.99%
utilization -- pat
yourself on the back,
you've done well.
29. Analytics rock.
Analytics roll.
30. Don't use the
slower UNION when
UNION ALL will do
31. Never never
never do dynamically
what you can do
statitically, in PL/SQL.
32. You want to
scale? Use static SQL
in PL/SQL, all binds,
all the time.
33. Triggers are evil.
34. Magic should be
avoided. Experience
tells me this.
35. Never create stuff
as "sys" or "sysdba",
thats a special
magical account not
to be used by you or
me.
36. Be careful doing
anything non-
transactional in a
trigger. It won't
rollback when the
transaction rolls back.
36a. Be very careful

http://thinkoracle.blogspot.com/2007_03_01_archive.html (6 of 10)1/9/2008 2:50:47 AM


OracleBlog: March 2007

using any routine


that starts with UTL_
in a trigger, they're
generally non-
transactional
37. Use
dbms_application_info
package to allow you
to show a
procedure's progress
in v$session.
38. The sheer beauty
of PL/SQL is that your
concerns with other
languages, like
"parse once; execute
many" and using bind
variables are done
automatically and
transparently.
39. Cursor sharing is
a bad thing, if you
don't need it
40. Not binding is
actually harder to do
than binding (and
less secure)

More Tom Humour!

Refresh on
Materialized View

Q: see oracle bug no


2088032
A: And then scratch
your head and ask
"why am I reading
this bug report which
doesn't have
anything to do with
my problem?"

http://thinkoracle.blogspot.com/2007_03_01_archive.html (7 of 10)1/9/2008 2:50:47 AM


OracleBlog: March 2007

Update Statement
Not that I don't
believe you -- but --
I don't believe you.

Oracle PL/SQL -
Performance Tuning
- Comments in Code
In response to
someone saying their
code review team
told them to remove
comments from the
code for performance
reasons. I just KNEW
a good retort was
coming.

Oh my gosh.

I have never heard of


anything so - well, I
won't be that blunt,
fill in your favorite
word.
...
get a new code
review team, one that
actually knows how
to review code
...
umm, they are sort of
"not correct"

DBMS_JOB Package
This is one of Tom's
favourite comebacks
to someone saying "it
doesn't work."

My car won't start


either. why not?

Umm, define "does

http://thinkoracle.blogspot.com/2007_03_01_archive.html (8 of 10)1/9/2008 2:50:47 AM


OracleBlog: March 2007

not work"

String Concatenation
Q: Can you do the
same thing in
Micro