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. Fo