<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>The Anti-Kyte</title>
	<atom:link href="http://mikesmithers.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://mikesmithers.wordpress.com</link>
	<description>Oracle - for when it was like that when you got there</description>
	<lastBuildDate>Mon, 30 Jan 2012 20:31:19 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='mikesmithers.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>The Anti-Kyte</title>
		<link>http://mikesmithers.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://mikesmithers.wordpress.com/osd.xml" title="The Anti-Kyte" />
	<atom:link rel='hub' href='http://mikesmithers.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Turning off Code Completion in SQLDeveloper – a Grumpy Old Man Fights Back</title>
		<link>http://mikesmithers.wordpress.com/2012/01/28/turning-off-code-completion-in-sqldeveloper-a-grumpy-old-man-fights-back/</link>
		<comments>http://mikesmithers.wordpress.com/2012/01/28/turning-off-code-completion-in-sqldeveloper-a-grumpy-old-man-fights-back/#comments</comments>
		<pubDate>Sat, 28 Jan 2012 12:04:47 +0000</pubDate>
		<dc:creator>mikesmithers</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[SQLDeveloper]]></category>
		<category><![CDATA[code completion]]></category>
		<category><![CDATA[Enable Completion Auto-Popup in SQLWorksheet]]></category>
		<category><![CDATA[turn off code completion]]></category>

		<guid isPermaLink="false">http://mikesmithers.wordpress.com/?p=1241</guid>
		<description><![CDATA[“You&#8217;re problem is you&#8217;re BBC”, a colleague remarked recently. On further investigation, I found this not to be some reference to the British Broadcasting Corporation but rather that I had been “Born Before Computers”. Yes, I grew up – in computing terms at least – on the Command Line. A number of things have changed [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1241&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>“You&#8217;re problem is you&#8217;re BBC”, a colleague remarked recently.<br />
On further investigation, I found this not to be some reference to the British Broadcasting Corporation but rather that I had been “Born Before Computers”. Yes, I grew up – in computing terms at least – on the Command Line.<br />
A number of things have changed since those dim and distant days.<br />
Recently, I had a comment from <a href="http://darrylgriffiths.blogspot.com/">Darryl</a> claiming that chocolate bars had also been gradually reducing in size.<br />
Damning photographic evidence of this scandal has recently come into my possession&#8230;</p>
<div id="attachment_1242" class="wp-caption alignnone" style="width: 460px"><a href="http://mikesmithers.files.wordpress.com/2012/01/bounty.jpg"><img src="http://mikesmithers.files.wordpress.com/2012/01/bounty.jpg?w=450&#038;h=269" alt="" title="BOUNTY" width="450" height="269" class="size-full wp-image-1242" /></a><p class="wp-caption-text">A Bounty Bar from 1980 together with it&#039;s modern counterpart</p></div>
<p>There&#8217;s more. My phone keeps insisting that I can&#8217;t spell and arbitrarily replacing words when I&#8217;m writing an SMS.<br />
“You&#8217;re just the breast” took a bit of explaining to a rather skeptical Deb.<br />
Having finally persuaded my phone that I really don&#8217;t require it&#8217;s assistance when composing a short missive, I have now turned my attention to SQLDeveloper. <span id="more-1241"></span></p>
<p>Whilst most modern IDEs have those ever-so-helpful code completion features, I do sometimes find that they get in the way, especially when you know what you want to type. Pause for a second or two, or start going back to change something and that SQLDeveloper feels compelled to interrupt with some “helpful” suggestion of what I might want to put.</p>
<p>To put an end to these annoying interruptions, simply go to the <em>Tools</em> menu and select <em>Preferences&#8230;</em></p>
<p>In the tree on the left-hand side, expand the <em>Code Editor</em> node and click on <em>Completion Insight</em>.</p>
<p>Uncheck the boxes marked <strong>Enable Completion Auto-Popup in SQLWorksheet</strong> and <strong>Enable Completion Auto-Popup in PL/SQL Editor</strong>.</p>
<p><a href="http://mikesmithers.files.wordpress.com/2012/01/preferences.png"><img src="http://mikesmithers.files.wordpress.com/2012/01/preferences.png?w=450&#038;h=321" alt="SQLDeveloper &quot;Smart Alec&quot; settings" title="preferences" width="450" height="321" class="alignnone size-full wp-image-1243" /></a></p>
<p>No need to re-start, the changes should take effect as soon as you next start typing.</p>
<p>Now, if you should happen to require some assistance, you can simply press <em>CTRL + SPACE</em> and SQLDeveloper will present you  a variation on the theme of “helpful suggestion”.</p>
<p>Whilst I&#8217;m being a grumpy old man, what is it with all this spam ? All these unsolicited offers of Viagra. I mean, how do they know ?!</p>
<br />Filed under: <a href='http://mikesmithers.wordpress.com/category/oracle/'>Oracle</a>, <a href='http://mikesmithers.wordpress.com/category/sqldeveloper/'>SQLDeveloper</a> Tagged: <a href='http://mikesmithers.wordpress.com/tag/code-completion/'>code completion</a>, <a href='http://mikesmithers.wordpress.com/tag/enable-completion-auto-popup-in-sqlworksheet/'>Enable Completion Auto-Popup in SQLWorksheet</a>, <a href='http://mikesmithers.wordpress.com/tag/sqldeveloper/'>SQLDeveloper</a>, <a href='http://mikesmithers.wordpress.com/tag/turn-off-code-completion/'>turn off code completion</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mikesmithers.wordpress.com/1241/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mikesmithers.wordpress.com/1241/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mikesmithers.wordpress.com/1241/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mikesmithers.wordpress.com/1241/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mikesmithers.wordpress.com/1241/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mikesmithers.wordpress.com/1241/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mikesmithers.wordpress.com/1241/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mikesmithers.wordpress.com/1241/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mikesmithers.wordpress.com/1241/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mikesmithers.wordpress.com/1241/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mikesmithers.wordpress.com/1241/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mikesmithers.wordpress.com/1241/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mikesmithers.wordpress.com/1241/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mikesmithers.wordpress.com/1241/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1241&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mikesmithers.wordpress.com/2012/01/28/turning-off-code-completion-in-sqldeveloper-a-grumpy-old-man-fights-back/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e3cb0956016bbad280193fbbd8e649b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">Mike S</media:title>
		</media:content>

		<media:content url="http://mikesmithers.files.wordpress.com/2012/01/bounty.jpg" medium="image">
			<media:title type="html">BOUNTY</media:title>
		</media:content>

		<media:content url="http://mikesmithers.files.wordpress.com/2012/01/preferences.png" medium="image">
			<media:title type="html">preferences</media:title>
		</media:content>
	</item>
		<item>
		<title>Nested Tables – Flat-packed data in an Oracle Table</title>
		<link>http://mikesmithers.wordpress.com/2012/01/14/nested-tables-flat-packed-data-in-an-oracle-table/</link>
		<comments>http://mikesmithers.wordpress.com/2012/01/14/nested-tables-flat-packed-data-in-an-oracle-table/#comments</comments>
		<pubDate>Sat, 14 Jan 2012 19:01:44 +0000</pubDate>
		<dc:creator>mikesmithers</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[OraDBPedia Syndication]]></category>
		<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[create type as object]]></category>
		<category><![CDATA[dba_arguments]]></category>
		<category><![CDATA[nested table]]></category>

		<guid isPermaLink="false">http://mikesmithers.wordpress.com/?p=1231</guid>
		<description><![CDATA[In the aftermath of the holiday season, there follows the inevitable January sales. This year, I have been spared the inevitable trudge around the stores. Deb has hurt her knee and has therefore been restricted to browsing on-line. I thought she “kneeded” cheering up, but to date, my attempts at lightening the mood, seem only [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1231&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>In the aftermath of the holiday season, there follows the inevitable January sales.<br />
This year, I have been spared the inevitable trudge around the stores. Deb has hurt her knee and has therefore been restricted to browsing on-line.</p>
<p>I thought she “kneeded” cheering up, but to date, my attempts at lightening the mood, seem only to have given her the “kneedle”.</p>
<p>Sitting quietly, whilst Deb is wandering through various furniture store websites, I had cause to reflect on Oracle&#8217;s own version of Nested Tables.<br />
These were introduced way back in Oracle 8, when Oracle confidently predicted that the Object-Relational Database was the way of the future.<br />
Imagine if they were just bringing this feature out now. You can picture it. Larry would have spent months making disparaging remarks about IKEA&#8217;s occasional table range, before unveiling his own version, which was better, cheaper and more efficient.</p>
<p>Whilst you&#8217;re never going to be able to rest your pint on one, a Nested Table in Oracle may be useful on occasion. <span id="more-1231"></span></p>
<h3>The Application Error Log</h3>
<p>In many Oracle database applications you will find a utility that&#8217;s used for debugging issues.<br />
It consists of :</p>
<ul>
<li>a table to hold the error log information</li>
<li>a procedure to write to the table</li>
<li>a large amount of logging data</li>
</ul>
<p>The structure of the table will probably be something like this :<br />
<pre class="brush: sql;">
CREATE TABLE error_logs(
    username VARCHAR2(30),
    datetime TIMESTAMP,
    program_name VARCHAR2(30),
    parameters VARCHAR2(4000),
    message VARCHAR2(4000))
/
</pre></p>
<p>And the procedure is likely to be a variation on theme of :</p>
<p><pre class="brush: sql;">
CREATE OR REPLACE PROCEDURE log_error_pr (
    i_prog_name VARCHAR2, i_params VARCHAR2, i_err VARCHAR2) AS

    PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
    INSERT INTO error_logs(
        username, datetime, program_name,
        parameters, message)
    VALUES(
        USER, SYSTIMESTAMP, i_prog_name, 
        i_params, i_err);
    COMMIT;
END log_error_pr;
/ 
</pre></p>
<p>At this point, it&#8217;s worth considering the parameters column. Yes, it is a VARCHAR2(4000) and whilst this may, in exceptional circumstances, prove to be too small to hold the requisite data, on the whole it should be OK.<br />
Unfortunately, getting the required data ( in this case the parameter names and values) into the required format to go into the table requires a fair bit of messing about.</p>
<p><pre class="brush: sql; highlight: [21,22,23,24]; wrap-lines: false;">
CREATE OR REPLACE PROCEDURE trouble_pr(
    i_name IN VARCHAR2, i_payday IN VARCHAR2,
    i_been_to_ikea IN VARCHAR2)
     AS
    --
    -- This procedure only exists to cause trouble
    -- It starts off having just returned from a well-known 
    -- furniture store
    --
    l_msg VARCHAR2(4000);
    e_bits_missing EXCEPTION;
    l_params error_logs.parameters%TYPE;
BEGIN
    --
    -- here it comes...
    --
    l_msg := 'Back to the shop';
    RAISE e_bits_missing;
EXCEPTION
    WHEN OTHERS THEN
        l_params :=
            'i_name : '||i_name
            ||' i_payday : '||i_payday
            ||' i_been_to_ikea : '||i_been_to_ikea;
        log_error_pr( 
            i_prog_name =&gt; 'TROUBLE_PR',
            i_params =&gt; l_params,
            i_err =&gt; l_msg);
        RAISE_APPLICATION_ERROR(-20000, l_msg);
END trouble_pr;
/
</pre></p>
<p>Of course, you can have a peek in the data dictionary to get the parameter names by means of DBA_ARGUMENTS. You could then use this information in the error logging procedure meaning that you only had to build a string of parameter values in the order in which they appear in the program. However, looking at the parameter column, especially when there are a large number of parameters passed into the program in question, can get a bit tedious.</p>
<p>Let&#8217;s take a different approach which, for the want of a better gag, we&#8217;ll call the IKEA method.</p>
<h3>Object Relational thingys</h3>
<p>The steps for this are :</p>
<ul>
<li>create a database type to hold the data</li>
<li>create another type – essentially an arary of the first type</li>
<li>create the table with a column defined as the array type</li>
<li>enter and retrieve the data using the new column</li>
</ul>
<p>The base type essentially defines a record. The record consists of two fields – the parameter name and the parameter value :</p>
<p><pre class="brush: sql;">
CREATE or REPLACE TYPE paramlist_typ AS OBJECT( 
  param_name VARCHAR2(30), 
  param_val VARCHAR2(4000)) 
/  
</pre></p>
<p>Now to create an array of the first type. This will enable us to use the base type as a Nested Table :</p>
<p><pre class="brush: sql;">
CREATE or REPLACE TYPE paramlist_tab_typ AS TABLE OF paramlist_typ 
/
</pre></p>
<p>Next up, the table :</p>
<p><pre class="brush: sql; highlight: [5,7]; wrap-lines: false;">
CREATE TABLE error_logs( 
    username VARCHAR2(30), 
    datetime TIMESTAMP, 
    program_name VARCHAR2(30), 
    parameters paramlist_tab_typ, 
    message VARCHAR2(4000)) 
    NESTED TABLE parameters STORE AS paramlist 
/
</pre></p>
<h3>Insert and Select on a Nested Table</h3>
<p>Probably a good idea to go through a simple insert statement at this point to see how this nested table thing works :</p>
<p><pre class="brush: sql; highlight: [6,7,8,9]; wrap-lines: false;">
INSERT INTO error_logs( 
    username, datetime, program_name, 
    parameters, message) 
VALUES( 
    USER, SYSTIMESTAMP, 'TEST', 
    paramlist_tab_typ( 
        paramlist_typ('PARAM1', 'Someval'), 
        paramlist_typ('PARAM2', TO_CHAR(SYSDATE, 'DD-MON-RR HH24:MI')), 
        paramlist_typ('PARAM3', 123456)), 
    'Some error message') 
/
</pre></p>
<p>If we want to select from the nested table, we can do :</p>
<p><pre class="brush: sql; wrap-lines: false;">
SQL&gt; select parameters 
  2  from error_logs 
  3  where program_name = 'TEST'; 

PARAMETERS(PARAM_NAME, PARAM_VAL) 
-------------------------------------------------------------------------------- 
PARAMLIST_TAB_TYP(PARAMLIST_TYP('PARAM1', 'Someval'), PARAMLIST_TYP('PARAM2', '0 
7-JAN-12 20:44'), PARAMLIST_TYP('PARAM3', '123456')) 

</pre></p>
<p>Hmmm, not the most elegant output. By casting the parameters column in the error_logs table to a TABLE, we can flatten out the nested table, which looks quite a bit better :</p>
<p><pre class="brush: sql; highlight: [2]; wrap-lines: false;">
SQL&gt; SELECT pl.param_name, pl.param_val 
  2  FROM error_logs err, TABLE( err.parameters) pl 
  3  WHERE err.program_name = 'TEST'; 

PARAM_NAME	     PARAM_VAL 
-------------------- -------------------- 
PARAM1		     Someval 
PARAM2		     07-JAN-12 20:44 
PARAM3		     123456 

SQL&gt; 
</pre></p>
<p>Now we&#8217;ve got that sorted, we can see how this translates into our error logging utility.<br />
The procedure to log the errors first :</p>
<p><pre class="brush: sql; highlight: [3]; wrap-lines: false;">
CREATE OR REPLACE PROCEDURE log_error_pr ( 
    i_prog_name VARCHAR2, 
    i_params paramlist_tab_typ, 
    i_err VARCHAR2) AS 

    PRAGMA AUTONOMOUS_TRANSACTION; 
BEGIN 
    INSERT INTO error_logs( 
        username, datetime, program_name, 
        parameters, message) 
    VALUES( 
        USER, SYSTIMESTAMP, i_prog_name, 
        i_params, i_err); 
    COMMIT; 
END log_error_pr; 
/ 
</pre></p>
<p>And now for a procedure to call it :</p>
<p><pre class="brush: sql; wrap-lines: false;">
CREATE OR REPLACE PROCEDURE more_trouble_pr( 
    i_name VARCHAR2, 
    i_somedate DATE, 
    i_some_num NUMBER) IS 

    l_msg VARCHAR2(4000); 
    e_bits_missing EXCEPTION; 
    
BEGIN 
    l_msg := 'Where did I leave that lump hammer ?'; 
    RAISE e_bits_missing; 
EXCEPTION 
    WHEN OTHERS THEN 
        log_error_pr( 
            i_prog_name =&gt; 'MORE_TROUBLE_PR', 
            -- 
            -- Might be a good idea to do type conversions in 
            -- the program calling the error logging routine 
            -- as at this point we know, for example, what the 
            -- date format should be 
            --           
            i_params =&gt; paramlist_tab_typ( 
                paramlist_typ( 'i_name', i_name), 
                paramlist_typ( 'i_somedate', TO_CHAR(i_somedate, 'DD-MON-YYYY')), 
                paramlist_typ( 'i_some_num', TO_CHAR(i_some_num,9999)) 
            ), 
            i_err =&gt; l_msg); 
        RAISE_APPLICATION_ERROR(-20000, l_msg); 
END; 
/
</pre></p>
<p>And now to run the procedure :</p>
<p><pre class="brush: sql;">
SQL&gt; exec more_trouble_pr('MIKE', TO_DATE('03012012','DDMMRRRR'), 1234) 
BEGIN more_trouble_pr('MIKE', TO_DATE('03012012','DDMMRRRR'), 1234); END; 

* 
ERROR at line 1: 
ORA-20000: Where did I leave that lump hammer ? 
ORA-06512: at &quot;MIKE.MORE_TROUBLE_PR&quot;, line 28 
ORA-06512: at line 1 


SQL&gt; 
</pre></p>
<p>Now let&#8217;s have a look at the entry in the error_logs table :</p>
<p><pre class="brush: sql; wrap-lines: false;">
SQL&gt; SELECT pl.param_name, pl.param_val 
  2  FROM error_logs err, TABLE(parameters) pl 
  3  WHERE err.program_name = 'MORE_TROUBLE_PR'; 

PARAM_NAME	     PARAM_VAL 
-------------------- -------------------- 
i_name		     MIKE 
i_somedate	     03-JAN-2012 
i_some_num	      1234 
</pre></p>
<p>I could go on, but Deb has just forbade me from making any more “kneedless” puns on pain of having to live in the shed.</p>
<br />Filed under: <a href='http://mikesmithers.wordpress.com/category/oracle/'>Oracle</a>, <a href='http://mikesmithers.wordpress.com/category/oradbpedia-syndication/'>OraDBPedia Syndication</a>, <a href='http://mikesmithers.wordpress.com/category/plsql/'>PL/SQL</a>, <a href='http://mikesmithers.wordpress.com/category/sql/'>SQL</a> Tagged: <a href='http://mikesmithers.wordpress.com/tag/create-type-as-object/'>create type as object</a>, <a href='http://mikesmithers.wordpress.com/tag/dba_arguments/'>dba_arguments</a>, <a href='http://mikesmithers.wordpress.com/tag/nested-table/'>nested table</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mikesmithers.wordpress.com/1231/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mikesmithers.wordpress.com/1231/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mikesmithers.wordpress.com/1231/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mikesmithers.wordpress.com/1231/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mikesmithers.wordpress.com/1231/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mikesmithers.wordpress.com/1231/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mikesmithers.wordpress.com/1231/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mikesmithers.wordpress.com/1231/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mikesmithers.wordpress.com/1231/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mikesmithers.wordpress.com/1231/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mikesmithers.wordpress.com/1231/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mikesmithers.wordpress.com/1231/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mikesmithers.wordpress.com/1231/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mikesmithers.wordpress.com/1231/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1231&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mikesmithers.wordpress.com/2012/01/14/nested-tables-flat-packed-data-in-an-oracle-table/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e3cb0956016bbad280193fbbd8e649b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">Mike S</media:title>
		</media:content>
	</item>
		<item>
		<title>Upgrading to APEX 4.1 on XE 11g</title>
		<link>http://mikesmithers.wordpress.com/2011/12/20/upgrading-to-apex-4-1-on-xe-11g/</link>
		<comments>http://mikesmithers.wordpress.com/2011/12/20/upgrading-to-apex-4-1-on-xe-11g/#comments</comments>
		<pubDate>Tue, 20 Dec 2011 20:10:53 +0000</pubDate>
		<dc:creator>mikesmithers</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[OraDBPedia Syndication]]></category>
		<category><![CDATA[apex 4.1]]></category>
		<category><![CDATA[apex_public_user]]></category>
		<category><![CDATA[dba_registry]]></category>
		<category><![CDATA[ERR-1014]]></category>
		<category><![CDATA[flows_files]]></category>
		<category><![CDATA[Mint]]></category>
		<category><![CDATA[oracle 11gXE]]></category>
		<category><![CDATA[Oracle XDB]]></category>
		<category><![CDATA[owa_util.get_version]]></category>
		<category><![CDATA[PL/SQL Toolkit]]></category>
		<category><![CDATA[shared_pool_size]]></category>
		<category><![CDATA[sys as sysdba]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://mikesmithers.wordpress.com/?p=1221</guid>
		<description><![CDATA[It&#8217;s that time of year. Slay bells ringing, children singing&#8230;and the UKOUG Conference. This year, I was lucky to get along to attend the last day in the company of my good friend Alan. I love going to the Conference. You get the chance to see lots of great presentations about all sorts of things [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1221&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s that time of year. Slay bells ringing, children singing&#8230;and the UKOUG Conference.<br />
This year, I was lucky to get along to attend the last day in the company of my good friend Alan.</p>
<p>I love going to the Conference. You get the chance to see lots of great presentations about all sorts of things in the Oracle world.<br />
Takeaways from this year? Well, apart from the stress-ball and the cuddly Rhino ( yes, we did have a wander through the exhibition hall as well), I learned quite a bit about Application Express.</p>
<p>Just in case they&#8217;re struggling for an angle for APEX in the Oracle marketing department, how about :<br />
“Application Express – Forms 3.0 for the Internet Age”</p>
<p>I suppose I&#8217;d better do some explaining fairly quickly before I am taken to task by any APEX aficionados who happen to be reading.</p>
<p>Back in the good old days, when I still had hair, Forms 3 was the character based interface for the Oracle database. A major advance on Forms 2.3, you were able to code actual PL/SQL right into the triggers. Of course, everything ran on the server back then. Forms, the database ( we don&#8217;t talk about SQL*Reportwriter&#8230;ever !)</p>
<p>APEX has certain similarities to it&#8217;s ancestor. The code is stored in the database itself and you can write PL/SQL in it. Of course, it is also “web-aware”. It could easily be thought of as a UI for SQL and PL/SQL&#8230;without all that mucking about with Java.</p>
<p>Enough of this Oracle Tech naval gazing. The point of this post is that, if you&#8217;ve downloaded Oracle 11g XE, you will have APEX4.0 included. Due to the tiresome reluctance of software vendors to use major release numbers, you may have been under the misapprehension that APEX 4.1 was just a minor tweak. The truth is a rather different.</p>
<p>APEX is maturing rapidly. So, if you&#8217;re running XE 11g on a Debian OS ( or even 10g XE), you may very well be interested in getting the latest version of APEX to have a play with&#8230;</p>
<p><strong>NOTE</strong> – I ran this installation on 11g XE running on Mint.<br />
I&#8217;ve tried to highlight any differences you may get when installing on 10gXE, but I haven&#8217;t actually done the installation on this database version. <span id="more-1221"></span></p>
<h3>Pre-Installation Checks</h3>
<p>There are a few bits and pieces to check here :</p>
<ul>
<li>shared pool size</li>
<li>Oracle XDB version</li>
<li>PL/SQL Web Toolkit version</li>
</ul>
<h4>Shared Pool Size</h4>
<p>The shared pool size needs to be at least 100 MB. Shouln&#8217;t be a problem. In SQL*Plus you can check this by :</p>
<p><pre class="brush: plain; light: true;">
show parameter shared_pool_size
</pre></p>
<p>Alternatively, you can just run this query :</p>
<p><pre class="brush: plain; light: true;">
SELECT value
FROM v$parameter
WHERE name='shared_pool_size';

VALUE

--------------------------------------------------------------------------------

0

</pre></p>
<p>Hmmm, not quite so straight forward then.</p>
<p>When this parameter is set to 0 then Oracle automatically determines the size of the shared pool.<br />
If you&#8217;re running on a 64-bit OS then this should ( according to the documentation) equate to 128 MB. If you&#8217;re on a 32-bit OS however, this will default to 64MB.</p>
<p>If you need to change this parameter, then you can simply :</p>
<p><pre class="brush: plain; light: true;">
ALTER SYSTEM set shared_pool_size=100M;
</pre></p>
<p>If you do need to make this change then it&#8217;s probably best to stop and re-start the database at this point to make sure that the additional memory is utilized.</p>
<h4>Oracle XDB</h4>
<p>The Oracle XDB should be there by default on XE.<br />
Just to check :</p>
<p><pre class="brush: sql;">
SELECT comp_name, version, status
FROM dba_registry
WHERE comp_id = 'XDB';
</pre></p>
<p>Provided you get a row back from this query where the status is <em>VALID</em>, you&#8217;re good to go.</p>
<h4>PL/SQL Web Toolkit</h4>
<p>You need to have version 10.1.2.0.6 or later. Once again, this should already be there on XE. If you want to check then :</p>
<p><pre class="brush: sql;">
SELECT owa_util.get_version
FROM dual;
</pre></p>
<p>On 11gXE  you should get version 10.1.2.0.8.<br />
On 10g XE you&#8217;ll probably be on  version 10.1.2.0.4.</p>
<p>The APEX 4.1 download does come with files to install version 10.1.2.0.6 and you should be able to run this upgrade by means of the <em>owainst.sql</em> script which will be in the <em>apex/owa</em> directory after you&#8217;ve unzipped the download.<br />
If you are going to do this, then I&#8217;d suggest you do a full backup of the database beforehand because (a) it&#8217;s just good practice and (b) I&#8217;ve no idea if this will do what it claims without error on 10gXE.</p>
<p>In fact, even if everything is fine at this point, it&#8217;s still a good idea to backup your database before you run the installation&#8230; unless you don&#8217;t mind losing what you have on there already.</p>
<h3>Download Apex 4.1</h3>
<p>Next step is to download the <a href="http://www.oracle.com/technetwork/developer-tools/apex/downloads/index.html">Apex4.1 zip file from OTN.</a></p>
<p>NOTE – if I&#8217;m starting to bore you at this point and you&#8217;re tempted to follow the “official” installation instructions, <a href="http://www.oracle.com/technetwork/developer-tools/apex/upgrade-apex-for-xe-154969.html">the ones for XE</a> are a lot more concise and less confusing than the full-blown APEX installation guide ( <a href="http://docs.oracle.com/cd/E23903_01/doc/doc.41/e21673/toc.htm">which is here</a>).</p>
<p>Once you&#8217;ve downloaded the file – <em>apex_4.1_en.zip</em> to give it it&#8217;s full name ( I&#8217;ve just downloaded the English Language version), you need to copy it somewhere sensible.</p>
<p>In my case, I did the following :</p>
<p><pre class="brush: bash;">
cp apex_4.1_en.zip /u01/app/oracle
</pre></p>
<p>Wherever you choose to drop the file, you need to make sure that there are no spaces in the path. Otherwise, the script to install the icons isn&#8217;t very happy and you end up with a blank screen&#8230;er..so I&#8217;ve heard. I mean, I&#8217;ve got this friend who tried it. No obviously, I wasn&#8217;t dumb enough to do that myself. Ahem.</p>
<p>Anyway, next step is to unzip the file. To save lots of messing about with file permissions and such like, I just switched to the oracle user :</p>
<p><pre class="brush: bash;">
cd /u01/app/oracle
sudo su oracle
sudo unzip apex_4.1_en.zip
cd apex
</pre></p>
<p>That last cd was to the newly created apex directory. From this point on, this is where we&#8217;ll be running the apex upgrade scripts themselves.<br />
There is one more bit of admin before we get to that, but as the rest of this stuff happens on the database, we can connect now.</p>
<h3>At last – the installation</h3>
<p>You need to connect to Oracle as SYS as SYSDBA. If you&#8217;re the oracle user on the OS then – after making sure that your $ORACLE_SID is set to XE, you should simply be able to do :</p>
<p><pre class="brush: bash;">
sqlplus / as sysdba
</pre></p>
<p>If you want to be a bit more boring and conventional ( and haven&#8217;t su&#8217;d to oracle) then :</p>
<p><pre class="brush: bash;">
sqlplus sys as sysdba@xe
</pre></p>
<p>Now, whenever I&#8217;m in a multi-database environment, I do like to make sure that I&#8217;ve connected to the database I think I have. This makes it so much easier to avoid those hilarious situations where you mistakenly drop a production database or similar.<br />
Anyway, if you&#8217;re feeling equally paranoid then :</p>
<p><pre class="brush: plain; light: true;">
SELECT name FROM v$database;
</pre></p>
<p>This will either set your mind at ease ( in my case by returning &#8216;XE&#8217;) or cause you to quit the SQL session with unseemly haste.</p>
<p>Once we&#8217;re on the correct database as SYS then we first need to unlock the APEX_PUBLIC_USER:</p>
<p><pre class="brush: plain; light: true;">
ALTER USER apex_public_user UNLOCK;
</pre></p>
<p>Next, we need to find the default and temporary tablespaces for the APEX user in the database ( it should be SYSAUX and TEMP respectively) :</p>
<p><pre class="brush: sql;">
SELECT default_tablespace, temporary_tablespace
FROM dba_users
WHERE username = 'APEX_040000';
</pre></p>
<p>NOTE – if you&#8217;re running this on 10g XE with APEX 2 installed ( the version that 10gXE shipped with) then the username will be FLOWS_020100. There will also be a FLOWS_FILES user and you will need to make a note of the default tablespace for this user.</p>
<p>Now we can get on with running the scripts.<br />
First up is <em>apexins.sql</em>, which takes three arguments :</p>
<ul>
<li>default tablespace of the APEX user (usually SYSAUX)</li>
<li>the same as the first argument, unless you have the FLOWS_FILES user, in which case it&#8217;s the default tablespace of the FLOWS_FILES user( this is also SYSAUX by default)</li>
<li>the APEX user&#8217;s temporary tablespace (usually TEMP)
</li>
<li>a virtual directory for the APEX images ( I used “/i/” like it says in the installation notes)</li>
</ul>
<p>So, assuming your setup is like the one I&#8217;m using :</p>
<p><pre class="brush: sql;">
@apexins.sql SYSAUX SYSAUX TEMP /i/
</pre></p>
<p>You&#8217;ll be pleased to know that this script creates a logfile in the apex directory with a name in the format <em>installYYYY-MM-DD HH24:MI:SS.log</em>.<br />
You&#8217;ll be slightly less pleased to know that it&#8217;s a bit big (over 700K). Yes, it doesn&#8217;t sound that huge&#8230;until you have to wade through it.<br />
Anyway, this script takes a little while to run, especially on my asthmatic, ageing laptop with a whopping 1GB RAM and 2GHz Celeron Processor.</p>
<p>Eventually, I got the cheery message :<br />
&#8220;Now beginning upgrade. This will take several minutes&#8221;</p>
<p>This did cause me to wonder vaguely what on earth the script had been doing for the previous 25 minutes.<br />
Finally, the script completed and logged me off.</p>
<p>Now to load the images – by means of <em>apxldimg.sql</em>.<br />
This script accepts one parameter – the directory you unzipped apex into ( in my case, /u01/app/oracle).</p>
<p>Reconnect to the database as SYS as SYSDBA and run the script</p>
<p><pre class="brush: sql;">
@apxldimg.sql /u01/app/oracle
</pre></p>
<p>The final step is to set the password for the APEX ADMIN user :</p>
<p><pre class="brush: sql;">
@apxchpwd.sql
</pre></p>
<p>Enter the new password when prompted (it&#8217;s hidden so you won&#8217;t see anything when you type it in).<br />
You&#8217;ll be asked to reset the password as soon as you use it for the first time so it doesn&#8217;t need to conform to the databases password complexity rules at this stage.</p>
<h3>Post Installation steps</h3>
<p>If you now click on the link on your desktop to the database start page, you may get a bit of a shock.<br />
Instead of the start page, you&#8217;ll get the rather unfriendly <strong>“Error – ERR-1014 Application not found”</strong>.</p>
<p>Don&#8217;t worry, you haven&#8217;t missed a step ( necessarily). We&#8217;ll fix this in a minute.<br />
For now, point your browser at <a href="http://localhost:8080/apex/apex_admin">http://localhost:8080/apex/apex_admin</a>.</p>
<p>You will now be presented with a login screen.<br />
Enter admin as the username and the password you&#8217;ve just set for the admin user.</p>
<p>At this point, you&#8217;ll be asked to set a new password, which will have to conform to the password complexity rules ( unless you&#8217;ve disabled them) – i.e. at least one uppercase, and one punctuation character. The password will also need to be a minimum of 8 characters.</p>
<p>Once the password change has been processed, you&#8217;ll be asked to connect again using the new password.</p>
<p>You should now see :</p>
<div id="attachment_1222" class="wp-caption alignnone" style="width: 460px"><a href="http://mikesmithers.files.wordpress.com/2011/12/apex_admin.png"><img src="http://mikesmithers.files.wordpress.com/2011/12/apex_admin.png?w=450&#038;h=349" alt="" title="apex_admin" width="450" height="349" class="size-full wp-image-1222" /></a><p class="wp-caption-text">Looks like Christmas has come early</p></div>
<h4>Fixing the desktop link</h4>
<p>When you install 11gXE, a link to the APEX home page is automatically created on your desktop.<br />
The link calls a script called gettingstarted.sh in $ORACLE_HOME/config/scripts.</p>
<p>In order to fix the link, you need to edit this file.</p>
<p>The line :</p>
<p><pre class="brush: bash;">
/usr/bin/$ihttp://localhost:8080/apex/f?p=4950
</pre></p>
<p>needs to change to :</p>
<p><pre class="brush: bash;">
/usr/bin/$ihttp://localhost:8080/apex/
</pre></p>
<p>Deb is starting to fret that we haven&#8217;t quite got enough alcohol in the house to see us over the festive period, so it looks like I&#8217;m going to have to venture out into the cold winter evening and brave the crush at the all-night supermarket. Christmas &#8211; it&#8217;s for the kids really.</p>
<br />Filed under: <a href='http://mikesmithers.wordpress.com/category/linux-2/'>Linux</a>, <a href='http://mikesmithers.wordpress.com/category/oracle/'>Oracle</a>, <a href='http://mikesmithers.wordpress.com/category/oradbpedia-syndication/'>OraDBPedia Syndication</a> Tagged: <a href='http://mikesmithers.wordpress.com/tag/apex-4-1/'>apex 4.1</a>, <a href='http://mikesmithers.wordpress.com/tag/apex_public_user/'>apex_public_user</a>, <a href='http://mikesmithers.wordpress.com/tag/dba_registry/'>dba_registry</a>, <a href='http://mikesmithers.wordpress.com/tag/err-1014/'>ERR-1014</a>, <a href='http://mikesmithers.wordpress.com/tag/flows_files/'>flows_files</a>, <a href='http://mikesmithers.wordpress.com/tag/mint/'>Mint</a>, <a href='http://mikesmithers.wordpress.com/tag/oracle-11gxe/'>oracle 11gXE</a>, <a href='http://mikesmithers.wordpress.com/tag/oracle-xdb/'>Oracle XDB</a>, <a href='http://mikesmithers.wordpress.com/tag/owa_util-get_version/'>owa_util.get_version</a>, <a href='http://mikesmithers.wordpress.com/tag/plsql-toolkit/'>PL/SQL Toolkit</a>, <a href='http://mikesmithers.wordpress.com/tag/shared_pool_size/'>shared_pool_size</a>, <a href='http://mikesmithers.wordpress.com/tag/sys-as-sysdba/'>sys as sysdba</a>, <a href='http://mikesmithers.wordpress.com/tag/ubuntu/'>Ubuntu</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mikesmithers.wordpress.com/1221/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mikesmithers.wordpress.com/1221/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mikesmithers.wordpress.com/1221/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mikesmithers.wordpress.com/1221/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mikesmithers.wordpress.com/1221/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mikesmithers.wordpress.com/1221/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mikesmithers.wordpress.com/1221/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mikesmithers.wordpress.com/1221/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mikesmithers.wordpress.com/1221/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mikesmithers.wordpress.com/1221/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mikesmithers.wordpress.com/1221/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mikesmithers.wordpress.com/1221/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mikesmithers.wordpress.com/1221/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mikesmithers.wordpress.com/1221/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1221&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mikesmithers.wordpress.com/2011/12/20/upgrading-to-apex-4-1-on-xe-11g/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e3cb0956016bbad280193fbbd8e649b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">Mike S</media:title>
		</media:content>

		<media:content url="http://mikesmithers.files.wordpress.com/2011/12/apex_admin.png" medium="image">
			<media:title type="html">apex_admin</media:title>
		</media:content>
	</item>
		<item>
		<title>Installing Oracle 11gXE on Mint and Ubuntu</title>
		<link>http://mikesmithers.wordpress.com/2011/11/26/installing-oracle-11gxe-on-mint-and-ubuntu/</link>
		<comments>http://mikesmithers.wordpress.com/2011/11/26/installing-oracle-11gxe-on-mint-and-ubuntu/#comments</comments>
		<pubDate>Sat, 26 Nov 2011 20:00:59 +0000</pubDate>
		<dc:creator>mikesmithers</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[OraDBPedia Syndication]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[.bashrc]]></category>
		<category><![CDATA[/var/lock]]></category>
		<category><![CDATA[/var/lock/subsys]]></category>
		<category><![CDATA[alien]]></category>
		<category><![CDATA[chkconfig]]></category>
		<category><![CDATA[Debian]]></category>
		<category><![CDATA[dkpg --install]]></category>
		<category><![CDATA[libaio1]]></category>
		<category><![CDATA[Mint]]></category>
		<category><![CDATA[NLS_LANG]]></category>
		<category><![CDATA[Oracle Express Edition]]></category>
		<category><![CDATA[oracle xe]]></category>
		<category><![CDATA[Oracle XE 11g]]></category>
		<category><![CDATA[oracle_env.sh]]></category>
		<category><![CDATA[sudo su -]]></category>
		<category><![CDATA[uninstall Oracle]]></category>

		<guid isPermaLink="false">http://mikesmithers.wordpress.com/?p=1188</guid>
		<description><![CDATA[Things have been a bit hectic lately. What with putting in a new kitchen, being insanely busy at work, and trying not to come out with embarrassing sheep jokes, I&#8217;ve ended up with quite a long list of things to do blog-wise. Top of the list, until now, was installing the long-awaited Oracle 11gXE Release [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1188&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Things have been a bit hectic lately. What with putting in a new kitchen, being insanely busy at work, and trying not to come out with embarrassing sheep jokes, I&#8217;ve ended up with quite a long list of things to do blog-wise.<br />
Top of the list, until now, was installing the long-awaited Oracle 11gXE Release 2 onto one of my Linux machines.<br />
Yes, the free version of Oracle&#8217;s RDBMS has finally had an upgrade from 10g and I really want to get my hands on it and have a good nose around.<br />
As well as being based on the latest release of the RDBMS, the Express Edition has had one or two other improvements added. Maybe the most significant of these is that the limit for the amount of user data that XE can hold has been increased from 4GB to 11GB.<br />
What I&#8217;m going to do here is :</p>
<ul>
<li>Go through the package conversion process</li>
<li>Install the database using steps applicable both to Mint and Ubuntu ( and any other Debian based distro)</li>
<li>Apply some finishing touches so that the menu items work as intended</li>
<p>Along the way, we&#8217;ll find out just why Oracle can&#8217;t speak English (and lots of other languages), where Mint has hidden the .bashrc, and how Aliens can be friendly.
</ul>
<p>Because I&#8217;m trying to cover both distros in this post, the installation process will be done entirely on the command line. Don&#8217;t worry, it&#8217;s not as bad as it sounds.</p>
<p>But first&#8230;a small morsel of Linux history. Debian, the distro upon which both Mint and Ubuntu are based, was named after a Deb. I had to mention that as this will cause my beloved to think that I&#8217;m writing about her ( again), and thus give me enough time to finish writing this !</p>
<p>What are we waiting for then ? Let&#8217;s get going. <span id="more-1188"></span></p>
<h3>Before you install – counting the bits</h3>
<p>In fact, the experience of constructing flat-packed kitchen units will stand me in good stead for this installation. This is because, whilst XE is available for both 32 and 64-bit windows, Oracle have seen fit to release only a 64-bit version for Linux.<br />
This immediately presents me with a bit of a problem because all of my Linux installs are 32-bit.<br />
If you&#8217;re not sure whether your current installation is 32 or 64-bit, simply open a terminal and issue the command :<br />
<pre class="brush: bash;">
uname -i
</pre></p>
<p>If the output of this command is <em>x86_64</em>, the you&#8217;re good to go. If it&#8217;s <em>i686</em>, then you&#8217;re going to need to  install a 64-bit version of your OS before you go any further.<br />
For my part, I&#8217;ve taken one of my machines and installed a 64-bit version of Linux Mint 11.</p>
<h3>Getting the required Linux packages</h3>
<p>We need two packages for this installation – <em>libaio1</em>, which Oracle uses, and <em>alien</em>, which will allow us to convert Oracle&#8217;s rpm package to a Debian package, which we can then install.<br />
Oracle&#8217;s supported Linux distros are based on Red Hat so there is no Debian package available at the time of writing. Some kind soul may eventually build one ( as happened for 10gXE), but for now, we&#8217;ll just have to make do and mend.<br />
So, open Terminal and type :<br />
<pre class="brush: bash;">
sudo apt-get install alien libaio1
</pre></p>
<p>The next step is to get the Oracle package itself. Rather than go to a repository, we need to go to the web page. Oh, how Windows.<br />
Anyway, point your browser to the <a href="http://www.oracle.com/technetwork/database/express-edition/downloads/index.html">11g Express Edition Download Page.</a> and select Oracle Express Edition 11g Release 2 for Linux x64.<br />
If you haven&#8217;t already got an account, you&#8217;ll have to create one, but it doesn&#8217;t cost anything and you&#8217;re unlikely to get loads of spam filling up your inbox as a result.<br />
Save the file ( the default of the Downloads directory is as good as any) and away you go.<br />
Congratulations, you are now the proud owner of a 301 MB file called oracle-xe-11.2.0.1.0.x86_64.rpm.zip </p>
<h3>RPM to DEB&#8230;with nothing up your sleeves</h3>
<p>The next step is to unzip the downloaded file :<br />
<pre class="brush: bash;">
unzip oracle-xe-11.2.0.1.0.x86_64.rpm.zip
</pre></p>
<p>The output for this command should be something like :<br />
<pre class="brush: plain; light: true;">
Archive:  oracle-xe-11.2.0-1.0.x86_64.rpm.zip 
   creating: Disk1/ 
   creating: Disk1/upgrade/ 
  inflating: Disk1/upgrade/gen_inst.sql  
   creating: Disk1/response/ 
  inflating: Disk1/response/xe.rsp   
  inflating: Disk1/oracle-xe-11.2.0-1.0.x86_64.rpm  
</pre></p>
<p>The unzipped rpm is in the Disk1 sub-directory. Now all we need to do is to use alien to magically transform the ugly rpm into a beautiful deb. Look, she&#8217;s standing behind me right now, so I had to write that.</p>
<p><pre class="brush: bash;">
cd Disk1
sudo alien --scripts oracle-xe-11.2.0-1.0.x86_64.rpm
</pre></p>
<p>It&#8217;ll probably take a while, but eventually, you should get the following message :</p>
<p><pre class="brush: plain; light: true;">
oracle-xe_11.2.0-2_amd64.deb generated
</pre></p>
<h3>Re-arranging the furniture</h3>
<p>Before we play with our shiny new deb file, we need to do a bit of sorting out.<br />
Whilst Red Hat and Debian are both Linux, there are some variations in where stuff is kept. We need to make sure that these bits and pieces are accessible when we&#8217;re running the installation.<br />
I know this because I blithely ignored any of these precautions before I ran this the first time with, as they say, hilarious results.<br />
So, the following steps are definitely required if your flat-packed database is to be transformed into an all-singing all-dancing Oracle Instance.</p>
<h4>chkconfig</h4>
<p>For this particular tip, I&#8217;m indebted to a certain Dude who mentioned this in his installation guide for the XE11 beta on Ubuntu.</p>
<p>First off, check to see if you&#8217;ve got a chkconfig file under the <em>/sbin</em> directory.<br />
If not, then you need to create the chkconfig file as follows :</p>
<p><pre class="brush: bash;">
cd /sbin
vi chkconfig
</pre></p>
<p>The contents of the file ( taken from the above link, complete with comments) should be :</p>
<p><pre class="brush: bash; wrap-lines: false;">
#!/bin/bash
# Oracle 11gR2 XE installer chkconfig hack for Debian by Dude
file=/etc/init.d/oracle-xe
if [[ ! `tail -n1 $file | grep INIT` ]]; then
   echo &gt;&gt; $file
   echo '### BEGIN INIT INFO' &gt;&gt; $file
   echo '# Provides:             OracleXE' &gt;&gt; $file
   echo '# Required-Start:       $remote_fs $syslog' &gt;&gt; $file
   echo '# Required-Stop:        $remote_fs $syslog' &gt;&gt; $file
   echo '# Default-Start:        2 3 4 5' &gt;&gt; $file
   echo '# Default-Stop:         0 1 6' &gt;&gt; $file
   echo '# Short-Description:    Oracle 11g Express Edition' &gt;&gt; $file
   echo '### END INIT INFO' &gt;&gt; $file
fi
update-rc.d oracle-xe defaults 80 01
</pre></p>
<p>Now set the appropriate permissions on the file :</p>
<p><pre class="brush: bash;">
sudo chmod 755 chkconfig
</pre></p>
<p>When you list the file, you should see&#8230;<br />
<pre class="brush: plain; highlight: [2]; light: true;">
ls -l chkconfig
-rwxr-xr-x 1 root root 611 2011-11-20 15:12 chkconfig
</pre></p>
<p>Offer a silent prayer of thanks to the inestimable Mr Dude ( well, I assume it&#8217;s Mr from the name), and move on to&#8230;</p>
<h4>Awk</h4>
<p>But we&#8217;ve already got awk. I mean, this is Linux. Awk is always there. Except, apparently, when it&#8217;s somewhere else.<br />
In this case, Red Hat keeps awk under <em>/bin</em> whereas Debian puts it under <em>/usr/bin</em>.<br />
There is, fortunately, a simple fix – just create a symbolic link to <em>/usr/bin/awk</em> in <em>/bin</em> :</p>
<p><pre class="brush: bash;">
sudo ln -s /usr/bin/awk /bin/awk
</pre></p>
<p>If you check, you should now see an entry for awk in the /bin directory :<br />
<pre class="brush: bash; highlight: [3]; wrap-lines: false;">
cd /bin
ls -l awk
lrwxrwxrwx 1 root root 12 2011-11-20 15:49 awk -&gt; /usr/bin/awk
</pre></p>
<p>There is one more minor glitch to take care of, but to do this, we need to do the installation first. </p>
<h3>Installing Oracle</h3>
<p>For this bit, it&#8217;s probably a good idea to be connected as root.<br />
<pre class="brush: bash;">
sudo su -
</pre></p>
<p>If the $ prompt has suddenly become a # you can congratulate yourself on having been bestowed God-like powers. You are now root.<br />
A point to note here is that <em>su –</em> takes you to the home directory of the user you&#8217;re switching to ( in this case <em>/root</em>), so you need to cd back to the directory containing the .deb file ( in my case <em>/home/mike/Downloads/Disk1</em>).<br />
NOTE – stay connected as root for these next few steps. I&#8217;ll let you know when it&#8217;s safe to re-join us other mere mortals.<br />
OK, deep breath&#8230;</p>
<p><pre class="brush: bash;">
dpkg --install ./oracle-xe_11.2.0-2_amd64.deb 
</pre></p>
<p>At this point you should get output similar to the following :</p>
<p><pre class="brush: plain; light: true;">
Selecting previously deselected package oracle-xe. 
(Reading database ... 141714 files and directories currently installed.) 
Unpacking oracle-xe (from ./oracle-xe_11.2.0-2_amd64.deb) ... 
Setting up oracle-xe (11.2.0-2) ... 
Executing post-install steps... 

 Adding system startup for /etc/init.d/oracle-xe ... 
   /etc/rc0.d/K01oracle-xe -&gt; ../init.d/oracle-xe 
   /etc/rc1.d/K01oracle-xe -&gt; ../init.d/oracle-xe 
   /etc/rc6.d/K01oracle-xe -&gt; ../init.d/oracle-xe 
   /etc/rc2.d/S80oracle-xe -&gt; ../init.d/oracle-xe 
   /etc/rc3.d/S80oracle-xe -&gt; ../init.d/oracle-xe 
   /etc/rc4.d/S80oracle-xe -&gt; ../init.d/oracle-xe 
   /etc/rc5.d/S80oracle-xe -&gt; ../init.d/oracle-xe 

You must run '/etc/init.d/oracle-xe configure' as the root user to configure the database. 

Processing triggers for ureadahead ... 
ureadahead will be reprofiled on next reboot 
Processing triggers for bamfdaemon ... 
Rebuilding /usr/share/applications/bamf.index... 
Processing triggers for desktop-file-utils ... 
Processing triggers for python-gmenu ... 
Rebuilding /usr/share/applications/desktop.en_GB.utf8.cache... 
Processing triggers for libc-bin ... 
ldconfig deferred processing now taking place 
Processing triggers for python-support ... 
</pre></p>
<h4>If you want to start over</h4>
<p>From this point on, if, by some chance, you get to a point where you&#8217;ve got an intractable error, or realise you&#8217;ve missed a step, or simply decide that you really are better off with MySQL after all, you can uninstall Oracle with the following steps :<br />
<pre class="brush: bash;">
 /etc/init.d/oracle-xe stop 
</pre></p>
<p>Now remove the package&#8230;</p>
<p><pre class="brush: bash;">
dpkg --purge oracle-xe 
</pre></p>
<p>And finally, tidy-up&#8230;</p>
<p><pre class="brush: bash;">
rm -r /u01/app 
rm /etc/default/oracle-xe 
update-rc.d -f oracle-xe remove 
</pre></p>
<p>Assuming you&#8217;re still raring to go, before you run the final configuration, it&#8217;s time for that other bit of tidying up I mentioned earlier. </p>
<h4>Lock</h4>
<p>the <em>/etc/init.d/oracle-xe</em> that has just been created will be looking for a directory called <em>/var/lock/subsys</em>. On Debian distros this is located in <em>/var/lock</em>.</p>
<p><pre class="brush: bash;">
grep /var/lock/subsys /etc/init.d/oracle-xe
</pre></p>
<p>You should see this :<br />
<pre class="brush: plain; light: true;">
	touch /var/lock/subsys/listener 
	touch /var/lock/subsys/oracle-xe 
			touch /var/lock/subsys/listener 
		touch /var/lock/subsys/oracle-xe 
    if [ $RETVAL -eq 0 ] &amp;&amp; rm -f /var/lock/subsys/listener 
	rm -f /var/lock/subsys/oracle-xe 
</pre></p>
<p>Easiest way to fix this is :<br />
<pre class="brush: bash;">
sed -i 's,/var/lock/subsys,/var/lock,' /etc/init.d/oracle-xe
</pre></p>
<p>Now to when you check again&#8230;</p>
<p><pre class="brush: bash; highlight: [3,4,5,6,7];">
grep /var/lock/ /etc/init.d/oracle-xe

	touch /var/lock/listener 
	touch /var/lock/oracle-xe 
			touch /var/lock/listener 
		touch /var/lock/oracle-xe 
    if [ $RETVAL -eq 0 ] &amp;&amp; rm -f /var/lock/listener
</pre></p>
<h4>Configure Oracle</h4>
<p>Now, finally, we&#8217;re ready to roll. When you run the configuration, you&#8217;ll be prompted for </p>
<p>The HTTP Port for Application Express (default is 8080)<br />
The port for the listener (default is 1521)<br />
A password for SYS and SYSTEM<br />
Whether you want XE to start at boot time</p>
<p>Where appropriate, you can just press Enter to accept the default.</p>
<p><pre class="brush: bash; highlight: [11,13,19,21]; wrap-lines: false;">
/etc/init.d/oracle-xe configure

Oracle Database 11g Express Edition Configuration 
------------------------------------------------- 
This will configure on-boot properties of Oracle Database 11g Express 
Edition.  The following questions will determine whether the database should 
be starting upon system boot, the ports it will use, and the passwords that 
will be used for database accounts.  Press &lt;Enter&gt; to accept the defaults. 
Ctrl-C will abort. 

Specify the HTTP port that will be used for Oracle Application Express [8080]: 

Specify a port that will be used for the database listener [1521]: 

Specify a password to be used for database accounts.  Note that the same 
password will be used for SYS and SYSTEM.  Oracle recommends the use of 
different passwords for each database account.  This can be done after 
initial configuration: 
Confirm the password: 

Do you want Oracle Database 11g Express Edition to be started on boot (y/n) [y]:n 

Starting Oracle Net Listener...Done 
Configuring database...Done 
Starting Oracle Database 11g Express Edition instance...Done 
Installation completed successfully.
</pre></p>
<p>You&#8217;ll notice that I decided not to have XE startup on boot. I can make any number of technical justifications for this, but Deb just gives me a withering look and tells me it&#8217;s because I&#8217;m a control freak.</p>
<p>If you are similarly afflicted, do not despair. Once the installation is complete, you will have an option on the desktop menu to allow you to start the database ( assuming you&#8217;re condition is not acute and you prefer to start the database from the command line).<br />
NOTE – OK, that&#8217;s quite enough of the power trip. You can disconnect from the root account now.</p>
<p>Anyway, the last thing we need to do is setup the environment variables and then we can get on to the database.</p>
<p>Look, Oracle even provides a handy script to do this for us &#8211;  <em>/u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh</em>. I mean, what could possibly go wrong&#8230;</p>
<h3>Help ! Oracle can&#8217;t speak Welsh </h3>
<p>It&#8217;s English isn&#8217;t any better&#8230; y posiblimente, no hablo Espanol.<br />
I should probably explain this from the beginning.<br />
When I run the script, I get&#8230;</p>
<p><pre class="brush: bash; highlight: [2];">
sh /u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh 
export: 3: KINGDOM.AL32UTF8: bad variable name 
</pre></p>
<p>Time to take a closer look.</p>
<p><pre class="brush: plain; highlight: [4];">
cat /u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh
export ORACLE_HOME=/u01/app/oracle/product/11.2.0/xe 
export ORACLE_SID=XE 
export NLS_LANG=`$ORACLE_HOME/bin/nls_lang.sh` 
export PATH=$ORACLE_HOME/bin:$PATH 
</pre></p>
<p>The offending line is the NLS_LANG setting, for which another script is called – nls.lang.sh in the same directory.<br />
The script builds the NLS_LANG value by identifying the appropriate character set and then doing a lookup on locale.<br />
You can follow through what it&#8217;s doing as follows :<br />
<pre class="brush: bash;">
locale charmap
UTF-8
echo $LANG
en_GB.UTF-8
</pre></p>
<p>In the script, the <em>locale charmap</em> output ( UTF-8 in my case) gets resolved to AL32UTF8.<br />
The $LANG value then gets transformed as follows :<br />
<pre class="brush: bash;">
echo $LANG |sed 's/[.@].*$//'
en_GB
</pre><br />
The script then does another lookup to get the first half of the NLS_LANG value then outputs the concatenated string &#8230;</p>
<p><pre class="brush: bash;">
case $locale in 
…
en_gb) nlslang='ENGLISH_UNITED KINGDOM';;
…
esac

# construct the NLS_LANG 
# 
NLS_LANG=${nlslang}.${charset} 

echo $NLS_LANG 
</pre></p>
<p>Can you spot where the problem might be ?<br />
Yes, because it&#8217;s outputting a string with a space in it but not enclosing it in quotes, instead of returning ENGLISH_UNITED KINGDOM.AL32UTF8, it returns simply KINGDOM.AL32UTF8.</p>
<p>Having looked through the script, you may well encounter this problem if your $LANG starts with any of the following :</p>
<p>af_ZA (South Africa) – Note to Wayne – you don&#8217;t have this problem in Australia<br />
ar_AE (United Arab Emirates)<br />
ar_SA (Saudi Arabia)<br />
cs_CZ (Czech Republic)<br />
cy_GB(Wales) – just in case someone was getting smug<br />
en_BW(Botswana)<br />
en_HK( Hong Kong)<br />
en_NZ( New Zealand)<br />
en_ZA(South Africa)<br />
en_ZW(Zimbabwe)<br />
es_AR( Argentina)<br />
es_BO(Bolivia)<br />
es_CL(Chile)<br />
es_CO (Colombia) – yes German, even you<br />
es_CR(Costa Rica)<br />
es_DO (Dominican Republic)<br />
es_EC(Ecuador)<br />
es_GT(Guatemala)<br />
es_HN(Honduras)<br />
es_MX(Mexico)<br />
es_NI(Nicaragua)<br />
es_PA(Panama)<br />
es_PE(Peru)<br />
es_PR(Puerto Rico)<br />
es_SV(El Salvador)<br />
es_US( US Spanish)<br />
es_UY(Uruguay)<br />
es_VE(Venezuela)<br />
gv_GB(Isle of Man)<br />
kw_GB( Cornish)<br />
mi_NZ(Maori New Zealand)<br />
nl_NL( The Netherlands)<br />
pt_BR(Brazil)<br />
sr_YU( Serbian)<br />
zh_CN(China)<br />
zn_HK( Hong Kong – Chinese)<br />
zh_TW(Taiwan)</p>
<p>Given that this file is always run on the machine you are on, the simplest thing to do is to just edit the <em>oracle_env.sh</em> script and hard-code your NLS_LANG setting ( putting it in quotes)&#8230;.</p>
<p><pre class="brush: bash; highlight: [3];">
export ORACLE_HOME=/u01/app/oracle/product/11.2.0/xe 
export ORACLE_SID=XE 
export NLS_LANG='ENGLISH_UNITED KINGDOM.AL32UTF8' 
export PATH=$ORACLE_HOME/bin:$PATH 
</pre></p>
<p>If you now re-run the script, all the environment variables should now be set :</p>
<p><pre class="brush: bash;">
 sh /u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh 
echo $ORACLE_HOME 
/u01/app/oracle/product/11.2.0/xe 
echo $ORACLE_SID 
XE 
echo $NLS_LANG 
ENGLISH_UNITED KINGDOM.AL32UTF8 
echo $PATH 
/u01/app/oracle/product/11.2.0/xe/bin:/u01/app/oracle/product/11.2.0/xe/bin:...
</pre></p>
<p>At this point, you can go running off to play with your lovely new database. However, it&#8217;s probably worth doing a bit of housekeeping first.<br />
Deb&#8217;s eyes have just lit up at the mention of housekeeping and she&#8217;s started dropping hints about me running the hoover round so I&#8217;d better make this quick.</p>
<h3>Set environment variables on startup</h3>
<p>Rather than having to run the <em>oracle_env.sh</em> script every time you want to play with Oracle on the command line ( and to ensure that the desktop menu items work), it&#8217;s a good idea to just call the script from your .bashrc. You&#8217;ll probably want to add it to the oracle user&#8217;s .bashrc as well.<br />
At this point, Mint users ( at least, the newer ones like me) will be wondering why they can&#8217;t find a .bashrc in their home directory.</p>
<p>Apparently, Mint abandoned individual users having their own .bashrc as standard some years ago and instead, simply uses the system-wide file which is at <em>/etc/bash.basrc</em></p>
<p>Ubuntu users do have their own .bashrc in their home directory but, as with Mint, it executes after the <em>/etc/bash.bashrc</em></p>
<p>Rather than mess around with multiple .bashrc changes for both myself and oracle, I&#8217;ll just add the following to the end of <em>/etc/bash.bashrc</em><br />
<pre class="brush: bash;">
. /u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh
</pre></p>
<p>If you&#8217;re an independent minded soul, and do go down the route of setting up a .bashrc in your own home directory, make sure that it&#8217;s executable before you start another terminal session :</p>
<p><pre class="brush: bash;">
chmod a+x .bashrc 
</pre></p>
<h3>What&#8217;s on the Menu ?</h3>
<p>NOTE – as stated previously, I&#8217;m doing this on Mint. More to the point, I&#8217;m still on a Gnome 2.3 desktop. The steps here should be pretty much the same on Unity/Gnome 3/KDE/ Xfce but I can&#8217;t make any promises.</p>
<p>Whilst you&#8217;ve been doing all of that hacking around in terminal, there have been some changes to your Applications menu. Also, your desktop has acquired a new icon with the snappy name  <em>oraclexe-gettingstarted.desktop</em></p>
<p>There are a couple of things you now need to do to before you can go happily clicking on these options.</p>
<h4>The desktop icon</h4>
<p>Right-click the file on the desktop and select the Permissions tab.<br />
Now check the box to “Allow executing file as program”.<br />
Close the window.</p>
<p>You will notice that the icon has transformed into the familiar Oracle beehive and is now called<br />
<em>Get Started With Oracle Database 11g Express Edition</em>.</p>
<h4>Getting the Menu Options to work</h4>
<p>Before you take this invitation, there&#8217;s one more bit of tidying up, for which you&#8217;ll have to return to the command line. Well, you could do this via tools in the Administration menu but I&#8217;m trying to keep things generic here.<br />
So, once more unto the terminal dear friends, we need to make both ourselves and oracle members of the DBA group that was created as part of the installation :</p>
<p><pre class="brush: bash;">
sudo usermod -a -G dba oracle 
sudo usermod -a -G dba mike 
</pre></p>
<p>Just to check everything has gone according to plan :</p>
<p><pre class="brush: bash; highlight: [2];">
sudo grep dba /etc/group 
dba:x:1001:oracle,mike 
</pre></p>
<div id="attachment_1190" class="wp-caption alignnone" style="width: 460px"><a href="http://mikesmithers.files.wordpress.com/2011/11/oracle_menu.png"><img src="http://mikesmithers.files.wordpress.com/2011/11/oracle_menu.png?w=450&#038;h=360" alt="" title="oracle_menu" width="450" height="360" class="size-full wp-image-1190" /></a><p class="wp-caption-text">Red and Green should not be seen...unless you&#039;re installing Oracle on Mint</p></div>
<h3>Getting onto the database</h3>
<p>Finally, with the database up and running, click on the Getting Started icon.<br />
After a bit of thought on the part of your browser (well, Oracle actually), you should see something like this :</p>
<div id="attachment_1192" class="wp-caption alignnone" style="width: 460px"><a href="http://mikesmithers.files.wordpress.com/2011/11/dbhome_page1.png"><img src="http://mikesmithers.files.wordpress.com/2011/11/dbhome_page1.png?w=450&#038;h=307" alt="" title="dbhome_page" width="450" height="307" class="size-full wp-image-1192" /></a><p class="wp-caption-text">Ooohh, that looks a bit different. But it does prove it&#039;s working</p></div>
<h3>Speeding up startup</h3>
<p>Once the novelty wears off, you may begin to tire of the fact that Oracle seems to take an inordinate amount of time to start, and you&#8217;re never quite sure when it has actually started.<br />
The reasons for this are connected with the order in which XE starts various components. If you want to tweak this ( and add a desktop notification to boot), <a href="http://mikesmithers.wordpress.com/2011/05/16/oracle-xe-%e2%80%93-speeding-up-startup-and-getting-nofications-on-the-desktop-in-ubuntu/"> head over to this post</a>.</p>
<h3>Acknowledgement</h3>
<p>There&#8217;s a pretty good tutorial on XE installation by Alexander Penev <a href="https://confluence.bytesource.net/display/bytesourcepub/2011/04/02/Howto+install+Oracle+11XE+Beta+on+Ubuntu+10.04+x64">here</a>, which I used as a starting point. If you have any issues with these steps, it may well be worth a look.</p>
<p>I&#8217;d love to stay for a while, but domestic drudgery calls.</p>
<br />Filed under: <a href='http://mikesmithers.wordpress.com/category/linux-2/'>Linux</a>, <a href='http://mikesmithers.wordpress.com/category/oracle/'>Oracle</a>, <a href='http://mikesmithers.wordpress.com/category/oradbpedia-syndication/'>OraDBPedia Syndication</a>, <a href='http://mikesmithers.wordpress.com/category/ubuntu/'>Ubuntu</a> Tagged: <a href='http://mikesmithers.wordpress.com/tag/bashrc/'>.bashrc</a>, <a href='http://mikesmithers.wordpress.com/tag/varlock/'>/var/lock</a>, <a href='http://mikesmithers.wordpress.com/tag/varlocksubsys/'>/var/lock/subsys</a>, <a href='http://mikesmithers.wordpress.com/tag/alien/'>alien</a>, <a href='http://mikesmithers.wordpress.com/tag/chkconfig/'>chkconfig</a>, <a href='http://mikesmithers.wordpress.com/tag/debian/'>Debian</a>, <a href='http://mikesmithers.wordpress.com/tag/dkpg-install/'>dkpg --install</a>, <a href='http://mikesmithers.wordpress.com/tag/libaio1/'>libaio1</a>, <a href='http://mikesmithers.wordpress.com/tag/mint/'>Mint</a>, <a href='http://mikesmithers.wordpress.com/tag/nls_lang/'>NLS_LANG</a>, <a href='http://mikesmithers.wordpress.com/tag/oracle-express-edition/'>Oracle Express Edition</a>, <a href='http://mikesmithers.wordpress.com/tag/oracle-xe/'>oracle xe</a>, <a href='http://mikesmithers.wordpress.com/tag/oracle-xe-11g/'>Oracle XE 11g</a>, <a href='http://mikesmithers.wordpress.com/tag/oracle_env-sh/'>oracle_env.sh</a>, <a href='http://mikesmithers.wordpress.com/tag/sudo-su/'>sudo su -</a>, <a href='http://mikesmithers.wordpress.com/tag/ubuntu/'>Ubuntu</a>, <a href='http://mikesmithers.wordpress.com/tag/uninstall-oracle/'>uninstall Oracle</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mikesmithers.wordpress.com/1188/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mikesmithers.wordpress.com/1188/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mikesmithers.wordpress.com/1188/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mikesmithers.wordpress.com/1188/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mikesmithers.wordpress.com/1188/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mikesmithers.wordpress.com/1188/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mikesmithers.wordpress.com/1188/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mikesmithers.wordpress.com/1188/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mikesmithers.wordpress.com/1188/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mikesmithers.wordpress.com/1188/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mikesmithers.wordpress.com/1188/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mikesmithers.wordpress.com/1188/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mikesmithers.wordpress.com/1188/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mikesmithers.wordpress.com/1188/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1188&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mikesmithers.wordpress.com/2011/11/26/installing-oracle-11gxe-on-mint-and-ubuntu/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e3cb0956016bbad280193fbbd8e649b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">Mike S</media:title>
		</media:content>

		<media:content url="http://mikesmithers.files.wordpress.com/2011/11/oracle_menu.png" medium="image">
			<media:title type="html">oracle_menu</media:title>
		</media:content>

		<media:content url="http://mikesmithers.files.wordpress.com/2011/11/dbhome_page1.png" medium="image">
			<media:title type="html">dbhome_page</media:title>
		</media:content>
	</item>
		<item>
		<title>Speed Dating – NLS_DATE FORMAT in Oracle</title>
		<link>http://mikesmithers.wordpress.com/2011/11/23/speed-dating-nls_date-format-in-oracle/</link>
		<comments>http://mikesmithers.wordpress.com/2011/11/23/speed-dating-nls_date-format-in-oracle/#comments</comments>
		<pubDate>Wed, 23 Nov 2011 18:23:27 +0000</pubDate>
		<dc:creator>mikesmithers</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[OraDBPedia Syndication]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Date format mask RR]]></category>
		<category><![CDATA[NLS_DATE_FORMAT]]></category>

		<guid isPermaLink="false">http://mikesmithers.wordpress.com/?p=1180</guid>
		<description><![CDATA[When dealing with dates in a program, I&#8217;ll tend to err on the side of caution and explicitly do the conversion from a varchar to a date, specifying the format so there&#8217;s no chance of anything unexpected happening if the program should run in a session with a different NLS_DATE_FORMAT from that I&#8217;m using. However, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1180&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>When dealing with dates in a program, I&#8217;ll tend to err on the side of caution and explicitly do the conversion from a varchar to a date, specifying the format so there&#8217;s no chance of anything unexpected happening if the program should run in a session with a different NLS_DATE_FORMAT from that I&#8217;m using.<br />
However, if for example, I need to do a one-off data fix, sometimes, I just can&#8217;t be bothered with all that typing.<br />
<span id="more-1180"></span><br />
So, to save me writing TO_DATE all the time, I&#8217;ll just use :</p>
<p><pre class="brush: sql;">
ALTER SESSION SET NLS_DATE_FORMAT='DDMMRR'
</pre></p>
<p>Time for a quick example.</p>
<p>Let&#8217;s say we have a table called birthdays :</p>
<p><pre class="brush: sql;">
CREATE TABLE birthdays(
    person VARCHAR2(50),
    dob DATE)
/
</pre></p>
<p>Now, when I come to populate this table with all those dates I simply mustn&#8217;t forget, do I can just do this …</p>
<p><pre class="brush: sql;">
ALTER SESSION SET NLS_DATE_FORMAT='DDMMRR'
/

INSERT INTO birthdays( person, dob)
VALUES( 'LARRY', '170844')
/

INSERT INTO birthdays( person, dob)
VALUES( 'STEVE B', '240356')
/

INSERT INTO birthdays( person, dob)
VALUES( 'LEO', '180953')
/
</pre></p>
<p>That was easy, look ….</p>
<p><pre class="brush: sql; highlight: [6];">
SELECT person, TO_CHAR(dob, 'DD-MON-YYYY')
FROM birthdays
/
PERSON			       TO_CHAR(DOB,'DD-MON-YYYY')
------------------------------ ---------------------------------
LARRY			       17-AUG-2044
STEVE B 		       24-MAR-1956
LEO			       18-SEP-1953
</pre></p>
<p>Hmm, unless Oracle have acquired some Silicon Valley start-up that has IP rights on the fountain of youth (or possibly time travel), I think that may not have gone totally according to plan.</p>
<p>A better option may have been :<br />
<pre class="brush: sql;">
ALTER SESSION SET NLS_DATE_FORMAT='DDMMYYYY'
/

INSERT INTO birthdays( person, dob)
VALUES( 'LARRY', '17081944')
/

INSERT INTO birthdays( person, dob)
VALUES( 'STEVE B', '24031956')
/

INSERT INTO birthdays( person, dob)
VALUES( 'LEO', '18091953')
/
</pre></p>
<p>Now when we run the query we get :</p>
<p><pre class="brush: sql; highlight: [6];">
SELECT person, TO_CHAR( dob, 'DD-MON-YYYY')
FROM birthdays;

PERSON			       TO_CHAR(DOB,'DD-MON-YYYY')
------------------------------ ---------------------------------
LARRY			       17-AUG-1944
STEVE B 		       24-MAR-1956
LEO			       18-SEP-1953

</pre></p>
<p>Most of the time, the RR format works fine. However, if you&#8217;re messing around with dates before the 50th year of a century, you may well get problems like this.<br />
If the year number is less than 50, RR will assume that you&#8217;re talking about the current century. If it&#8217;s 50 or more, it&#8217;ll assume that you&#8217;re talking about the last century.<br />
Not an issue you&#8217;re likely to come across every day I grant you, but useful to know if you&#8217;re trying to suck up to billionaire tech tycoons.</p>
<br />Filed under: <a href='http://mikesmithers.wordpress.com/category/oracle/'>Oracle</a>, <a href='http://mikesmithers.wordpress.com/category/oradbpedia-syndication/'>OraDBPedia Syndication</a>, <a href='http://mikesmithers.wordpress.com/category/sql/'>SQL</a> Tagged: <a href='http://mikesmithers.wordpress.com/tag/date-format-mask-rr/'>Date format mask RR</a>, <a href='http://mikesmithers.wordpress.com/tag/nls_date_format/'>NLS_DATE_FORMAT</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mikesmithers.wordpress.com/1180/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mikesmithers.wordpress.com/1180/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mikesmithers.wordpress.com/1180/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mikesmithers.wordpress.com/1180/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mikesmithers.wordpress.com/1180/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mikesmithers.wordpress.com/1180/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mikesmithers.wordpress.com/1180/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mikesmithers.wordpress.com/1180/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mikesmithers.wordpress.com/1180/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mikesmithers.wordpress.com/1180/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mikesmithers.wordpress.com/1180/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mikesmithers.wordpress.com/1180/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mikesmithers.wordpress.com/1180/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mikesmithers.wordpress.com/1180/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1180&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mikesmithers.wordpress.com/2011/11/23/speed-dating-nls_date-format-in-oracle/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e3cb0956016bbad280193fbbd8e649b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">Mike S</media:title>
		</media:content>
	</item>
		<item>
		<title>Help &#8211; DBMS_SCHEDULER keeps Spamming me&#8230;and can&#8217;t tell the time either</title>
		<link>http://mikesmithers.wordpress.com/2011/11/10/help-dbms_scheduler-keeps-spamming-me-and-cant-tell-the-time-either/</link>
		<comments>http://mikesmithers.wordpress.com/2011/11/10/help-dbms_scheduler-keeps-spamming-me-and-cant-tell-the-time-either/#comments</comments>
		<pubDate>Thu, 10 Nov 2011 21:12:20 +0000</pubDate>
		<dc:creator>mikesmithers</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[OraDBPedia Syndication]]></category>
		<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[after startup on database trigger]]></category>
		<category><![CDATA[alter system enable restricted session]]></category>
		<category><![CDATA[create_job]]></category>
		<category><![CDATA[create_job_class]]></category>
		<category><![CDATA[create_service]]></category>
		<category><![CDATA[dbms_scheduler]]></category>
		<category><![CDATA[dbms_scheduler daylight saving]]></category>
		<category><![CDATA[dbms_service]]></category>
		<category><![CDATA[job_queue_processes]]></category>
		<category><![CDATA[ORA-27486]]></category>
		<category><![CDATA[run_job]]></category>
		<category><![CDATA[start_service]]></category>
		<category><![CDATA[systimestamp]]></category>
		<category><![CDATA[v$active_services]]></category>

		<guid isPermaLink="false">http://mikesmithers.wordpress.com/?p=1168</guid>
		<description><![CDATA[Sundays – a day of rest. Certainly true for me. Sunday morning is a time for lazing around leafing through the colour supplements and thinking about nothing in particular. Sunday 23rd October was a little bit different. Wide-awake at 8 am ( I didn&#8217;t know that there was such a time as 8am on a [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1168&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Sundays – a day of rest. Certainly true for me. Sunday morning is a time for lazing around leafing through the colour supplements and thinking about nothing in particular. Sunday 23rd October was a little bit different.<br />
Wide-awake at 8 am ( I didn&#8217;t know that there was such a time as 8am on a Sunday), like several million others, I was wondering what would confront the All Blacks – the Gallic flair with which France had swept aside England or the Gallic shrug with which they had surrendered to Tonga ?<br />
Look, I&#8217;m not really a New Zealander. Yes, I was born in Auckland but both my parents are English and I&#8217;ve lived most of my life in England. However, like anyone with a connection to the Land of the Long White Cloud, there is a part of my soul, however small, that takes the form of a Rugby ball.<br />
At the end of the match, I was able to join my &#8220;fellow&#8221; Kiwis in, not so much paroxysms of joy as a huge collective sigh of relief.</p>
<p>On the whole though, I&#8217;d rather not have to see Sunday morning from that early on. So, if there is, for example, something that needs to run on my database on a Sunday morning, I&#8217;d rather the database just did it without my intervention.</p>
<p>What I plan to do here is :</p>
<ol>
<li>set up a scheduler job</li>
<li>explore the ways in which we can control whether a class of job runs on a given database</li>
<li>stop jobs running on database startup</li>
<li>teach the scheduler how to tell the time – especially in terms of daylight saving</li>
</ol>
<p><span id="more-1168"></span></p>
<h3>Creating a scheduler job</h3>
<p>There is a really good and comprehensive guide on the myriad options available for Oracle&#8217;s database scheduler over at <a href="http://www.oracle-base.com/articles/10g/Scheduler10g.php.">Oracle Base</a>.</p>
<p>Here, I&#8217;m going to keep things quick and simple.<br />
I&#8217;ve got a table that looks something like this :</p>
<p><pre class="brush: sql;">
CREATE TABLE reminders(
    message VARCHAR2(4000),
    msg_ts TIMESTAMP)
/
</pre></p>
<p>For some reason I can&#8217;t think of right now, I need to insert a row into this table at 8.30 every Sunday morning.<br />
Rather than me having to drag my weary bones all the way to the keyboard, I can simply get the database to remember to do it. So, as a user with CREATE JOB privilege :</p>
<p><pre class="brush: sql; wrap-lines: false;">
DECLARE
    l_job_action VARCHAR2(500) := 
        'BEGIN '
            ||'INSERT INTO reminders( message, msg_ts) '
            ||'VALUES(''What time do you call this ?'', SYSTIMESTAMP); '
            ||'END;';
    
BEGIN
    DBMS_SCHEDULER.CREATE_JOB(
        job_name =&gt; 'wakeup_sun',
        job_type =&gt; 'PLSQL_BLOCK',
        job_action =&gt; l_job_action,
        start_date =&gt; SYSDATE,
        repeat_interval =&gt; 'freq=weekly; byday=SUN; byhour=8; byminute=30',
        end_date =&gt; NULL,
        enabled =&gt; TRUE,
        comments =&gt; 'Do something automatically on Sunday morning');
END;
/
</pre></p>
<p>Notice anything odd about the START_TIME parameter ? Neither did I&#8230;at first. We&#8217;ll come back to this a little later. In the meantime, if we want to test that our job will actually do what we need it to, we can do a test run :</p>
<p><pre class="brush: sql;">
BEGIN
    DBMS_SCHEDULER.RUN_JOB(job_name =&gt; 'wakeup_sun');
END;
/

PL/SQL procedure successfully completed.

SQL&gt; SELECT * 
  2  FROM reminders;

MESSAGE
------------------------------
MSG_TS
---------------------------------------------------------------------------
What time do you call this ?
10-NOV-11 20.16.09.044987

</pre></p>
<p>We could even tidy things up a bit by creating a stored procedure to do the work and then just calling that from the scheduler job.</p>
<p><pre class="brush: sql; wrap-lines: false;">
CREATE OR REPLACE PROCEDURE sunday_am_pr IS
BEGIN
    INSERT INTO reminders( message, msg_ts)
    VALUES( 'Now we know that DBA stands for Does Bugger All !', SYSTIMESTAMP);
END sunday_am_pr;
/
</pre></p>
<p>And now the job to call it …</p>
<p><pre class="brush: sql; wrap-lines: false;">
BEGIN
    DBMS_SCHEDULER.CREATE_JOB(
        job_name =&gt; 'sunday_am',
        job_type =&gt; 'STORED_PROCEDURE',
        job_action =&gt; 'sunday_am_pr',
        start_date =&gt; SYSDATE,
        repeat_interval =&gt; 'freq=weekly; byday=SUN; byhour=8; byminute=30',
        end_date =&gt; NULL,
        enabled =&gt; TRUE,
        comments =&gt; 'Do something automatically on Sunday morning');
END;
/
</pre></p>
<h3>The scheduler can&#8217;t tell the time</h3>
<p>Let&#8217;s have a look at those jobs we just created in a little more detail :</p>
<p><pre class="brush: sql; highlight: [8];">
SQL&gt; SELECT TO_CHAR(start_date, 'DD-MON-RR HH24:MI:SS TZR')
  2  FROM dba_scheduler_jobs
  3  WHERE owner = USER
  4  AND job_name = 'SUNDAY_AM';

TO_CHAR(START_DATE,'DD-MON-RRHH24:MI:SSTZR')
--------------------------------------------------------------------------------
10-NOV-11 20:22:55 +00:00

SQL&gt; 
</pre></p>
<p>Hmmm, the start time doesn&#8217;t seem to have an offset to account for daylight savings. So, rather than using SYSDATE as the START_TIME when defining a job, maybe we should be using SYSTIMESTAMP ?<br />
Well, yes and no. SYSTIMESTAMP will work fine for jobs that have run intervals of less than 24 hours. However, for jobs such as this one, it will blithely ignore changes in daylight saving. So, when, in my case, we move from the optimistically named British Summer Time ( BST) back to GMT, the job will run an hour later than before.</p>
<p>If we&#8217;re going to get the job to run at the correct time, we need to be explicit.<br />
Just in case you&#8217;ve been typing along whilst reading this post and are now busy cursing me as you&#8217;ll have to go back and drop and re-create any jobs you&#8217;ve already set up, this script should set things right :</p>
<p><pre class="brush: sql; wrap-lines: false;">

set serveroutput on
DECLARE
    CURSOR c_jobs IS
        SELECT job_name, start_date
        FROM dba_scheduler_jobs
        WHERE owner = USER;
BEGIN
    FOR r_jobs IN c_jobs LOOP
        DBMS_SCHEDULER.SET_ATTRIBUTE(
            name =&gt; r_jobs.job_name,
            attribute =&gt; 'start_date',
            value =&gt; TO_TIMESTAMP_TZ(
                TO_CHAR(r_jobs.start_date, 'DDMMRR HH24:MI:SS')
                    ||'EUROPE/LONDON', 'DDMMRR HH24:MI:SS TZR'));
        DBMS_OUTPUT.PUT_LINE('Job '||r_jobs.job_name||' altered.');
    END LOOP;
END;
/
</pre></p>
<p>After running this script, if we re-run the same query we get&#8230;<br />
<pre class="brush: sql; highlight: [8];">
SQL&gt; select TO_CHAR(start_date, 'DD-MON-RR HH24:MI:SS TZR')
  2  FROM dba_scheduler_jobs
  3  WHERE job_name = 'SUNDAY_AM'
  4  /

TO_CHAR(START_DATE,'DD-MON-RRHH24:MI:SSTZR')
--------------------------------------------------------------------------------
10-NOV-11 20:22:55 EUROPE/LONDON

</pre></p>
<h3>Help, my database is spamming me</h3>
<p>So, you have your scheduled jobs running happily in the database. You probably have a few sending e-mails to you as the DBA to let you know all is well, or if there is a problem.<br />
What happens when you refresh your test database with a copy of Live ?</p>
<p>Yep, as soon as you open the instance, the scheduler checks to see if any jobs should have run. If    the current system time is later than the next_run_time, then they&#8217;ll kick off immediately. Even if the first thing you do after opening the database is to disable these jobs, your inbox is still going to be flooded with spam.</p>
<p>In the good old days of dbms_job, you could avoid this simply by setting the job_queue_processes parameter to 0. This solution has now finally found it&#8217;s way into 11gR2 as well. However, if you&#8217;re currently stuck somewhere between 10g and 11gR1 then you&#8217;ll need an alternative.<br />
The workaround below is a quick n dirty version of <a href="http://www.morganslibrary.com/hci/hci012.html">this infinitely more elegant solution proposed by Dan Morgan</a>.</p>
<h4>Getting classy</h4>
<p>The first thing we need to do is create a service. For our specific purposes, you can think of a service as&#8230;.well&#8230;a thingy.</p>
<p><pre class="brush: sql;">
BEGIN
    DBMS_SERVICE.CREATE_SERVICE( 
        service_name =&gt; 'not_so_fast', 
        network_name =&gt; 'some_random_string');
END;
/
</pre></p>
<p>Next, we create a job class and associate it with the service&#8230;</p>
<p><pre class="brush: sql;">
BEGIN
    DBMS_SCHEDULER.CREATE_JOB_CLASS(
        job_class_name =&gt; 'only_on_live',
        service =&gt; 'not_so_fast');
END;
/
</pre></p>
<p>Finally, we assign our job to the job class</p>
<p><pre class="brush: sql; wrap-lines: false;">
set serveroutput on
DECLARE
    CURSOR c_jobs IS
        SELECT job_name
        FROM dba_scheduler_jobs
        WHERE owner = USER;
BEGIN
    FOR r_jobs IN c_jobs LOOP
        DBMS_SCHEDULER.SET_ATTRIBUTE(
            name =&gt; r_jobs.job_name,
            attribute =&gt; 'job_class',
            value =&gt; 'only_on_live');
        DBMS_OUTPUT.PUT_LINE('Job '||r_jobs.job_name||' added to ONLY_ON_LIVE class.');
    END LOOP;
END;
/
</pre></p>
<p>NOTE – if you subsequently create any jobs that are assigned to a class owned by someone else then you need to GRANT EXECUTE ANY CLASS to the job owner. Otherwise, when you run the job you’ll get :<br />
<pre class="brush: sql;">
ORA-27486: insufficient privileges
ORA-06512: at &quot;SYS.DBMS_ISCHED&quot;, line 2751
ORA-06512: at &quot;SYS.DBMS_SCHEDULER&quot;, line 1794
ORA-06512: at line 2
</pre><br />
This happens even if you’re trying to run the job as sys as sysdba.</p>
<p>In order to enable or disable jobs in a specified class, all we need to do is enable or disable the service with which the class is associated.</p>
<p><pre class="brush: sql; wrap-lines: false;">

BEGIN
    DBMS_SERVICE.START_SERVICE( service_name =&gt; 'not_so_fast');
END;
/
</pre></p>
<p>You can see what services are running on your database by querying v$active_services&#8230;</p>
<p><pre class="brush: sql; highlight: [7];">
SQL&gt; SELECT name
  2  FROM v$active_services 
  3  /

NAME
------------------------------
not_so_fast
XEXDB
XE
SYS$BACKGROUND
SYS$USERS

</pre></p>
<p>If the service is not running, then none of the jobs associated with the class that is, in turn, associated with the service, will run.<br />
So how do we stop the spam ? Dan&#8217;s solution used a simple config file based on the same format as oratab. Mine is a bit more basic, but does have the advantage of meaning that you have one less thing to remember when cloning your database.<br />
Here, we&#8217;re going to use a database startup trigger :</p>
<p><pre class="brush: sql; wrap-lines: false;">
CREATE OR REPLACE TRIGGER start_service_trg
    AFTER STARTUP ON DATABASE 
DECLARE
    lc_live_name CONSTANT v$database.name%TYPE := 'XE';
    l_db_name v$database.name%TYPE;
BEGIN
    SELECT name INTO l_db_name FROM v$database;
    IF l_db_name = lc_live_name THEN
        DBMS_SERVICE.START_SERVICE( service_name =&gt; 'not_so_fast');
    END IF;
END;
/
</pre></p>
<p>Simple really, only start the service if we&#8217;re running on production. When I start a test database (in this case, where the database name is not XE, the trigger will not enable the services ( and therefore the jobs) thus keeping my inbox spam free.<br />
Regular readers may be wondering how I got through this entire explanation without any Monty Python references.</p>
<h3>Take it easy, I&#8217;m just recovering</h3>
<p>What about those times when you&#8217;re bringing the production database back up after some unforeseen downtime. The last thing you want is a load of potentially long-running jobs to kick off and hog all of the available database resources.<br />
If you haven&#8217;t used the Services method above, you&#8217;re going to have to find an alternative solution&#8230;</p>
<p><pre class="brush: sql;">
STARTUP NOMOUNT
ALTER SYSTEM ENABLE RESTRICTED SESSION;
</pre></p>
<p>Once you open the database, restricted session is still enabled and the jobs don&#8217;t run.<br />
You can then disable them at your leisure before&#8230;</p>
<p><pre class="brush: sql;">
ALTER SYSTEM DISABLE RESTRICTED SESSION;
</pre></p>
<p>Once you open the database, restricted session is still enabled and the jobs don&#8217;t run.<br />
You can then disable them at your leisure before&#8230;</p>
<p><pre class="brush: plain;">
ALTER SYSTEM DISABLE RESTRICTED SESSION;
</pre></p>
<p>Deb has been sulking most of the way through this post. In fact, she&#8217;s not been entirely happy ever since the French knocked out Wales in the Semis. Oh well, only another 4 years till the next World Cup. I mean, how long can a sulk last ?</p>
<br />Filed under: <a href='http://mikesmithers.wordpress.com/category/oracle/'>Oracle</a>, <a href='http://mikesmithers.wordpress.com/category/oradbpedia-syndication/'>OraDBPedia Syndication</a>, <a href='http://mikesmithers.wordpress.com/category/plsql/'>PL/SQL</a>, <a href='http://mikesmithers.wordpress.com/category/sql/'>SQL</a> Tagged: <a href='http://mikesmithers.wordpress.com/tag/after-startup-on-database-trigger/'>after startup on database trigger</a>, <a href='http://mikesmithers.wordpress.com/tag/alter-system-enable-restricted-session/'>alter system enable restricted session</a>, <a href='http://mikesmithers.wordpress.com/tag/create_job/'>create_job</a>, <a href='http://mikesmithers.wordpress.com/tag/create_job_class/'>create_job_class</a>, <a href='http://mikesmithers.wordpress.com/tag/create_service/'>create_service</a>, <a href='http://mikesmithers.wordpress.com/tag/dbms_scheduler/'>dbms_scheduler</a>, <a href='http://mikesmithers.wordpress.com/tag/dbms_scheduler-daylight-saving/'>dbms_scheduler daylight saving</a>, <a href='http://mikesmithers.wordpress.com/tag/dbms_service/'>dbms_service</a>, <a href='http://mikesmithers.wordpress.com/tag/job_queue_processes/'>job_queue_processes</a>, <a href='http://mikesmithers.wordpress.com/tag/ora-27486/'>ORA-27486</a>, <a href='http://mikesmithers.wordpress.com/tag/run_job/'>run_job</a>, <a href='http://mikesmithers.wordpress.com/tag/start_service/'>start_service</a>, <a href='http://mikesmithers.wordpress.com/tag/systimestamp/'>systimestamp</a>, <a href='http://mikesmithers.wordpress.com/tag/vactive_services/'>v$active_services</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mikesmithers.wordpress.com/1168/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mikesmithers.wordpress.com/1168/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mikesmithers.wordpress.com/1168/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mikesmithers.wordpress.com/1168/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mikesmithers.wordpress.com/1168/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mikesmithers.wordpress.com/1168/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mikesmithers.wordpress.com/1168/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mikesmithers.wordpress.com/1168/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mikesmithers.wordpress.com/1168/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mikesmithers.wordpress.com/1168/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mikesmithers.wordpress.com/1168/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mikesmithers.wordpress.com/1168/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mikesmithers.wordpress.com/1168/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mikesmithers.wordpress.com/1168/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1168&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mikesmithers.wordpress.com/2011/11/10/help-dbms_scheduler-keeps-spamming-me-and-cant-tell-the-time-either/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e3cb0956016bbad280193fbbd8e649b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">Mike S</media:title>
		</media:content>
	</item>
		<item>
		<title>Oracle SQL and PL/SQL Coding Standards – Cat Herding for Dummies</title>
		<link>http://mikesmithers.wordpress.com/2011/10/22/oracle-sql-and-plsql-coding-standards-%e2%80%93-cat-herding-for-dummies/</link>
		<comments>http://mikesmithers.wordpress.com/2011/10/22/oracle-sql-and-plsql-coding-standards-%e2%80%93-cat-herding-for-dummies/#comments</comments>
		<pubDate>Sat, 22 Oct 2011 11:54:55 +0000</pubDate>
		<dc:creator>mikesmithers</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[OraDBPedia Syndication]]></category>
		<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[COMMENT ON COLUMN]]></category>
		<category><![CDATA[CREATE OR REPLACE TRIGGER]]></category>
		<category><![CDATA[DBMS_OUTPUT.PUT_LINE]]></category>
		<category><![CDATA[implicit cursor]]></category>
		<category><![CDATA[PL/SQL Coding Standards]]></category>
		<category><![CDATA[TOO_MANY_ROWS]]></category>

		<guid isPermaLink="false">http://mikesmithers.wordpress.com/?p=1147</guid>
		<description><![CDATA[Whilst in Montreal recently, Deb and I made a pilgrimage to the Circuit Giles Villeneuve, home of the Canadian Grand Prix. When not in use, the track is open to the public. It&#8217;s divided into two lanes &#8211; one for people to walk and cycle down down, and a one for people to drive down. [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1147&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Whilst in Montreal recently, Deb and I made a pilgrimage to the Circuit Giles Villeneuve, home of the Canadian Grand Prix. When not in use, the track is open to the public. It&#8217;s divided into two lanes &#8211; one for people to walk and cycle down down, and a one for people to drive down.<br />
You can just imagine flying round in an F1 car. You come out of the excruciatingly slow L&#8217;epingle hairpin and build up to top speed as you tear down the Casino Straight. Ahead lies the final chicane before the start/finish line. A tricky right left combination with the treacherous curb on the inside of the last turn ready to spit the unwary into the Wall of Champions on the opposite side of the track.<br />
At over 300 kph you start to think about spotting your braking point. Suddenly, this comes into view&#8230;.</p>
<div id="attachment_1148" class="wp-caption alignnone" style="width: 460px"><a href="http://mikesmithers.files.wordpress.com/2011/10/speed_limit.png"><img src="http://mikesmithers.files.wordpress.com/2011/10/speed_limit.png?w=450&#038;h=337" alt="" title="speed_limit" width="450" height="337" class="size-full wp-image-1148" /></a><p class="wp-caption-text">What do you think this is, a race track ?</p></div>
<p>&#8230; and now you know what it&#8217;s like to be a programmer, who has channeled raw inspiration through his or her dancing fingers to produce a thing of beauty and elegance&#8230;only to run into the QA person pointing out that the  commas are in the wrong place according to page 823, paragraph 2 sub-section e of The Coding Standards.</p>
<p>Often measured in weight rather than the number of pages, Coding Standards documents are often outdated, arbitrary and just plain wrong.<br />
On the other hand, their absence can cause much heartache, not least to those poor souls in support who are trying to maintain code where the Agilista philosophy of Code over Documentation has been taken to the ultimate extreme.</p>
<p>What follows is an attempt to make sense of the Coding Standards conundrum.<br />
I&#8217;ll look at what I think a Coding Standards document should contain, and what it shouldn&#8217;t.<br />
Then I&#8217;ll give some suggestions as to standards for Oracle SQL and PL/SQL which you can either embrace or throw rocks at, depending on your preference.<br />
Before all of that however, I feel the need for some serious catharsis&#8230; <span id="more-1147"></span></p>
<h3>Wacky Coding Standards</h3>
<p>What follows is a select list of standards that I&#8217;ve been required to work with at various places. Some of them are out of date, some just plain arbitrary. Others are what happens when you take the word of “experts” without checking it out for yourself. As you can imagine, this particular section has required quite a bit of restraint on my part.</p>
<h4>The ever-changing alias</h4>
<p>“When joining two or more tables in a SQL query, the first table must have an alias of &#8216;a&#8217;, the second &#8216;b&#8217;, and so forth.”</p>
<p>So, if we use the HR schema as an example, the following would fall foul of the standards&#8230;</p>
<p><pre class="brush: sql;">
SELECT emp.first_name, emp.last_name
FROM employees emp, departments dept
WHERE emp.department_id = dept.department_id
AND dept.department_id = 60
/
</pre></p>
<p>What we must do to conform to this stricture is :</p>
<p><pre class="brush: sql; highlight: [2];">
SELECT a.first_name, a.last_name
FROM employees a, departments b
WHERE a.department_id = b.department_id
AND b.department_id = 60
/
</pre></p>
<p>You can just imagine how exciting it is when a table alias can be any arbitrary letter from a to z and it&#8217;s different in every query.</p>
<h4>Implicit Cursors are bad, mkay?</h4>
<p>“Thou shalt not use an implicit cursor!&#8221;</p>
<p>This one was quite popular for quite a long time. This was almost entirely based on the opinion of the great and the good of PL/SQL programming ( you know who you are).<br />
It&#8217;s surprising how few people actually thought about this in any depth.<br />
The premise behind this prohibition was that an implicit cursor always executes an extra fetch after retrieving the first row. This extra fetch, the argument went, was inefficient. Using an explicit cursor would result in only one fetch.</p>
<p>What happens when an implicit cursor finds a row when performing that second fetch ? You get a TOO_MANY_ROWS error. If you&#8217;re using an implicit cursor, it can be reasonably assumed that you want to fetch one, and only one, row. If there&#8217;s more than one row being returned, you probably want to know about it.</p>
<p>To be fair to the experts in question, one of the main health-warnings they issue is “don&#8217;t take my word for it”. </p>
<h4>Look Mum, less typing</h4>
<p>This standard was born out of the ban on implicit cursors.<br />
“When fetching a single row from an explicit cursor,  use a FOR LOOP to reduce the amount of code written&#8230;”</p>
<p><pre class="brush: sql; highlight: [8,9,10,11];">
CURSOR c_deptno IS 
    SELECT department_id 
    FROM departments 
    WHERE department_name = 'IT'; 

BEGIN 
    ... 
    FOR r_deptno IN c_deptno LOOP 
	    l_deptno := r_deptno.department_id; 
	    EXIT; 
    END LOOP; 
    ... 
</pre></p>
<p>None of that OPEN FETCH CLOSE malarkey, oh no. For us it was the simple and oh so easy to read construct you see above.<br />
Of course, those unfamiliar with our coding standards often did a double-take when they saw this sort of thing, but they soon got used to it. After all, less typing = less work, right ? I mean, what could possibly go wrong ? Um&#8230;</p>
<h4> It&#8217;s C Jim, but not as we know it</h4>
<p>This last one isn&#8217;t an Oracle example, it comes from a C coding standards document.</p>
<p>“When incrementing a variable by 1, don&#8217;t use the ++ operator. Instead use var = var + 1 as this is more readable”.</p>
<p>The author of this particular gem was later cornered by the entire Development Team and forced to read aloud, extracts from “The C Programming Language” by Kernighan and Ritchie.</p>
<p>I&#8217;m sure that anyone who has been programming professionally for any length of time will have their own list of favourites. But how does this help move the discussion on ?<br />
Sure, it gives us some insight into the problems with Standards, but how are we going to solve them ?</p>
<p>This brings us on to the “ideal” Coding Standards document, or at least, my ideal Coding Standards document.<br />
At this point, you may well wonder what right I have to lay down the Coding Standards ? The only answer I can think of is that I&#8217;m the egomaniac at the keyboard right now. So there.</p>
<p>To my mind, Coding Standards need to be  :-</p>
<ul>
<li>concise</li>
<li>concerned exclusively with Standards, not Best Practice</li>
<li>concerned with a single language or language family (e.g. SQL and PL/SQL)</li>
</ul>
<h3>The Secret is in the Scope</h3>
<p>The first thing to do is to put the Standards Document on a diet.</p>
<p>Best Practices change between releases. They are not standards, to my mind.<br />
Do you remember when you used SELECT COUNT(rowid) instead of SELECT COUNT(*) ?<br />
Back in Oracle 7, the former was more efficient. However, since Oracle 8, the latter statement now works in exactly the same way. </p>
<p>Best Practices belong in a version-specific Best Practices document. Standards should be rather more immutable.</p>
<p>Rather than being buried in a comprehensive Coding Standards document for all of the technologies being used on site, each language or language-family, should have it&#8217;s own document.</p>
<p>I have a feeling that my final point on our Standards Diet may be a touch controversial&#8230; Standards do not have to specify code layout in any detail&#8230;</p>
<h3>Code Layout Standards</h3>
<p>There always seems to be reams written about how to indent and align code, not to mention the old favourite of where to put your commas.<br />
There are historical reasons for this.<br />
Once upon a time, Oracle would determine whether a statement was cached by doing a straight character-by-character comparison. Consistent use of whitespace was therefore important.<br />
Since around 9i, it takes a slightly different approach.<br />
All non-literals in the statement are converted to lowercase and whitespace is stripped prior to the comparison.</p>
<p>Therefore, I&#8217;d contend that all you need to say in the Standards is that code should be indented consistently and be readable.<br />
Provided peer reviews are a feature of your development process, this should be more than enough to ensure that the code that goes forward to production is fit for purpose in terms of maintainability. This is, after all, the primary purpose of Coding Standards.</p>
<p>If you really are an obsessive/compulsive, you can always make use of whichever IDE happens to be in favour and stipulate that code should be run through it&#8217;s formatter prior to check in. Yes, all of them can be configured so you can get your commas wherever you want them.</p>
<h3>SQL and PL/SQL Coding Standards</h3>
<p>If you&#8217;ve read this blog for any length of time, you&#8217;ll have noticed that my coding standards have evolved over time. One of the advantages of being my own QA department is that I can adopt/change/drop standards as I come across better ways of doing stuff.</p>
<p>PL/SQL is essentially, ADA with SQL extensions. As so much of PL/SQL relies on SQL, it makes sense to combine the standards for both in one place, at least, if you&#8217;re exclusively an Oracle shop.</p>
<p>The standards themselves should begin with a disclaimer along the lines of :</p>
<p>“These standards should be adhered to, unless there is a sensible reason to deviate from them.”</p>
<p>This get-out clause should mean that we won&#8217;t get lumbered with following a rule which is no longer sensible/ was wrong to start with.<br />
One example that springs to mind&#8230;it would seem sensible to have a standard stipulating that all calls to stored program units from within PL/SQL should be by reference, right ?<br />
Sounds like a great idea&#8230;until you get to DBMS_OUTPUT.PUT_LINE, for example.<br />
Do you really want to be lumbered with …</p>
<p><pre class="brush: sql;">
DBMS_OUTPUT.PUT_LINE( a =&gt; 'Some line to output');
</pre></p>
<p>What now follows are the standards I use because I&#8217;m comfortable with them and it&#8217;s what I&#8217;m used to. There&#8217;s no reason to believe that you&#8217;ll be struck by lightning if, for example, you put your SQL keywords in lowercase.<br />
Anyway, rocks at the ready&#8230;</p>
<h4>Object naming</h4>
<p>In general terms, I prefer the use of suffixes rather than prefixes. This is mainly because my heart sinks every time I look at a list of, say triggers, in an IDE and find that they all start with TRG_.<br />
By using a suffix, you&#8217;ll still be able to easily identify the different object types and have a nice usable alphabetical listing.</p>
<p>Another point to note – object names are stored in uppercase in the data dictionary. Therefore, separating words in object names is best done with underscores ( e.g. order_items).<br />
Using Camel Case is problematic in this context as the word boundaries will be lost in the data dictionary ( e.g. OrderItems will be stored as ORDERITEMS).</p>
<p><strong>Tables</strong></p>
<p>Table names should be meaningful. They should also be plural, unless you&#8217;re creating a table to hold only a single row.<br />
EMPLOYEES ( because we&#8217;ve got rows for more than one) rather than EMPLOYEE or EMP.<br />
Generally speaking, we don&#8217;t need a suffix for tables. The exceptions are :<br />
Global Temporary Tables should have a suffix of GTT<br />
Permanent segments used to hold temporary data should have a suffix of TMP.<br />
Comments should be added for all columns in a table.<br />
The comment should specify :</p>
<ul>
<li>Whether the column is part of a Primary or Foreign Key.</li>
<li>If it is part of a Foreign Key, what the parent table/column is.</li>
<li>If it is a Synthetic Key generated from a sequence, the name of the sequence.</li>
<li>If there is a check constraint a <em>description</em> of the allowable values rather than just the values themselves.</li>
</ul>
<p>Primary Key, Foreign Key and Check constraints should be named with appropriate table aliases :</p>
<ul>
<li>Primary Key – alias_pk</li>
<li>Foreign Key – child alias_parent alias_fk</li>
<li>Check constraint alias_column_name_ck</li>
</ul>
<p>Where an index is created to support a Foreign Key relationship, it&#8217;s named after the Foreign Key constraint with a _IDX suffix. Otherwise, it should start with the alias of the table and end with _IDX. What you put in the middle is more or less up to you.</p>
<p>As an example :</p>
<p><pre class="brush: sql;">
CREATE TABLE contracts ( 
    contract_id NUMBER CONSTRAINT con_pk PRIMARY KEY, 
    client_id NUMBER CONSTRAINT con_cli_fk REFERENCES clients(id), 
    status_ind VARCHAR2(1) CONSTRAINT con_status_ck 
        CHECK (status_ind IN ('L', 'D', 'F')) 
) 
/ 


CREATE INDEX con_cli_fk_idx ON contracts( client_id) 
/ 

COMMENT ON COLUMN contracts.contract_id IS 
    'Synthetic Key, populated from sequence CON_ID_SEQ' 
/ 

COMMENT ON COLUMN contracts.client_id IS 
    'FK to clients.id' 
/ 

COMMENT ON COLUMN contracts.status_ind IS 
    'Valid values are L(ive), D(ead) and F(rozen)' 
/ 
</pre></p>
<p><strong>Stored Program Units</strong></p>
<p>As Oracle supplied packages are essentially extensions to the PL/SQL language, it makes sense to treat them in the same way as the core language keywords. In my case, I put SQL and PL/SQL keywords in uppercase.</p>
<p>I use the following suffixes :</p>
<ul>
<li>function &#8211; _fn</li>
<li>materialized_view _mv</li>
<li>package &#8211; _pkg</li>
<li>procedure _pr</li>
<li>sequence &#8211; seq</li>
<li>trigger _trg</li>
<li>view _vw</li>
</ul>
<p>For SQL statements, each clause begins on a new line unless the entire statement can fit comfortably onto one line ( I use a limit of 80 characters as a rule of thumb on this one).</p>
<p>For PL/SQL, indentation must be consistent throughout the program.</p>
<p><strong>Triggers</strong></p>
<p>The naming convention I use for DML Triggers is  :<br />
<em>table alias</em>_<em>firing timing</em>_<em>DML action(s)</em>_<em>level</em> ( if statement)<em>_trg</em>.</p>
<p>The firing timing is either B(efore) or A(fter).<br />
The DML actions are I(nsert), U(pdate) or D(elete)<br />
Most DML triggers tend to be row-level. If I have a statement Level then I&#8217;ll use S.</p>
<p>Lets say we have a table to contain the names and teams of F1 drivers. For reasons best known to the Application Designer, the synthetic key on this table needs to increment by 1 each time a record is added, with no gaps. Yes, I know that without using a sequence we could get the same id being used twice if the latest record in the table is deleted and then another record inserted. Look, this is just something I knocked together to illustrate the trigger naming thing. I&#8217;m not really trying to hammer home the point that standards and best practice don&#8217;t mix.<br />
Anyhow, say the table looks something like this :</p>
<p><pre class="brush: sql;">
SQL&gt; desc drivers 
 Name					   Null?    Type 
 ----------------------------------------- -------- ---------------------------- 
 ID					   NOT NULL NUMBER 
 FIRST_NAME				   NOT NULL VARCHAR2(100) 
 LAST_NAME				   NOT NULL VARCHAR2(100) 
 TEAM					   NOT NULL VARCHAR2(100) 
 CREATED_BY				   NOT NULL VARCHAR2(30) 
 CREATION_DATE				   NOT NULL DATE 
 MODIFIED_BY					    VARCHAR2(30) 
 MODIFIED_DATE					    DATE 

SQL&gt; 
</pre></p>
<p>Oh look, complete with old-style auditing columns. I wonder what we&#8217;d need a trigger for&#8230;</p>
<p><pre class="brush: sql; highlight: [1];">
CREATE OR REPLACE TRIGGER drv_biu_trg 
    BEFORE INSERT OR UPDATE on drivers 
    FOR EACH ROW 
DECLARE 
    l_next_id drivers.id%TYPE; 
BEGIN 
    IF INSERTING THEN 
        SELECT NVL( MAX( id), 0) + 1 INTO l_next_id FROM drivers; 
        :new.id := l_next_id; 
        :new.created_by := USER; 
        :new.creation_date := SYSDATE; 
    ELSIF UPDATING THEN 
        :new.modified_by := USER; 
        :new.modified_date := SYSDATE; 
    END IF; 
END; 
/
</pre></p>
<p>There you go – the trigger name is the table alias followed by the timing ( BEFORE in this case), followed by the DML actions the trigger fires on (Insert, Update) and the appropriate suffix.<br />
You&#8217;ll also notice that the code is (a) beautifully formatted and (b) not worth reading.</p>
<h4>Variables</h4>
<p>Variables should have <a href="http://wp.me/pweWl-il">anchored declarations</a> where they are :</p>
<ul>
<li>always assigned a value directly from a database column</li>
<li>is used in a query predicate as a comparison against a database column</li>
<li>is used in a DML statement to assign a value to a database column</li>
</ul>
<p><strong>NOTE</strong> – I&#8217;ve deliberately not gone into details about scalar declarations because they tend to be version specific. For example, it may be more efficient to use BINARY_INTEGER, PLS_INTEGER or NATURAL_INTEGER depending on which database version you&#8217;re running.<br />
Of course, by the time Oracle 12 comes out, it&#8217;s entirely possible that they&#8217;ll all be synonyms for the same thing. In 10g PLS_INTEGER and BINARY_INTEGER already are.</p>
<p><strong>Variable Names</strong></p>
<p>I use the following prefixes should for variable names :</p>
<ul>
<li>local variable – l_</li>
<li>Global variable – g_</li>
<li>Constant – gc_ for a global constant, </li>
<li>local constant &#8211; lc_</li>
<li>Type – typ_</li>
<li>record – rec_</li>
<li>Table of records – tbl_</li>
<li>cursor &#8211; c_</li>
<li>ref cursor – rc_</li>
</ul>
<p>Parameters are prefixed as follows </p>
<ul>
<li>In parameter – i_</li>
<li>Out parameter o_</li>
<li>In/Out parameter – io_</li>
</ul>
<p><strong> Comments</strong></p>
<p>To my mind, comments, when taken with the code, should allow you to work out what is going on.<br />
A header comment should be included to explain the program&#8217;s purpose and, if it&#8217;s quite involved, to give a brief overview of the functionality it implements.</p>
<h3>What does all this have to do with Cats ?</h3>
<p>Yes, trying to control a bunch of computer programmers is like trying to herd cats.<br />
My take on this is, if at first you don&#8217;t succeed&#8230;don&#8217;t bother.<br />
By providing a simple concise framework for standards and then allowing code readability to be policed by means of peer review, everyone benefits from a degree of coding consistency from easy to follow rules.<br />
The rules themselves do not get in the way of the actual process of writing code.<br />
Of course, it may well mean that your Peer Review sessions get quite a bit more interesting but hey, we all need a bit of excitement now and then. Just stand back and let the fur fly !<br />
In the meantime, I&#8217;m off to take cover from all those rocks that suddenly seem to be flying in my direction.</p>
<br />Filed under: <a href='http://mikesmithers.wordpress.com/category/oracle/'>Oracle</a>, <a href='http://mikesmithers.wordpress.com/category/oradbpedia-syndication/'>OraDBPedia Syndication</a>, <a href='http://mikesmithers.wordpress.com/category/plsql/'>PL/SQL</a>, <a href='http://mikesmithers.wordpress.com/category/sql/'>SQL</a> Tagged: <a href='http://mikesmithers.wordpress.com/tag/comment-on-column/'>COMMENT ON COLUMN</a>, <a href='http://mikesmithers.wordpress.com/tag/create-or-replace-trigger/'>CREATE OR REPLACE TRIGGER</a>, <a href='http://mikesmithers.wordpress.com/tag/dbms_output-put_line/'>DBMS_OUTPUT.PUT_LINE</a>, <a href='http://mikesmithers.wordpress.com/tag/implicit-cursor/'>implicit cursor</a>, <a href='http://mikesmithers.wordpress.com/tag/plsql-coding-standards/'>PL/SQL Coding Standards</a>, <a href='http://mikesmithers.wordpress.com/tag/too_many_rows/'>TOO_MANY_ROWS</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mikesmithers.wordpress.com/1147/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mikesmithers.wordpress.com/1147/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mikesmithers.wordpress.com/1147/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mikesmithers.wordpress.com/1147/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mikesmithers.wordpress.com/1147/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mikesmithers.wordpress.com/1147/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mikesmithers.wordpress.com/1147/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mikesmithers.wordpress.com/1147/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mikesmithers.wordpress.com/1147/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mikesmithers.wordpress.com/1147/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mikesmithers.wordpress.com/1147/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mikesmithers.wordpress.com/1147/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mikesmithers.wordpress.com/1147/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mikesmithers.wordpress.com/1147/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1147&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mikesmithers.wordpress.com/2011/10/22/oracle-sql-and-plsql-coding-standards-%e2%80%93-cat-herding-for-dummies/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e3cb0956016bbad280193fbbd8e649b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">Mike S</media:title>
		</media:content>

		<media:content url="http://mikesmithers.files.wordpress.com/2011/10/speed_limit.png" medium="image">
			<media:title type="html">speed_limit</media:title>
		</media:content>
	</item>
		<item>
		<title>Anchored Declarations and the Brownie Point Economy</title>
		<link>http://mikesmithers.wordpress.com/2011/10/03/anchored-declarations-and-the-brownie-point-economy/</link>
		<comments>http://mikesmithers.wordpress.com/2011/10/03/anchored-declarations-and-the-brownie-point-economy/#comments</comments>
		<pubDate>Mon, 03 Oct 2011 17:52:18 +0000</pubDate>
		<dc:creator>mikesmithers</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[OraDBPedia Syndication]]></category>
		<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[%ROWTYPE]]></category>
		<category><![CDATA[%TYPE]]></category>
		<category><![CDATA[anchored declarations]]></category>
		<category><![CDATA[ORA-6502]]></category>
		<category><![CDATA[PL/SQL: numeric or value error: character string buffer too small]]></category>

		<guid isPermaLink="false">http://mikesmithers.wordpress.com/?p=1137</guid>
		<description><![CDATA[This week&#8217;s hot conversational topic in the Nut and Squirrel was the Global Economic Crisis, with particular reference to a little-reported side-effect that has huge ramifications. I am, of course, referring to the devaluation of Brownie Points. Unless you&#8217;re English, I guess some explanation may be called for at this point. So, at the risk [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1137&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>This week&#8217;s hot conversational topic in the Nut and Squirrel was the Global Economic Crisis, with particular reference to a little-reported side-effect that has huge ramifications. I am, of course, referring to the devaluation of Brownie Points.</p>
<p>Unless you&#8217;re English, I guess some explanation may be called for at this point. So, at the risk of getting all anthropological&#8230;<br />
Brownie Points are awarded by females to their mate for certain actions. When enough brownie points have been accrued, the male of the species can have these converted into a Pass.</p>
<p>The Pass can be used for a night out with the lads, at the footie, or whatever other pursuit is of interest.</p>
<p>This system is instinctively understood by females, although, due to the sudden and unexpected fluctuations in value, less so by the males.</p>
<p>You will often hear conversations such as :</p>
<p>“We&#8217;re going to Luton Saturday, their playing Mansfield, you reckon you can get a pass ?”<br />
“Sorry, we&#8217;re at the Garden Centre on Saturday, need to earn some brownie points.”</p>
<p>This system goes under many different guises but is essentially the same the world over.<br />
Lately however, it has become apparent that males are having to work harder for their brownie points than previously. The suspicion is that this is related to the retail price of women&#8217;s shoes.</p>
<p>What a mess. Where can you put your hard earned savings to ensure an index-linked return ?<br />
Well, if you really want to know, you&#8217;ll have to read the Financial Times. Variables in PL/SQL, however, can be indexed-linked to database columns by the simple expedient of an anchored declaration. <span id="more-1137"></span></p>
<h3>Your Flexible Friend</h3>
<p>Imagine we had to keep track of the brownie point values in Oracle. Let&#8217;s start with a table :</p>
<p><pre class="brush: sql;">
CREATE TABLE brownie_points( 
    activity VARCHAR2(20), 
    points  NUMBER(3)) 
/
</pre></p>
<p>You may also have a bit of code knocking around somewhere to display all of the activities for which you can gain points :</p>
<p><pre class="brush: sql; highlight: [3];">
set serveroutput on 
DECLARE 
    l_activity VARCHAR2(20); 

    CURSOR c_activities IS 
        SELECT activity 
        FROM brownie_points 
        WHERE points &gt; 0; 
BEGIN 
    FOR r_activities IN c_activities LOOP 
        -- 
        -- Slightly contrived for the purposes of this example 
        -- 
        l_activity := r_activities.activity; 
        DBMS_OUTPUT.PUT_LINE( l_activity); 
    END LOOP; 
END; 
/ 
</pre></p>
<p>Notice anything amiss with the l_activity variable ? Well, it&#8217;s declared as a VARCHAR2(20) same as the column from which we&#8217;ll be selecting data into it. No problem so far.<br />
But what happens if, to take a completely random example, your better-half decides to get involved. Yes, Deb decided that 20 characters just isn&#8217;t long-enough to describe the various activities for which points may be awarded. As a result we have to amend the table as follows :</p>
<p><pre class="brush: sql;">
ALTER TABLE brownie_points MODIFY activity VARCHAR2(30)
/
</pre></p>
<p>Oh, and our new Business Analyst has had some input on the data we need to hold in this table&#8230;</p>
<p><pre class="brush: sql;">
INSERT INTO brownie_points( 
    activity, points)
VALUES(
    'Flowers ( all-night garage)', 2);

INSERT INTO brownie_points( 
    activity, points)
VALUES(
    'Flowers ( from florist)', 15);

INSERT INTO brownie_points( 
    activity, points)
VALUES(
    'Flowers( delivered)', 50);

INSERT INTO brownie_points( 
    activity, points)
VALUES(
    'Flowers( delivered to work)', 250);

INSERT INTO brownie_points( 
    activity, points)
VALUES(
    'Dinner( take away)', 5);

INSERT INTO brownie_points( 
    activity, points)
VALUES(
    'Dinner( restaurant)', 25);
    
INSERT INTO brownie_points( 
    activity, points)
VALUES(
    'Leaving the loo seat up', -10);
    
INSERT INTO brownie_points( 
    activity, points)
VALUES(
    'Late home from pub', -15);
</pre></p>
<p>The upshot of all of this is that when we next run our code, we get a nasty surprise&#8230;</p>
<p><pre class="brush: plain; light: true;">

ERROR at line 1: 
ORA-06502: PL/SQL: numeric or value error: character string buffer too small 
ORA-06512: at line 13 

</pre></p>
<p>If only I hadn&#8217;t acted like a rogue trader and tried to shave a bit off the typing, this problem would never have occurred. If only I&#8217;d used an anchored declaration&#8230;</p>
<p><pre class="brush: sql; highlight: [3];">
set serveroutput on 
DECLARE 
    l_activity brownie_points.activity%TYPE;

    CURSOR c_activities IS 
        SELECT activity 
        FROM brownie_points 
        WHERE points &gt; 0; 
BEGIN 
    FOR r_activities IN c_activities LOOP 
        -- 
        -- Slightly contrived for the purposes of this example 
        -- 
        l_activity := r_activities.activity; 
        DBMS_OUTPUT.PUT_LINE( l_activity); 
    END LOOP; 
END; 
/

</pre></p>
<p>Running this, we&#8217;d get :</p>
<p><pre class="brush: plain; light: true;">
Flowers ( all-night garage) 
Flowers ( from florist) 
Flowers( delivered) 
Flowers( delivered to work) 
Dinner( take away) 
Dinner( restaurant) 
</pre></p>
<h3> Stored Program Parameters</h3>
<p>You can also use anchored declarations for parameters in Stored Program Units.<br />
Say we had a procedure to add records to the table&#8230;</p>
<p><pre class="brush: sql; highlight: [2,3];">
CREATE OR REPLACE PROCEDURE add_activity_pr (
    i_activity brownie_points.activity%TYPE,
    i_points brownie_points.points%TYPE) IS

BEGIN
    INSERT INTO brownie_points(
        activity, points)
    VALUES( i_activity, i_points);
END;
/
</pre></p>
<p>Not only do we have a procedure that will never be susceptible to changes to the columns on which it relies, we also have what is, essentially, self-documenting code.<br />
The extra typing you have to do to define the parameters is offset by the reduction in the amount of typing you need to do for the comments.</p>
<h3>A bit less typing</h3>
<p>You can also use anchored declarations to save you typing. Let&#8217;s say you wanted to pull out all the stops&#8230;</p>
<p><pre class="brush: sql; highlight: [3]; wrap-lines: false;">
set serveroutput on 
DECLARE 
    rec_activity brownie_points%ROWTYPE; 

    CURSOR c_activities IS 
        SELECT activity, points 
        FROM brownie_points bp 
        WHERE points = (SELECT MAX(bp1.points) FROM brownie_points bp1); 
BEGIN 
    OPEN c_activities; 
    FETCH c_activities INTO rec_activity; 
    CLOSE c_activities; 
    DBMS_OUTPUT.PUT_LINE('If you want a Pass then '||rec_activity.activity||' is worth '||rec_activity.points||' points.'); 
END; 
/ 
</pre></p>
<p>Save this as all_stops.sql and …</p>
<p><pre class="brush: plain; light: true;">
SQL&gt; @all_stops.sql 
If you want a pass then Flowers( delivered to work) is worth 250 points. 

PL/SQL procedure successfully completed. 

SQL&gt;
</pre></p>
<p>Look at that. Instead of declaring two variables, we just need to declare one as %ROWTYPE for the table. Of course, we could go further. If we just want a cursor specifically to hold the values returned by the cursor, we can use the cursor itself for the basis of the variable declaration&#8230;</p>
<p><pre class="brush: sql; highlight: [11]; wrap-lines: false;">
set serveroutput on 
DECLARE 
    CURSOR c_activities IS 
        SELECT activity, 
            CASE 
                WHEN points &lt; 0 THEN 'Not a good idea' 
                ELSE 'This could work' 
            END as advice
        FROM brownie_points bp;

    rec_activity c_activities%ROWTYPE;          

BEGIN 
    OPEN c_activities;
    FETCH c_activities INTO rec_activity;
    WHILE c_activities%FOUND LOOP
        DBMS_OUTPUT.PUT_LINE( rec_activity.activity||' - '||rec_activity.advice);
        FETCH c_activities INTO rec_activity;
    END LOOP;
    CLOSE c_activities;
END;
/ 
</pre></p>
<p>Running this we get …</p>
<p><pre class="brush: plain; light: true;">
SQL&gt; @advice.sql 
Flowers ( from florist) - This could work 
Flowers( delivered) - This could work 
Flowers( delivered to work) - This could work 
Dinner( take away) - This could work 
Dinner( restaurant) - This could work 
Leaving the loo seat up - Not a good idea 
Late home from pub - Not a good idea 
Flowers ( all-night garage) - This could work  

PL/SQL procedure successfully completed. 

SQL&gt; 
</pre></p>
<p>A word of warning here – if you do want to use this construct, then you need to make sure that you declare the variable after the cursor. Otherwise, you&#8217;ll get something like:</p>
<p><pre class="brush: plain; light: true;">
ERROR at line 2: 
ORA-06550: line 2, column 18: 
PLS-00320: the declaration of the type of this expression is incomplete or 
malformed 
ORA-06550: line 2, column 18: 
PL/SQL: Item ignored 
ORA-06550: line 12, column 33: 
PLS-00320: the declaration of the type of this expression is incomplete or 
malformed 
ORA-06550: line 12, column 9: 
PL/SQL: SQL Statement ignored 
ORA-06550: line 13, column 31: 
PLS-00320: the declaration of the type of this expression is incomplete or 
malformed 
ORA-06550: line 13, column 9: 
PL/SQL: Statement ignored 
</pre></p>
<p>Anchored declarations are incredibly useful. As well as future-proofing, they serve to make code more readable and can even save you typing in the long-run.</p>
<p><strong>NOTE</strong> – Brownie points can go down as well as up. The author accepts no liability for the consequences of acting on any of the relationship advice contained in this blog.</p>
<br />Filed under: <a href='http://mikesmithers.wordpress.com/category/oracle/'>Oracle</a>, <a href='http://mikesmithers.wordpress.com/category/oradbpedia-syndication/'>OraDBPedia Syndication</a>, <a href='http://mikesmithers.wordpress.com/category/plsql/'>PL/SQL</a> Tagged: <a href='http://mikesmithers.wordpress.com/tag/rowtype/'>%ROWTYPE</a>, <a href='http://mikesmithers.wordpress.com/tag/type/'>%TYPE</a>, <a href='http://mikesmithers.wordpress.com/tag/anchored-declarations/'>anchored declarations</a>, <a href='http://mikesmithers.wordpress.com/tag/ora-6502/'>ORA-6502</a>, <a href='http://mikesmithers.wordpress.com/tag/plsql-numeric-or-value-error-character-string-buffer-too-small/'>PL/SQL: numeric or value error: character string buffer too small</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mikesmithers.wordpress.com/1137/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mikesmithers.wordpress.com/1137/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mikesmithers.wordpress.com/1137/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mikesmithers.wordpress.com/1137/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mikesmithers.wordpress.com/1137/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mikesmithers.wordpress.com/1137/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mikesmithers.wordpress.com/1137/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mikesmithers.wordpress.com/1137/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mikesmithers.wordpress.com/1137/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mikesmithers.wordpress.com/1137/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mikesmithers.wordpress.com/1137/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mikesmithers.wordpress.com/1137/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mikesmithers.wordpress.com/1137/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mikesmithers.wordpress.com/1137/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1137&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mikesmithers.wordpress.com/2011/10/03/anchored-declarations-and-the-brownie-point-economy/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e3cb0956016bbad280193fbbd8e649b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">Mike S</media:title>
		</media:content>
	</item>
		<item>
		<title>ROWNUM, Random updates and the Alert Log – A trip down Memory Lane</title>
		<link>http://mikesmithers.wordpress.com/2011/09/19/rownum-random-updates-and-the-alert-log-%e2%80%93-a-trip-down-memory-lane/</link>
		<comments>http://mikesmithers.wordpress.com/2011/09/19/rownum-random-updates-and-the-alert-log-%e2%80%93-a-trip-down-memory-lane/#comments</comments>
		<pubDate>Mon, 19 Sep 2011 19:02:38 +0000</pubDate>
		<dc:creator>mikesmithers</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[OraDBPedia Syndication]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[alert log as an external table]]></category>
		<category><![CDATA[alert.log]]></category>
		<category><![CDATA[dbms_system.ksdwrt]]></category>
		<category><![CDATA[external tables]]></category>
		<category><![CDATA[rownum]]></category>

		<guid isPermaLink="false">http://mikesmithers.wordpress.com/?p=1123</guid>
		<description><![CDATA[I met up with an old friend recently. Deb and I were in Toronto, hometown of a certain Simon Jennings. Apart from being a top bloke, Simon was also my first mentor in the mysterious ways of SQL, a sort of Obi-Wan Kenobi to my Anakin Skywalker, but without the light-sabers. Ah those heady days [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1123&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I met up with an old friend recently. Deb and I were in Toronto, hometown of a certain Simon Jennings.<br />
Apart from being a top bloke, Simon was also my first mentor in the mysterious ways of SQL, a   sort of Obi-Wan Kenobi to my Anakin Skywalker, but without the light-sabers.</p>
<p>Ah those heady days when the world was young&#8230;and I first discovered ROWNUM.<br />
That pseudo column was one I used often when investigating the structure and data within tables. It was also, the source of some confusion.<br />
<span id="more-1123"></span></p>
<p>Let&#8217;s take an example in keeping with Simon&#8217;s adopted home&#8230;</p>
<p><pre class="brush: sql;">
CREATE TABLE hockey_teams( 
    club_id NUMBER, 
    team_name VARCHAR2(50)) 
/ 

INSERT INTO hockey_teams( club_id, team_name) 
VALUES( 1, 'TORONTO MAPLE LEAFS') 
/ 

INSERT INTO hockey_teams( club_id, team_name) 
VALUES( 2, 'MONTREAL CANADIENS') 
/ 

INSERT INTO hockey_teams( club_id, team_name) 
VALUES(3, 'OTTOWA SENATORS') 
/ 

INSERT INTO hockey_teams( club_id, team_name) 
VALUES(4, 'WINNIPEG JETS') 
/ 

INSERT INTO hockey_teams( club_id, team_name) 
VALUES(5, 'CALGARY FLAMES') 
/ 

INSERT INTO hockey_teams( club_id, team_name) 
VALUES(6, 'EDMONTON OILERS') 
/ 

INSERT INTO hockey_teams( club_id, team_name) 
VALUES(7, 'VANCOUVER CANUCKS') 
/
</pre></p>
<p>If I just wanted to have a look at a few rows of the table ( remember, this was in the days before IDEs that return only the first few rows of a query) …</p>
<p><pre class="brush: sql;">
SELECT *
FROM hockey_teams
WHERE rownum &lt;= 5
/
</pre></p>
<p>Now let&#8217;s list them in reverse-alphabetical order …</p>
<p><pre class="brush: sql;">
SQL&gt;  SELECT ROWNUM, team_name 
  2  FROM hockey_teams 
  3* ORDER BY team_name DESC 
SQL&gt; / 

ROWNUM TEAM_NAME 
------ -------------------- 
     4 WINNIPEG JETS 
     7 VANCOUVER CANUCKS 
     1 TORONTO MAPLE LEAFS 
     3 OTTOWA SENATORS 
     2 MONTREAL CANADIENS 
     6 EDMONTON OILERS 
     5 CALGARY FLAMES 

7 rows selected. 

SQL&gt; 

</pre></p>
<p>Here we can see the “catch” with relying on ROWNUM. It&#8217;s applied to the result set of the query before the ORDER BY. If we want to associate ROWNUM to the result set in order we&#8217;ll have to do something like :</p>
<p><pre class="brush: sql;">
SQL&gt; SELECT ROWNUM, team_name 
  2  FROM ( 
  3	 SELECT team_name 
  4	 FROM hockey_teams 
  5*	 ORDER BY team_name DESC) 
SQL&gt; / 

ROWNUM TEAM_NAME 
------ -------------------- 
     1 WINNIPEG JETS 
     2 VANCOUVER CANUCKS 
     3 TORONTO MAPLE LEAFS 
     4 OTTOWA SENATORS 
     5 MONTREAL CANADIENS 
     6 EDMONTON OILERS 
     7 CALGARY FLAMES 

7 rows selected. 

SQL&gt; 
</pre></p>
<p>Since the days of Oracle 6, analytical functions have come on leaps and bounds. Let&#8217;s face it, since those days, dinosaurs have become extinct and this new-fangled interweb thing has taken over the planet.<br />
In the intervening years, ROWNUM has all but disappeared from my SQL vocabulary.<br />
Recently however, I&#8217;ve come across a couple of instances where this venerable pseudo-column has come in handy.</p>
<h3>Sort of Random</h3>
<p>Let&#8217;s imagine for a moment that I&#8217;m planning my next trip to Canada.<br />
I want to catch some NHL action whilst I&#8217;m over there but can&#8217;t decide which teams I want to see.<br />
I want to pick two teams to see, more or less at random, but I don&#8217;t want to drop into PL/SQL&#8230;</p>
<p><pre class="brush: sql; wrap-lines: false;">
SQL&gt; SELECT 
  2    CASE MOD( ROWNUM, 3) 
  3	 WHEN 0 THEN 'Going to see ' 
  4	 ELSE 'Not going to see ' 
  5    END 
  6    || team_name 
  7* FROM hockey_teams 
SQL&gt; / 

CASEMOD(ROWNUM,3)WHEN0THEN'GOINGTOSEE'ELSE'NOTGOINGTOSEE'END||TEAM_NAME 
-------------------------------------------------------------------------------- 
Not going to see TORONTO MAPLE LEAFS 
Not going to see MONTREAL CANADIENS 
Going to see OTTOWA SENATORS 
Not going to see WINNIPEG JETS 
Not going to see CALGARY FLAMES 
Going to see EDMONTON OILERS 
Not going to see VANCOUVER CANUCKS 

7 rows selected. 

SQL&gt; 
</pre></p>
<p>OK, so it&#8217;s not that random. However, if we take another example, the value of ROWNUM becomes a bit more apparent.</p>
<p>Say I want to test some new functionality on the HR schema – one of the example schemas that ships with the Oracle database.<br />
Here, I want to account for employees that are paid either weekly or monthly.<br />
I&#8217;ve written some fancy Payroll routine to identify and process all of the appropriate employees at the appropriate time. This imaginary routine relies on a flag set on a new column in the employees table.<br />
The value of the colum must be either &#8216;W&#8217; for weekly or &#8216;M&#8217; for monthly.<br />
Most employees will be paid Monthly, but I do want some set to Weekly to make sure I test both possibilities. At this point, it doesn&#8217;t really matter which records are assigned which value.</p>
<p>If you want to play along&#8230;</p>
<p><pre class="brush: sql;">
CREATE TABLE hr_employees AS SELECT * FROM hr.employees
/

ALTER TABLE hr_employees ADD ( pay_frequency VARCHAR2(1))
/
</pre></p>
<p>We should now have a table that looks like this :</p>
<p><pre class="brush: sql; wrap-lines: false;">
SQL&gt; desc hr_employees; 
 Name					   Null?    Type 
 ----------------------------------------- -------- ---------------------------- 
 EMPLOYEE_ID					    NUMBER(6) 
 FIRST_NAME					    VARCHAR2(20) 
 LAST_NAME				   NOT NULL VARCHAR2(25) 
 EMAIL					   NOT NULL VARCHAR2(25) 
 PHONE_NUMBER					    VARCHAR2(20) 
 HIRE_DATE				   NOT NULL DATE 
 JOB_ID 				   NOT NULL VARCHAR2(10) 
 SALARY 					    NUMBER(8,2) 
 COMMISSION_PCT 				    NUMBER(2,2) 
 MANAGER_ID					    NUMBER(6) 
 DEPARTMENT_ID					    NUMBER(4) 
 PAY_FREQUENCY					    VARCHAR2(1) 

SQL&gt; 
</pre></p>
<p>The table contains 107 records. Now we want to set the PAY_FREQUENCY. We want to have around 10% of the rows to be set to &#8216;W&#8217; and the rest to &#8216;M&#8217;.<br />
Now, we could mess around with PL/SQL and it&#8217;s fancy cursor for loops&#8230;or we could just do this&#8230;</p>
<p><pre class="brush: sql;">
UPDATE hr_employees 
SET pay_frequency = 
    CASE MOD( ROWNUM, 10) 
        WHEN 0 THEN 'W' 
        ELSE 'M' 
    END 
/
</pre></p>
<p>Once we&#8217;ve run this, we can then see the effect&#8230;</p>
<p><pre class="brush: sql;">
SQL&gt; SELECT pay_frequency, COUNT( employee_id) 
  2  FROM hr_employees 
  3  GROUP BY pay_frequency 
  4  / 

PAY COUNT(EMPLOYEE_ID) 
--- ------------------ 
W		    10 
M		    97 

SQL&gt;

</pre></p>
<h3>Alert Log as an External Table</h3>
<p>For the other example of ROWNUMs continued usefulness, I&#8217;m going to use an external table. Yes, I know what you&#8217;re thinking after my <a href="http://wp.me/pweWl-i1">last post</a>, when you&#8217;ve got a hammer, then everything looks like a nail.</p>
<p>Consider the DBA. First thing in the morning, the sugar rush from all that Maple Syrup has long since worn off and the caffeine from that first cup of coffee is still negotiating it&#8217;s way from the mug to his  or her brain.<br />
Whilst in this state of chemical imbalance, our DBA needs to make sure that all is well after last night&#8217;s batch runs.<br />
Part of this morning ritual may well involve wading through the alert log.<br />
Now wouldn&#8217;t it make things just that little bit easier if we could get Oracle to do the thinking for us and just flag up any relevant alert log entries ?</p>
<p>Well, we know we can take a flat-file and treat it as an external table. Couldn&#8217;t we do the same with the alert.log ?<br />
Er, Yep. </p>
<p><pre class="brush: sql;">
CREATE OR REPLACE DIRECTORY bdump AS 
    '/usr/lib/oracle/xe/app/oracle/admin/XE/bdump' 
/
</pre></p>
<p>Now to create our external table :</p>
<p><pre class="brush: sql;">
CREATE TABLE alert_log_ext( 
	line VARCHAR2(4000)) 
	ORGANIZATION EXTERNAL 
	( 
		TYPE oracle_loader 
		DEFAULT DIRECTORY bdump 
		ACCESS PARAMETERS( 
			RECORDS DELIMITED BY NEWLINE 
			FIELDS TERMINATED BY '~' 
			MISSING FIELD VALUES ARE NULL 
			( 
				line CHAR(4000) 
			) 
		) 
			LOCATION('alert_XE.log') 
	) 
	REJECT LIMIT UNLIMITED 
/
</pre></p>
<p>And do a select&#8230;</p>
<p><pre class="brush: sql; wrap-lines: false;">
SELECT * 
FROM alert_log_ext
/
…
LINE 
-------------------------------------------------------------------------------- 
Sun Sep 18 13:23:23 2011 
Completed: ALTER DATABASE OPEN 

39243 rows selected. 
</pre></p>
<p>Lovely, we have the alert log in the database&#8230;.except there&#8217;s no key so just querying the bit you want is still a bit fiddly. On the plus side, the rows seem to be read in in correct order by default ( i.e. the order in which they are read from the file) so the result set from the query will be in the correct order, even though no ORDER BY clause is specified.<br />
<strong>NOTE</strong> – that last bit is supposition on my part. That&#8217;s the way it appears to be working, but I haven&#8217;t found anything in the Oracle documentation to confirm it.</p>
<p>But where does ROWNUM fit into all this, I hear you ask ? Well, if you want to query the alert log for a specific time window, you can do something like this :</p>
<p><pre class="brush: sql;">
SELECT entries.line_no, entries.line 
FROM( 
	SELECT rownum as line_no, line 
	FROM alert_log_ext 
	) entries, 
	( 
	SELECT MIN(line_no) as line_no 
	FROM ( SELECT rownum as line_no, line FROM alert_log_ext) 
	WHERE line LIKE TO_CHAR(SYSDATE -1, 'Dy Mon DD')||'%' 
	) yesterday 
WHERE entries.line_no &gt;= yesterday.line_no 
/
</pre></p>
<p>That&#8217;s better. We can now just return the rows of the alert log that have been written since the start of yesterday. However, we may well want to rely on something a bit more precise that just yesterday&#8217;s date.</p>
<p>At this point, it&#8217;s probably worth looking at the incredibly useful KSDWRT.<br />
Gesundheit ! I hear you cry. Thanks, but no, I haven&#8217;t just sneezed, I&#8217;m referring to DBMS_SYSTEM.KSDWRT.</p>
<p>Despite having a name that looks like you&#8217;ve just leaned on the keyboard, this procedure does have the incredibly useful ability to write a custom message to the alert log&#8230;</p>
<p><pre class="brush: sql;">
BEGIN 
DBMS_SYSTEM.KSDWRT(2, 'Oooh, a message'); 
END; 
/
</pre></p>
<p>Now, if we look in the alert log for this message&#8230;</p>
<p><pre class="brush: sql;">
SELECT line_no, line 
FROM( 
    SELECT ROWNUM as line_no, line 
    FROM alert_log_ext) 
WHERE line LIKE '%Oooh, a message' 
/ 

   LINE_NO LINE 
---------- ---------------------------------------- 
     38989 Oooh, a message 

</pre></p>
<p>With an appropriate message, we can narrow down our query to just the bit of the alert log that we&#8217;re interested in.</p>
<p>If we return to our bleary-eyed DBA, we could help out by simply writing a message to the alert log at the start of the overnight batch window.</p>
<p><pre class="brush: sql;">
DECLARE 
    l_msg VARCHAR2(30); 
BEGIN 
    l_msg := 'Batch Window Start - '||TO_CHAR(SYSDATE, 'DDMMRR'); 
    DBMS_SYSTEM.KSDWRT(2, l_msg); 
END; 
/
</pre></p>
<p>To make sure I&#8217;ve now got something after the message in the alert log, I&#8217;ve bounced the database.<br />
Now let&#8217;s see what entries we have in the alert log after our message :</p>
<p><pre class="brush: sql;">
SELECT entries.line 
FROM( 
	SELECT ROWNUM as line_no, line 
	FROM alert_log_ext 
	) entries 
WHERE entries.line_no &gt;= 
    (SELECT line_no 
     FROM ( 
        SELECT ROWNUM as line_no, line 
        FROM alert_log_ext) 
    WHERE line LIKE '%Batch Window Start - '||TO_CHAR(SYSDATE, 'DDMMRR')||'%') 
/
</pre></p>
<p>If the batch window starts before midnight, you&#8217;ll want to amend the line :<br />
<pre class="brush: plain;">
WHERE line LIKE '%Batch Window Start - '||TO_CHAR(SYSDATE, 'DDMMRR')||'%')
</pre></p>
<p>to</p>
<p><pre class="brush: plain;">
WHERE line LIKE '%Batch Window Start - '||TO_CHAR(SYSDATE -1, 'DDMMRR')||'%')
</pre></p>
<p>Simon and I have both come a long way since those heady days. He turned into Ewan McGregor and I &#8230;well&#8230;turned into a Dark Lord of the Sith apparently.</p>
<br />Filed under: <a href='http://mikesmithers.wordpress.com/category/oracle/'>Oracle</a>, <a href='http://mikesmithers.wordpress.com/category/oradbpedia-syndication/'>OraDBPedia Syndication</a>, <a href='http://mikesmithers.wordpress.com/category/sql/'>SQL</a> Tagged: <a href='http://mikesmithers.wordpress.com/tag/alert-log-as-an-external-table/'>alert log as an external table</a>, <a href='http://mikesmithers.wordpress.com/tag/alert-log/'>alert.log</a>, <a href='http://mikesmithers.wordpress.com/tag/dbms_system-ksdwrt/'>dbms_system.ksdwrt</a>, <a href='http://mikesmithers.wordpress.com/tag/external-tables/'>external tables</a>, <a href='http://mikesmithers.wordpress.com/tag/rownum/'>rownum</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mikesmithers.wordpress.com/1123/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mikesmithers.wordpress.com/1123/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mikesmithers.wordpress.com/1123/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mikesmithers.wordpress.com/1123/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mikesmithers.wordpress.com/1123/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mikesmithers.wordpress.com/1123/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mikesmithers.wordpress.com/1123/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mikesmithers.wordpress.com/1123/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mikesmithers.wordpress.com/1123/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mikesmithers.wordpress.com/1123/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mikesmithers.wordpress.com/1123/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mikesmithers.wordpress.com/1123/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mikesmithers.wordpress.com/1123/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mikesmithers.wordpress.com/1123/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1123&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mikesmithers.wordpress.com/2011/09/19/rownum-random-updates-and-the-alert-log-%e2%80%93-a-trip-down-memory-lane/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e3cb0956016bbad280193fbbd8e649b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">Mike S</media:title>
		</media:content>
	</item>
		<item>
		<title>Oracle External Tables or What I did on my Holidays</title>
		<link>http://mikesmithers.wordpress.com/2011/08/26/oracle-external-tables-or-what-i-did-on-my-holidays/</link>
		<comments>http://mikesmithers.wordpress.com/2011/08/26/oracle-external-tables-or-what-i-did-on-my-holidays/#comments</comments>
		<pubDate>Fri, 26 Aug 2011 02:36:55 +0000</pubDate>
		<dc:creator>mikesmithers</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[OraDBPedia Syndication]]></category>
		<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[external tables]]></category>
		<category><![CDATA[Global Temporary Table]]></category>
		<category><![CDATA[KUP-04063]]></category>
		<category><![CDATA[ORA-31619]]></category>
		<category><![CDATA[oracle_datapump]]></category>
		<category><![CDATA[oracle_loader]]></category>

		<guid isPermaLink="false">http://mikesmithers.wordpress.com/?p=1117</guid>
		<description><![CDATA[This week&#8217;s missive is coming to you from the netbook. Deb and I have pushed the boat out this year and we&#8217;re currently in Canada for our holiday. This has nothing at all to do with Oracle External Tables, but does explain the flavour of the examples that follow. What are they? External tables are [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1117&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>This week&#8217;s missive is coming to you from the netbook. Deb and I have pushed the boat out this year and we&#8217;re currently in Canada for our holiday.<br />
This has nothing at all  to do with Oracle External Tables, but does explain the flavour of the examples that follow.<span id="more-1117"></span></p>
<div id="attachment_1113" class="wp-caption alignnone" style="width: 460px"><a href="http://mikesmithers.files.wordpress.com/2011/08/imag0007.jpg"><img src="http://mikesmithers.files.wordpress.com/2011/08/imag0007.jpg?w=450&#038;h=269" alt="" title="IMAG0007" width="450" height="269" class="size-full wp-image-1113" /></a><p class="wp-caption-text">The Anti-Kyte on holiday...the costume didn&#039;t catch on</p></div>
<h3> What are they?</h3>
<p>External tables are a mechanism by which you can load flat file data into your database, or by which you can export data from your database.</p>
<p>Hold on, what about SQLLoader for data uploads ? And what exactly is wrong with Data Pump for exports ? Come to that, why not just use UTL_FILE for reading/writing files ?<br />
Well, these are all pertinent questions.<br />
In fact External tables make use of the SQL*Loader API for loading data and the Datapump API for exporting data.<br />
They are essentially another means of achieving what you can do with all of these tools. Which one you choose will no doubt depend on what you want to accomplish.<br />
The big difference is that you can use External Tables to query data not stored in the database wheras the other tools listed here are more concerned with getting data into the database first.<br />
As I want to knock out a blog post about External Tables, well, you can guess which one I&#8217;ll be using here.<br />
Our starting point is a table that contains all of the places I&#8217;m going to visit, together with the dates I&#8217;ll be there :</p>
<p><pre class="brush: sql;">
CREATE TABLE holiday_destinations(
    city_name VARCHAR2(30),
    flight_time DATE,
    arrival_time DATE)
/

INSERT INTO holiday_destinations(
    city_name, flight_time, arrival_time)
VALUES('HALIFAX', TO_DATE('20-08-11 12:35', 'DD-MM-RR HH24:MI'),
    TO_DATE('20-08-11 15:15', 'DD-MM-RR HH24:MI'))
/

INSERT INTO holiday_destinations(
    city_name, flight_time, arrival_time)
VALUES('MONTREAL', TO_DATE('22-08-11 12:25', 'DD-MM-RR HH24:MI'),
    TO_DATE('22-08-11 12:58', 'DD-MM-RR HH24:MI'))
/

INSERT INTO holiday_destinations(
    city_name, flight_time, arrival_time)
VALUES('TORONTO', TO_DATE('24-08-11 11:00', 'DD-MM-RR HH24:MI'),
    TO_DATE('24-08-11 12:15', 'DD-MM-RR HH24:MI'))
/

INSERT INTO holiday_destinations(
    city_name, flight_time, arrival_time)
VALUES('OTTOWA', TO_DATE('27-08-11 11:10', 'DD-MM-RR HH24:MI'),
    TO_DATE('27-08-11 12:10', 'DD-MM-RR HH24:MI'))
/

</pre></p>
<p>The data we want to upload relates to the flights between these cities. We&#8217;re going to put these into a csv file :</p>
<p><pre class="brush: plain;">
HALIFAX, 20-AUG-2011, 22-AUG-2011
MONTREAL, 22-AUG-2011, 24-AUG-2011
TORONTO, 24-AUG-2011, 27-AUG-2011
NIAGARA FALLS, 25-AUG-2011, 25-AUG-2011
OTTOWA, 27-AUG-2011, 30-AUG-2011
</pre></p>
<h3>Setting up a directory</h3>
<p>The first step is to tell the database where to look for the data we&#8217;re going to load into our external table. This involves defining a directory object to point to the os directory where the file is going to reside.<br />
This is exactly the same step that you need to take when reading/writing files using UTL_FILE so, in best Blue Peter tradition, here&#8217;s one I made earlier :</p>
<p><pre class="brush: bash;">
cd /usr/lib/oracle/xe/app/oracle/admin/XE
sudo su oracle
mkdir ext_tabs
</pre><br />
You should now have a directory owned by oracle to which oracle has read and write privileges.</p>
<p>Next, copy the .dat file to this directory</p>
<p><pre class="brush: plain;">
sudo cp $HOME/itinerary.dat /usr/lib/oracle/xe/app/oracle/admin/XE/ext_tabs/.
</pre></p>
<p>Now, in the database, set up a directory</p>
<p><pre class="brush: sql;">
CREATE DIRECTORY myfiles AS
    '/usr/lib/oracle/xe/app/oracle/admin/XE/ext_tabs'
/
</pre></p>
<p>The owner of the directory object should already have READ and WRITE privileges. </p>
<h3>The External Table (Part 1) &#8211; load</h3>
<p>We need to tell the database how to hold the data in the csv file. This is where we create the external table</p>
<p><pre class="brush: sql;">
CREATE TABLE itinerary_ext(
    location VARCHAR2(30),
    from_date DATE,
    leave_date DATE)
    ORGANIZATION EXTERNAL
    (
        type oracle_loader
        default directory myfiles
        access parameters ( 
            records delimited by newline
            fields terminated by ','
            missing field values are NULL
            reject rows with all null fields( location, from_date, leave_date)
        )
        location( 'itinerary.dat')
    )
/
</pre></p>
<p>The table type can be either oracle_loader or oracle_datapump. We&#8217;re using the first option here as we want to read data in.</p>
<h3>The External Table Upload</h3>
<p>If we just want to query the data, then we now simply have to issue a SELECT statement</p>
<p><pre class="brush: sql;">
SELECT *
FROM itinerary_ext
/
</pre></p>
<p>If  you get an error like this :<br />
<pre class="brush: plain;">
ERROR at line 1: 
ORA-29913: error in executing ODCIEXTTABLEOPEN callout 
ORA-29400: data cartridge error 
KUP-04063: unable to open log file ITINERARY_EXT_1718.log 
OS error Permission denied 
ORA-06512: at &quot;SYS.ORACLE_LOADER&quot;, line 19 
</pre></p>
<p>then it&#8217;s more than likely a permissions issue on the os. Check that the oracle owner (usually oracle) has write permissions on the directory (at the os level rather than in the database) where the csv file is located.</p>
<p>Assuming all is working as expected, we can use this table in any valid query :<br />
<pre class="brush: plain;">
SELECT hd.city_name, ie.from_date, ie.leave_date 
FROM holiday_destinations hd, itinerary_ext ie 
WHERE ie.location = hd.city_name 
/
</pre></p>
<p>OK, so there are some limitations, you can&#8217;t specify indexes on the external table for example, and direct DML is also not going to work.<br />
If we want to play with the data inside the database, we&#8217;re going to have to load it into a permanent segment&#8230;or are we ?<br />
Say you had some external data that you wanted to manipulate in some way and dump the output back onto the OS without the overhead of a permanent segment such as a holding table ? Well, this is an option using only external tables&#8230;provided you want to dump the results into another Oracle Database. This is where the datapump type comes in.</p>
<h3>External Table (Part 2) &#8211; Dump</h3>
<p>Instead of creating a permanent table, where going to create a Global Temporary Table :</p>
<p><pre class="brush: sql;">
CREATE GLOBAL TEMPORARY TABLE holiday_itinerary_gtt(
    city_name VARCHAR2(30),
    from_date DATE,
    leave_date DATE,
    flight_time DATE,
    arrival_time DATE)
    ON COMMIT PRESERVE ROWS
/
</pre></p>
<p>OK, so the structure IS permanently held in the Data Dictionary, but the data itself is transient and lives exclusively in the PGA.</p>
<p>Next, we&#8217;re going to need a procedure to do the transformation and dump the results out onto the os. This will require us to create an external table on the fly&#8230;</p>
<p><pre class="brush: sql; wrap-lines: false;">
CREATE OR REPLACE PROCEDURE export_flights_pr AS
    l_dummy PLS_INTEGER;
    l_exists BOOLEAN;
    CURSOR c_tab_exists IS
        SELECT 1
        FROM user_tables
        WHERE table_name = 'EXP_ITINERARY';
    
    l_out_tab VARCHAR2(4000) :=
        'CREATE TABLE exp_itinerary ORGANIZATION EXTERNAL '
        ||'( TYPE oracle_datapump '
        ||'  DEFAULT DIRECTORY myfiles '
        ||q'[  LOCATION( 'flights.dmp')]'
        ||') AS SELECT * FROM holiday_itinerary_gtt';  
BEGIN
    --
    -- Check to see if our external table currently exists.
    -- If so, we need to drop it
    --
    OPEN c_tab_exists;
    FETCH c_tab_exists INTO l_dummy;
    l_exists := c_tab_exists%FOUND;
    CLOSE c_tab_exists;
    
    IF l_exists THEN
        EXECUTE IMMEDIATE 'DROP TABLE exp_itinerary';
    END IF;
    --
    -- Now populate the GTT
    --    
    INSERT INTO holiday_itinerary_gtt( 
        city_name, from_date, leave_date,
        flight_time, arrival_time)
    SELECT ie.location, ie.from_date, ie.leave_date,
        hd.flight_time, hd.arrival_time
    FROM itinerary_ext ie, holiday_destinations hd
    WHERE ie.location = hd.city_name;
    --
    -- Now create an external table on the fly to dump out the results
    --
    EXECUTE IMMEDIATE l_out_tab;
END;
/
</pre></p>
<p>For the sake of clarity, the code for creating the external table is reproduced here :</p>
<p><pre class="brush: sql;">
CREATE TABLE exp_itinerary ORGANIZATION EXTERNAL( 
    TYPE oracle_datapump 
    DEFAULT DIRECTORY myfiles 
    LOCATION( 'flights.dmp') 
    ) 
    AS SELECT * FROM holiday_itinerary_gtt 
/
</pre></p>
<p>Just run the procedure&#8230;<br />
<pre class="brush: sql;">
exec export_flights_pr
</pre></p>
<p>You should now have a file called flights.dmp in your myfiles directory.<br />
<pre class="brush: bash;">
 ls -l flights.dmp 
-rw-r----- 1 oracle dba 12288 2011-08-25 02:56 flights.dmp 
</pre></p>
<p>So now we have a dump file, should be simple enough to import into the target database, shouldn&#8217;t it ? Not using datapump import, apparently, which gives you an ORA-31619 error complaining that the dump file wasn&#8217;t created by a datapump export. Honestly, there&#8217;s no pleasing some database utilities !</p>
<p>Sigh, I suppose we&#8217;ll just have to create another external table on the target database. This time, however, we specify the type as datapump&#8230;</p>
<p><pre class="brush: sql;">
CREATE table imp_flights (
    city_name VARCHAR2(30), 
    from_date DATE, 
    leave_date DATE,
    flight_time DATE, 
    arrival_time DATE)
    ORGANIZATION EXTERNAL
    (
        TYPE oracle_datapump
        DEFAULT DIRECTORY myfiles
        LOCATION('flights.dmp')
    )
/
</pre></p>
<p>Now it should all work as expected&#8230;</p>
<p><pre class="brush: sql;">
SELECT * FROM imp_flights
/
</pre></p>
<p>Right, sun cream, bear repellent, directions to the Moulson Brewery. I&#8217;m all set.</p>
<br />Filed under: <a href='http://mikesmithers.wordpress.com/category/oracle/'>Oracle</a>, <a href='http://mikesmithers.wordpress.com/category/oradbpedia-syndication/'>OraDBPedia Syndication</a>, <a href='http://mikesmithers.wordpress.com/category/plsql/'>PL/SQL</a>, <a href='http://mikesmithers.wordpress.com/category/sql/'>SQL</a> Tagged: <a href='http://mikesmithers.wordpress.com/tag/external-tables/'>external tables</a>, <a href='http://mikesmithers.wordpress.com/tag/global-temporary-table/'>Global Temporary Table</a>, <a href='http://mikesmithers.wordpress.com/tag/kup-04063/'>KUP-04063</a>, <a href='http://mikesmithers.wordpress.com/tag/ora-31619/'>ORA-31619</a>, <a href='http://mikesmithers.wordpress.com/tag/oracle_datapump/'>oracle_datapump</a>, <a href='http://mikesmithers.wordpress.com/tag/oracle_loader/'>oracle_loader</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mikesmithers.wordpress.com/1117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mikesmithers.wordpress.com/1117/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mikesmithers.wordpress.com/1117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mikesmithers.wordpress.com/1117/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mikesmithers.wordpress.com/1117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mikesmithers.wordpress.com/1117/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mikesmithers.wordpress.com/1117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mikesmithers.wordpress.com/1117/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mikesmithers.wordpress.com/1117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mikesmithers.wordpress.com/1117/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mikesmithers.wordpress.com/1117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mikesmithers.wordpress.com/1117/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mikesmithers.wordpress.com/1117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mikesmithers.wordpress.com/1117/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mikesmithers.wordpress.com&amp;blog=7683929&amp;post=1117&amp;subd=mikesmithers&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mikesmithers.wordpress.com/2011/08/26/oracle-external-tables-or-what-i-did-on-my-holidays/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e3cb0956016bbad280193fbbd8e649b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">Mike S</media:title>
		</media:content>

		<media:content url="http://mikesmithers.files.wordpress.com/2011/08/imag0007.jpg" medium="image">
			<media:title type="html">IMAG0007</media:title>
		</media:content>
	</item>
	</channel>
</rss>
