<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1286598839924995997</id><updated>2012-01-25T08:54:41.290+02:00</updated><category term='data integrity'/><category term='ougf; sql'/><category term='Map-Reduce'/><category term='support'/><category term='tools'/><category term='Architecture'/><category term='jdbc'/><category term='denormalization'/><category term='ETL'/><category term='net'/><category term='case-insensitive'/><category term='SQL tuning'/><category term='Hierarchical SQL'/><category term='SQL Server'/><category term='load'/><category term='dba work'/><category term='sqlplus'/><category term='Oracle'/><category term='date'/><category term='insert'/><category term='temp usage'/><category term='Performance tuning'/><category term='opatch'/><category term='Coding Dojo'/><category term='grid control'/><category term='ASCII graphics'/><category term='maintenence'/><category term='database'/><category term='append'/><category term='foreign key'/><category term='sql; null'/><category term='11.2'/><category term='OUGF'/><category term='grants;dblink'/><category term='pl/sql'/><category term='indexing'/><category term='monitoring'/><category term='audit'/><category term='Java'/><category term='conversions'/><category term='direct path insert'/><category term='null'/><category term='temporal sql'/><category term='constraints'/><category term='isolation level'/><category term='PostgreSQL'/><category term='data types'/><category term='sql'/><category term='view'/><category term='parallel SQL'/><category term='SQL Developer'/><category term='DB2'/><category term='unindex'/><category term='modeling'/><category term='Easter'/><category term='data guard'/><title type='text'>Rafu on db</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default?start-index=101&amp;max-results=100'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>111</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-7873394443636708061</id><published>2012-01-24T14:39:00.000+02:00</published><updated>2012-01-25T08:54:41.294+02:00</updated><title type='text'>XMLType from no rows</title><content type='html'>I used DBMS_XMLGEN package in my post &lt;a href="http://rafudb.blogspot.com/2012/01/constraint-name-generated.html"&gt;constraint name generated&lt;/a&gt;. There I used GETXML function and got problems when the schema constraints were all named. So the query result was empty - no rows.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;SELECT XMLTYPE(&lt;br /&gt;         DBMS_XMLGEN.GETXML('SELECT 1 FROM dual WHERE 1=0')&lt;br /&gt;       ) AS xml&lt;br /&gt;  FROM dual&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;ORA-06502: PL/SQL: numeric or value error&lt;br /&gt;ORA-06512: at "SYS.XMLTYPE", line 272&lt;br /&gt;ORA-06512: at line 1&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;There is a built in &lt;a href="http://docs.oracle.com/cd/E11882_01/appdev.112/e25788/d_xmlgen.htm#i1015152"&gt;DBMS_XMLGEN.GETXMLTYPE&lt;/a&gt; function to get the XMLType. This is how you get rid of the ORA-06502 problem.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;SELECT DBMS_XMLGEN.GETXMLTYPE('SELECT 1 FROM dual WHERE 1=0') AS xml&lt;br /&gt;  FROM dual&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-7873394443636708061?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/7873394443636708061/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2012/01/xmltype-from-no-rows.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7873394443636708061'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7873394443636708061'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2012/01/xmltype-from-no-rows.html' title='XMLType from no rows'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-3866886271992626978</id><published>2012-01-20T17:43:00.001+02:00</published><updated>2012-01-20T17:45:01.876+02:00</updated><title type='text'>A single serializable session throwing ORA-08177</title><content type='html'>We have a newly created table in a 11.2.0.3 Enterprise edition instance. A single session is throwing ORA-08177 can't serialize access for this transaction.The whole service level is marked for trace. &lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;exec DBMS_MONITOR.SERV_MOD_ACT_TRACE_ENABLE('servicename')&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;No one else is updating the tables involved. There comes out only two trace files. One having only the select 1 from dual connection pool check. And in the another trace there may be found.&lt;PRE&gt;&lt;br /&gt;ALTER SESSION SET ISOLATION_LEVEL = SERIALIZABLE&lt;br /&gt;END OF STMT&lt;br /&gt;&lt;/PRE&gt;Yes we wanted transactions to be serialized. Couple of inserts and internal staements. And an update to seg$ table thowing ORA-08177. &lt;PRE&gt;&lt;br /&gt;PARSING IN CURSOR #47594977567928 len=314 dep=1 uid=0 oct=6 lid=0 tim=1327068762208173 hv=3096556448 ad='de83deb8' sqlid='0kkhhb2w93cx0'&lt;br /&gt;&lt;b&gt;update seg$ set type#=:4,blocks=:5,extents=:6,minexts=:7,maxexts=:8,extsize=:9,extpct=:10,user#=:11,iniexts=:12,lists=decode(:13, 65535, NULL&lt;br /&gt;, :13),groups=decode(:14, 65535, NULL, :14), cachehint=:15, hwmincr=:16, spare1=DECODE(:17,0,NULL,:17),scanhint=:18, bitmapranges=:19 where t&lt;br /&gt;s#=:1 and file#=:2 and block#=:3&lt;/b&gt;&lt;br /&gt;END OF STMT&lt;br /&gt;PARSE #47594977567928:c=0,e=673,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,plh=0,tim=1327068762208172&lt;br /&gt;EXEC #47594977567928:c=1999,e=1411,p=0,cr=3,cu=1,mis=1,r=1,dep=1,og=4,plh=2170058777,tim=1327068762209667&lt;br /&gt;STAT #47594977567928 id=1 cnt=0 pid=0 pos=1 obj=0 op='UPDATE  SEG$ (cr=3 pr=0 pw=0 time=116 us)'&lt;br /&gt;STAT #47594977567928 id=2 cnt=1 pid=1 pos=1 obj=14 op='TABLE ACCESS CLUSTER SEG$ (cr=3 pr=0 pw=0 time=16 us cost=2 size=68 card=1)'&lt;br /&gt;STAT #47594977567928 id=3 cnt=1 pid=2 pos=1 obj=9 op='INDEX UNIQUE SCAN I_FILE#_BLOCK# (cr=2 pr=0 pw=0 time=6 us cost=1 size=0 card=1)'&lt;br /&gt;CLOSE #47594977567928:c=0,e=2,dep=1,type=3,tim=1327068762209778&lt;br /&gt;EXEC #47594977567928:c=0,e=125,p=0,cr=3,cu=1,mis=0,r=1,dep=1,og=4,plh=2170058777,tim=1327068762209931&lt;br /&gt;CLOSE #47594977567928:c=0,e=1,dep=1,type=3,tim=1327068762209972&lt;br /&gt;EXEC #47594977567928:c=0,e=129,p=0,cr=4,cu=1,mis=0,r=1,dep=1,og=4,plh=2170058777,tim=1327068762210127&lt;br /&gt;CLOSE #47594977567928:c=0,e=1,dep=1,type=3,tim=1327068762210167&lt;br /&gt;EXEC #47594984047704:c=50992,e=50764,p=7,cr=576,cu=241,mis=1,r=0,dep=0,og=1,plh=0,tim=1327068762211409&lt;br /&gt;&lt;b&gt;ERROR #47594984047704:err=8177&lt;/b&gt; tim=1327068762211441&lt;br /&gt;STAT #47594984047704 id=1 cnt=0 pid=0 pos=1 obj=0 op='LOAD TABLE CONVENTIONAL  (cr=0 pr=0 pw=0 time=1 us)'&lt;br /&gt;&lt;br /&gt;*** 2012-01-20 16:12:42.223&lt;br /&gt;WAIT #47594984047704: nam='log file sync' ela= 11537 buffer#=84 sync scn=604674242 p3=0 obj#=-1 tim=1327068762223055&lt;br /&gt;WAIT #47594984047704: nam='SQL*Net break/reset to client' ela= 21 driver id=1413697536 break?=1 p3=0 obj#=-1 tim=1327068762223170&lt;br /&gt;WAIT #47594984047704: nam='SQL*Net break/reset to client' ela= 3715 driver id=1413697536 break?=0 p3=0 obj#=-1 tim=1327068762226909&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;After awhile the problem vanished... No solutions in this post. Just wondering why...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-3866886271992626978?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/3866886271992626978/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2012/01/single-serializable-session-throwing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3866886271992626978'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3866886271992626978'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2012/01/single-serializable-session-throwing.html' title='A single serializable session throwing ORA-08177'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-5835376482409426598</id><published>2012-01-19T10:09:00.000+02:00</published><updated>2012-01-19T10:09:15.553+02:00</updated><title type='text'>Oracle instance memory usage</title><content type='html'>The right place to look for memory usage of a process in at operating system level. Interpreting the shared memory usage might be misleading. The top command seems to add the shared part to each process. And thou makes it hard to get right numbers. &lt;a href="http://www.pythian.com/news/29703/oracle-instance-memory-usage/"&gt;Here is a blog post&lt;/a&gt; trying to do that. Thou you could ask the numbers also from Oracle.Parameters influencing Oracle instance memory usage limits. 11g instance might have memory target set or sga and pga set separately.&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;select name,display_value &lt;br /&gt;  from v$parameter &lt;br /&gt; where name like 'mem%target' &lt;br /&gt;    or name like 'pga%' &lt;br /&gt;    or name like 'sga%'&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;The actual PGA usage might hit and go above those limits. The current allocation can be queried.&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;select round(sum(bytes)/1024/1024/1024,3) SGA_G &lt;br /&gt;  from v$sgastat;&lt;br /&gt;&lt;br /&gt;select round(value/1024/1024/1024,3) PGA_G&lt;br /&gt;  from v$pgastat &lt;br /&gt; where name = 'total PGA allocated';&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;Most often the database load varies over time. For resource planning it is vital to know how the memory usage is changing during night time. There might be going on some batch jobs whose behavior is not seen during day time.If you have diagnostics pack purchased you can also ask what was the situation earlier. Here is a query getting hourly memory usages of an Oracle instance.&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;select sga.allo sga, pga.allo pga,(sga.allo+pga.allo) tot,trunc(SN.END_INTERVAL_TIME,'mi') time&lt;br /&gt;  from&lt;br /&gt;(select snap_id,round(sum(bytes)/1024/1024/1024,3) allo &lt;br /&gt;   from DBA_HIST_SGASTAT &lt;br /&gt;  group by snap_id) sga&lt;br /&gt;,(select snap_id,round(sum(value)/1024/1024/1024,3) allo &lt;br /&gt;    from DBA_HIST_PGASTAT where name = 'total PGA allocated' &lt;br /&gt;   group by snap_id) pga&lt;br /&gt;, dba_hist_snapshot sn &lt;br /&gt;where sn.snap_id=sga.snap_id&lt;br /&gt;  and sn.snap_id=pga.snap_id&lt;br /&gt;order by sn.snap_id desc&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-5835376482409426598?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/5835376482409426598/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2012/01/oracle-instance-memory-usage.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5835376482409426598'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5835376482409426598'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2012/01/oracle-instance-memory-usage.html' title='Oracle instance memory usage'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-3419337859049141293</id><published>2012-01-16T18:47:00.000+02:00</published><updated>2012-01-16T20:47:10.464+02:00</updated><title type='text'>Longest roman number</title><content type='html'>It is possible to ask Oracle database the roman number presentation of a number. Just use to_char function with RN format. Just wondering what is the longest roman number.&lt;PRE&gt;&lt;br /&gt;select rn,len&lt;br /&gt; from (&lt;br /&gt;  select rn, max(length(rn))over() mlen, length(rn) len&lt;br /&gt;    from (&lt;br /&gt;    select to_char(level,'RN') rn from dual connect by level &lt;= 4000&lt;br /&gt;    )&lt;br /&gt;  )&lt;br /&gt;where mlen=len&lt;br /&gt;;&lt;br /&gt;&lt;/PRE&gt;Well they all are not 15 characters. Need to trim. &lt;PRE&gt;&lt;br /&gt;select n, rn,len&lt;br /&gt; from (&lt;br /&gt;  select n, rn, max(length(rn))over() mlen, length(rn) len&lt;br /&gt;    from (&lt;br /&gt;    select level n, trim(to_char(level,'RN')) rn from dual connect by level &lt;= 4000&lt;br /&gt;    )&lt;br /&gt;  )&lt;br /&gt;where mlen=len&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;3888 MMMDCCCLXXXVIII 15&lt;br /&gt;4000 ############### 15&lt;br /&gt;&lt;/PRE&gt;4000 and above are not converted. Also negative numbers and zero are not available. But in between 3888 seems to be "the longest".&lt;BR/&gt;&lt;BR/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-3419337859049141293?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/3419337859049141293/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2012/01/longest-roman-number.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3419337859049141293'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3419337859049141293'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2012/01/longest-roman-number.html' title='Longest roman number'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-2461675887004692502</id><published>2012-01-10T22:01:00.000+02:00</published><updated>2012-01-10T22:01:06.141+02:00</updated><title type='text'>Using client identifier to populate a column</title><content type='html'>Earlier I wrote about missing &lt;a href="http://rafudb.blogspot.com/2011/01/getclientidentifier.html"&gt;dbms_session.get_client_identifier&lt;/a&gt;. Here is a compound trigger example using session client identifier to populate a column in a table.&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;drop table t;&lt;br /&gt;&lt;br /&gt;create table t(n number, client_id varchar2(30) not null);&lt;br /&gt;&lt;br /&gt;create or replace trigger t_iuc for insert or update on t &lt;br /&gt;  compound trigger&lt;br /&gt;  cli varchar2(30);&lt;br /&gt; before statement is&lt;br /&gt;  begin&lt;br /&gt;   cli := SYS_CONTEXT('userenv', 'CLIENT_IDENTIFIER');&lt;br /&gt;  end before statement;&lt;br /&gt; before each row is&lt;br /&gt;  begin&lt;br /&gt;   :new.client_id := cli;&lt;br /&gt;  end before each row;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;exec dbms_session.set_identifier('rafu')&lt;br /&gt;&lt;br /&gt;insert into t(n) select level from dual connect by level &lt; 4;&lt;br /&gt;&lt;br /&gt;select * from t;&lt;br /&gt;&lt;br /&gt;1 rafu&lt;br /&gt;2 rafu&lt;br /&gt;3 rafu&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-2461675887004692502?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/2461675887004692502/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2012/01/using-client-identifier-to-populate.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2461675887004692502'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2461675887004692502'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2012/01/using-client-identifier-to-populate.html' title='Using client identifier to populate a column'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-3383659478694725976</id><published>2012-01-04T11:39:00.000+02:00</published><updated>2012-01-24T14:54:50.848+02:00</updated><title type='text'>Constraint name generated</title><content type='html'>Generated constraint names makes development, testing and production environment error messages vary. And those reported SYS_C006206630 could be more informative. To identify those generated constraint names *_constraints views has the information available at generated column. The constraint search_condition is a long typed column and thou hard to use. &lt;A HREF=http://www.oracle-developer.net/display.php?id=430&gt;Working with long columns&lt;/A&gt; document gives tools to convert the search column to varchar2. This query reports generated named constraints in users schema. &lt;PRE&gt;&lt;br /&gt;WITH xml AS (&lt;br /&gt;          SELECT DBMS_XMLGEN.GETXMLTYPE(&lt;br /&gt;                     'select co.constraint_name&lt;br /&gt;                           , co.table_name&lt;br /&gt;                           , cc.column_name&lt;br /&gt;                           , co.constraint_type&lt;br /&gt;                           , co.r_constraint_name&lt;br /&gt;                           , co.search_condition  &lt;br /&gt;                        from user_constraints co&lt;br /&gt;                        left outer join user_cons_columns cc&lt;br /&gt;                          on co.constraint_name = cc.constraint_name &lt;br /&gt;                       where co.generated = ''GENERATED NAME''')&lt;br /&gt;                    AS xml&lt;br /&gt;          FROM   dual&lt;br /&gt;          ), concol as (&lt;br /&gt;  SELECT extractValue(xs.object_value, '/ROW/TABLE_NAME')       AS table_name&lt;br /&gt;  ,      extractValue(xs.object_value, '/ROW/COLUMN_NAME')      AS column_name&lt;br /&gt;  ,      extractValue(xs.object_value, '/ROW/CONSTRAINT_TYPE')  AS constraint_type&lt;br /&gt;  ,      extractValue(xs.object_value, '/ROW/CONSTRAINT_NAME')  AS constraint_name&lt;br /&gt;  ,      extractValue(xs.object_value, '/ROW/R_CONSTRAINT_NAME')  AS r_constraint_name&lt;br /&gt;  ,      extractValue(xs.object_value, '/ROW/SEARCH_CONDITION') AS search_condition&lt;br /&gt;  FROM   xml x&lt;br /&gt;  ,      TABLE(XMLSEQUENCE(EXTRACT(x.xml, '/ROWSET/ROW'))) xs&lt;br /&gt;)&lt;br /&gt;select cc.* &lt;br /&gt;  from concol cc&lt;br /&gt;order by table_name, column_name,constraint_type&lt;br /&gt;;&lt;br /&gt;&lt;/PRE&gt;&lt;BR/&gt;Give names to the reported constraints to your modeling tool. NOT NULL checks are not first in the list to be named. NOT NULL error messages are informative with the generated names also. But naming also those make the different (DEV,TST,PRD) schemas a bit more similar. &lt;a href="http://www.oracle.com/technetwork/developer-tools/datamodeler/overview/index.html"&gt;SQL Developer Data modeler&lt;/a&gt; 3.1 EA3 has the possibility to name those also at relational model. Formerly it was only possible at physical model. If you feel like too much work modeling those at least change the reported names. &lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;ALTER TABLE test RENAME CONSTRAINT SYS_C006206630 TO test_pk;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;BR/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-3383659478694725976?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/3383659478694725976/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2012/01/constraint-name-generated.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3383659478694725976'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3383659478694725976'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2012/01/constraint-name-generated.html' title='Constraint name generated'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-3555953041509937591</id><published>2011-12-28T15:30:00.003+02:00</published><updated>2011-12-28T15:30:58.125+02:00</updated><title type='text'>unindex 11.2 cross schema</title><content type='html'>Foreign keys might point to another schema. Here is an unindex query for such situation. My earlier queries &lt;a href="http://rafudb.blogspot.com/2009/02/unindex.html"&gt;unindex&lt;/a&gt; and &lt;a href="http://rafudb.blogspot.com/2009/11/unindex-112.html"&gt;unindex 11.2&lt;/a&gt; were built on top of user_* views. Here the queries are using all_* views. I am not using dba_* views as all_* views are usable for wider audience than just dba privileged.Reminder: you probably do not need all of those, but they might explain you some poor execution times or TM lock waits.&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;select case when i.index_name is not null&lt;br /&gt;            then 'OK'&lt;br /&gt;            else '****'&lt;br /&gt;       end ok&lt;br /&gt;     , c.owner&lt;br /&gt;     , c.table_name&lt;br /&gt;     , c.constraint_name&lt;br /&gt;     , c.cols&lt;br /&gt;     , i.index_name&lt;br /&gt;from (&lt;br /&gt;  select a.owner&lt;br /&gt;       , a.table_name&lt;br /&gt;       , a.constraint_name&lt;br /&gt;       , listagg(b.column_name, ' ' ) &lt;br /&gt;          within group (order by column_name) cols&lt;br /&gt;      from all_constraints a, all_cons_columns b&lt;br /&gt;     where a.owner = b.owner&lt;br /&gt;       and a.constraint_name = b.constraint_name&lt;br /&gt;       and a.constraint_type = 'R'&lt;br /&gt;  group by a.owner,a.table_name, a.constraint_name&lt;br /&gt; ) c&lt;br /&gt; left outer join&lt;br /&gt; (&lt;br /&gt;  select index_owner&lt;br /&gt;       , table_name&lt;br /&gt;       , index_name&lt;br /&gt;       , cr&lt;br /&gt;       , listagg(column_name, ' ' ) &lt;br /&gt;          within group (order by column_name) cols&lt;br /&gt;    from (&lt;br /&gt;        select index_owner&lt;br /&gt;             , table_name&lt;br /&gt;             , index_name&lt;br /&gt;             , column_position&lt;br /&gt;             , column_name&lt;br /&gt;             , connect_by_root(column_name) cr&lt;br /&gt;          from all_ind_columns&lt;br /&gt;       connect by prior column_position-1 = column_position&lt;br /&gt;              and prior index_name = index_name&lt;br /&gt;              and prior index_owner = index_owner&lt;br /&gt;         )&lt;br /&gt;    group by index_owner, table_name, index_name, cr&lt;br /&gt;) i on c.owner = i.index_owner and c.cols = i.cols and c.table_name = i.table_name&lt;br /&gt;order by ok,owner,table_name,constraint_name;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-3555953041509937591?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/3555953041509937591/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/12/unindex-112-cross-schema.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3555953041509937591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3555953041509937591'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/12/unindex-112-cross-schema.html' title='unindex 11.2 cross schema'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-3605549528692593713</id><published>2011-12-20T13:55:00.000+02:00</published><updated>2011-12-20T14:17:19.840+02:00</updated><title type='text'>The index could be unique</title><content type='html'>&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;drop table uq;&lt;br /&gt;&lt;br /&gt;create table uq(pk int constraint uq_pk primary key, col int, col2 int);&lt;br /&gt;&lt;br /&gt;create index uq_col_idx on uq(col,pk);&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;Index uq_col_idx is not unique but it might be defined as such. It contains all columns in a unique primary key. To find such candidates is just another relational division question.&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;with co as (&lt;br /&gt;select con.constraint_name&lt;br /&gt;     , con.table_name&lt;br /&gt;     , cco.column_name&lt;br /&gt;     , count(*) over (partition by con.constraint_name) ccc &lt;br /&gt;  from user_constraints con &lt;br /&gt; inner join user_cons_columns cco &lt;br /&gt;    on cco.constraint_name=con.constraint_name &lt;br /&gt; where con.constraint_type in ('P','U') &lt;br /&gt;   and con.deferrable = 'NOT DEFERRABLE' &lt;br /&gt;), ix as (&lt;br /&gt;select idx.table_name,idx.index_name,ico.column_name,idx.uniqueness&lt;br /&gt;  from user_indexes idx &lt;br /&gt; inner join user_ind_columns ico &lt;br /&gt;    on idx.index_name = ico.index_name&lt;br /&gt;), ixco as (&lt;br /&gt;select ix.table_name&lt;br /&gt;     , ix.index_name&lt;br /&gt;     , ix.column_name&lt;br /&gt;     , co.constraint_name&lt;br /&gt;     , co.ccc&lt;br /&gt;     , count(*) over (partition by co.constraint_name,ix.index_name) ixc&lt;br /&gt;     , ix.uniqueness&lt;br /&gt;  from co, ix&lt;br /&gt; where co.table_name=ix.table_name &lt;br /&gt;  and co.column_name=ix.column_name&lt;br /&gt;)&lt;br /&gt;select distinct table_name,index_name could_be_unique,constraint_name based_on&lt;br /&gt;  from ixco&lt;br /&gt; where uniqueness = 'NONUNIQUE'&lt;br /&gt;   and ccc=ixc&lt;br /&gt; order by table_name,index_name&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;TABLE_NAME                     COULD_BE_UNIQUE                BASED_ON&lt;br /&gt;------------------------------ ------------------------------ ------------------------------&lt;br /&gt;UQ                             UQ_COL_IDX                     UQ_PK&lt;br /&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;br /&gt;drop index uq_col_idx;&lt;br /&gt;&lt;br /&gt;create unique index uq_col_idx on uq(col,pk);&lt;br /&gt;&lt;/PRE&gt;&lt;BR/&gt;&lt;BR/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-3605549528692593713?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/3605549528692593713/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/12/index-could-be-unique.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3605549528692593713'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3605549528692593713'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/12/index-could-be-unique.html' title='The index could be unique'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-2138202290619220433</id><published>2011-12-14T00:39:00.002+02:00</published><updated>2011-12-14T00:39:58.633+02:00</updated><title type='text'>A table vanishing from a plan</title><content type='html'>Christian Antognini published his presentation slides &lt;a href="http://antognini.ch/2011/12/challenges-and-chances-of-the-11g-query-optimizer/"&gt;Challenges and Chances of the 11g Query Optimizer&lt;/a&gt;. Worth reading to get a nice overview.The 11g new feature "join elimination" is mentioned there. There is a similar behavior even in 10gR2 optimizer. A table mentioned in a query text vanishes from the query plan. It is not a join but a correlated sub query with a aggregate.&lt;PRE&gt;&lt;br /&gt;select 1 &lt;br /&gt;  from dual mai &lt;br /&gt; where exists (&lt;br /&gt;   select max(1) &lt;br /&gt;     from dual inn &lt;br /&gt;    where mai.dummy=inn.dummy&lt;br /&gt;)&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;---------------------------------&lt;br /&gt;| Id  | Operation        | Name |&lt;br /&gt;---------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT |      |&lt;br /&gt;|   1 |  FAST DUAL       |      |&lt;br /&gt;---------------------------------&lt;br /&gt;&lt;/PRE&gt;The sub query and the "inn" table is not seen in the plan. There is no need as the aggregate returns a row. This is not the case in my earlier post about &lt;a href="http://rafudb.blogspot.com/2011/02/not-exists-null.html"&gt;not exists null&lt;/a&gt;. There the sub query is not correlated and it is using not exists.The not exists correlated makes similar elimination. But in addition adds a filter(NULL IS NOT NULL) just before entering even the first table.&lt;PRE&gt;&lt;br /&gt;select 1 &lt;br /&gt;  from dual mai &lt;br /&gt; where not exists (&lt;br /&gt;   select max(1) &lt;br /&gt;     from dual inn &lt;br /&gt;    where mai.dummy=inn.dummy&lt;br /&gt;)&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;---------------------------------&lt;br /&gt;| Id  | Operation        | Name |&lt;br /&gt;---------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT |      |&lt;br /&gt;|*  1 |  FILTER          |      |&lt;br /&gt;|   2 |   FAST DUAL      |      |&lt;br /&gt;---------------------------------&lt;br /&gt; &lt;br /&gt;Predicate Information (identified by operation id):&lt;br /&gt;---------------------------------------------------&lt;br /&gt; &lt;br /&gt;   1 - filter(NULL IS NOT NULL)&lt;br /&gt;&lt;/PRE&gt;One could ask, why would somebody write such a query...&lt;BR/&gt;&lt;BR/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-2138202290619220433?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/2138202290619220433/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/12/table-vanishing-from-plan.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2138202290619220433'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2138202290619220433'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/12/table-vanishing-from-plan.html' title='A table vanishing from a plan'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6016963146573127269</id><published>2011-11-25T10:44:00.001+02:00</published><updated>2011-11-25T11:14:22.013+02:00</updated><title type='text'>A Question</title><content type='html'>I attended the Jonathan Lewis seminar three weeks ago and wrote just after that about &lt;a href="http://rafudb.blogspot.com/2011/11/information-overload.html"&gt;information overload&lt;/a&gt;. The things learned there have helped me understanding issues I have to deal with the Oracle optimizer. The amount of information gained need some time to melt into mind. One issue talked there was a question.The original written question was "How many choises does Oracle have in this example?" With addition there was mentioned "for all versions".&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;drop table t1;&lt;br /&gt;&lt;br /&gt;create table t1( &lt;br /&gt;  n1 number&lt;br /&gt;, n2 number&lt;br /&gt;, n3 number&lt;br /&gt;, constraint t1p primary key(n1)&lt;br /&gt;, constraint t1u unique (n2));&lt;br /&gt;&lt;br /&gt;select count(*) from t1;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;I answered wrongly mentioning also that it depends on the version.As so often my mind started to think howcome I answered such an answer. Maybe I was thinking a question: How many different execution plan possibilities does Oracle have in this example? Unfortunately I am not attending UKOUG to throw this to the &lt;a href="http://www.computerworlduk.com/news/it-business/3318022/can-the-oaktable-answer-your-oracle-question/"&gt;OakTable Challenge&lt;/a&gt;. Feel free to use "Give me at least one that was not in the list of the Jonathan's answer and how to get there." I will be coming back to the issue after 7th of December.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6016963146573127269?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6016963146573127269/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/11/question.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6016963146573127269'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6016963146573127269'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/11/question.html' title='A Question'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-8642475249408454020</id><published>2011-11-23T11:36:00.001+02:00</published><updated>2011-11-23T12:00:41.561+02:00</updated><title type='text'>Filtering outer join to hash join plan</title><content type='html'>I gave a SQL presentation a couple of years ago. There I mentioned the possibility to restrict an outer join when using ANSI joins. Every now and then seen such an join condition. Maybe even written myself. This week such a query has been bothering me with a long running nested loops access path. This was a simpler query than the one with &lt;a href="http://rafudb.blogspot.com/2011/09/migrating-to-11203-ora-00976.html"&gt;outer join exists predicate&lt;/a&gt; I have mentioned earlier.While dealing with it I saw a quite funny looking predicate. &lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;drop table aa;&lt;br /&gt;&lt;br /&gt;drop table bb;&lt;br /&gt;&lt;br /&gt;create table aa as &lt;br /&gt;select rownum id&lt;br /&gt;     , nullif(mod(rownum,3),1) val &lt;br /&gt;  from dual connect  by level &lt; 12;&lt;br /&gt;&lt;br /&gt;create table bb as &lt;br /&gt;select rownum id&lt;br /&gt;     , nullif(mod(rownum,3),0)+10 val &lt;br /&gt;  from dual connect by level &lt; 9;&lt;br /&gt;&lt;br /&gt;alter table aa modify id not null;&lt;br /&gt;&lt;br /&gt;alter table bb modify id not null;&lt;br /&gt;&lt;br /&gt;select aa.* from aa;&lt;br /&gt;&lt;br /&gt;        ID        VAL&lt;br /&gt;---------- ----------&lt;br /&gt;         1&lt;br /&gt;         2          2&lt;br /&gt;         3          0&lt;br /&gt;         4&lt;br /&gt;         5          2&lt;br /&gt;         6          0&lt;br /&gt;         7&lt;br /&gt;         8          2&lt;br /&gt;         9          0&lt;br /&gt;        10&lt;br /&gt;        11          2&lt;br /&gt;&lt;br /&gt;select bb.* from bb;&lt;br /&gt;&lt;br /&gt;        ID        VAL&lt;br /&gt;---------- ----------&lt;br /&gt;         1         11&lt;br /&gt;         2         12&lt;br /&gt;         3&lt;br /&gt;         4         11&lt;br /&gt;         5         12&lt;br /&gt;         6&lt;br /&gt;         7         11&lt;br /&gt;         8         12&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;Desired results:&lt;PRE&gt;   &lt;br /&gt;        ID        VAL         ID        VAL&lt;br /&gt;---------- ---------- ---------- ----------&lt;br /&gt;         1&lt;br /&gt;         2          2          2         12&lt;br /&gt;         3          0&lt;br /&gt;         4&lt;br /&gt;         5          2          5         12&lt;br /&gt;         6          0&lt;br /&gt;         7&lt;br /&gt;         8          2          8         12&lt;br /&gt;         9          0&lt;br /&gt;        10&lt;br /&gt;        11          2&lt;br /&gt;&lt;/PRE&gt;A normal outer join uses hash join plan. Adding the predicate aa.val = 2 to the join condition I get the result I want. &lt;PRE&gt;&lt;br /&gt;select * &lt;br /&gt;  from aa &lt;br /&gt;  left outer join bb &lt;br /&gt;    on aa.id=bb.id&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;-----------------------------------&lt;br /&gt;| Id  | Operation          | Name |&lt;br /&gt;-----------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT   |      |&lt;br /&gt;|*  1 |  HASH JOIN OUTER   |      |&lt;br /&gt;|   2 |   TABLE ACCESS FULL| AA   |&lt;br /&gt;|   3 |   TABLE ACCESS FULL| BB   |&lt;br /&gt;-----------------------------------&lt;br /&gt;&lt;br /&gt;Predicate Information (identified by operation id):&lt;br /&gt;---------------------------------------------------&lt;br /&gt;&lt;br /&gt;   1 - access("AA"."ID"="BB"."ID")&lt;br /&gt;   &lt;br /&gt;   &lt;br /&gt;select * &lt;br /&gt;  from aa &lt;br /&gt;  left outer join bb &lt;br /&gt;    on aa.id=bb.id and &lt;B&gt;aa.val = 2&lt;/B&gt;&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;-------------------------------------&lt;br /&gt;| Id  | Operation            | Name |&lt;br /&gt;-------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT     |      |&lt;br /&gt;|   1 |  NESTED LOOPS OUTER  |      |&lt;br /&gt;|   2 |   TABLE ACCESS FULL  | AA   |&lt;br /&gt;|   3 |   VIEW               |      |&lt;br /&gt;|*  4 |    FILTER            |      |&lt;br /&gt;|*  5 |     TABLE ACCESS FULL| BB   |&lt;br /&gt;-------------------------------------&lt;br /&gt;&lt;br /&gt;Predicate Information (identified by operation id):&lt;br /&gt;---------------------------------------------------&lt;br /&gt;&lt;br /&gt;   4 - filter("AA"."VAL"=2)&lt;br /&gt;   5 - filter("AA"."ID"="BB"."ID")&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;But the 11.1.0.7 optimizer goes to a nested loops path. My problem is that the table BB is kind of big. Together with plan row 4 filter is not filtering out so many rows the execution is full table scanning the table bb too many times.Throwing the same query to 11.2.0.3 optimizer I get a hash join access path. Nice. That was something I was hoping for. But look at the access predicate.   &lt;PRE&gt;&lt;br /&gt;-----------------------------------&lt;br /&gt;| Id  | Operation          | Name |&lt;br /&gt;-----------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT   |      |&lt;br /&gt;|*  1 |  HASH JOIN OUTER   |      |&lt;br /&gt;|   2 |   TABLE ACCESS FULL| AA   |&lt;br /&gt;|   3 |   TABLE ACCESS FULL| BB   |&lt;br /&gt;-----------------------------------&lt;br /&gt;&lt;br /&gt;Predicate Information (identified by operation id):&lt;br /&gt;---------------------------------------------------&lt;br /&gt;&lt;br /&gt;   1 - access("AA"."ID"="BB"."ID" AND "AA"."VAL"=CASE  WHEN ("BB"."ID"&lt;br /&gt;              IS NOT NULL) THEN 2 ELSE 2 END )&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;Obviously the outer join (+) are missing next to BB.ID. You need to read it from the word OUTER next to the HASH JOIN. Sqldeveloper is able to visualize the predicate differently. &lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;AA.ID=BB.ID(+) AND AA.VAL=CASE  WHEN (BB.ID(+) IS NOT NULL) THEN 2 ELSE 2 END&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;But that case statement seems kind of weird. "If something then constant otherwise the same constant". Should that case statement not be possible to be optimized to be a simple constant 2? I rewrote my query to use the old style join. And with 11.2.0.3 the plan and results stay the same. But going back to 11.1.0.7 things change.&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;select aa.*,bb.* &lt;br /&gt; from aa, bb &lt;br /&gt;where aa.id=bb.id(+) &lt;br /&gt;  and aa.val = case when (bb.id(+) is not null) then 2 else 2 end&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;-----------------------------------&lt;br /&gt;| Id  | Operation          | Name |&lt;br /&gt;-----------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT   |      |&lt;br /&gt;|*  1 |  HASH JOIN OUTER   |      |&lt;br /&gt;|*  2 |   TABLE ACCESS FULL| AA   |&lt;br /&gt;|   3 |   TABLE ACCESS FULL| BB   |&lt;br /&gt;-----------------------------------&lt;br /&gt;&lt;br /&gt;Predicate Information (identified by operation id):&lt;br /&gt;---------------------------------------------------&lt;br /&gt;&lt;br /&gt;   1 - access("AA"."ID"="BB"."ID")&lt;br /&gt;   2 - filter("AA"."VAL"=2)&lt;br /&gt;   &lt;br /&gt;&lt;/PRE&gt;   The case statement is optimized as a simple constant and used as a filter staright to the table AA.Query results change compared to 11.2.0.3 results. Actually the thing I wanted out is without the else part in the predicate.&lt;PRE&gt;&lt;br /&gt;select aa.*,bb.* &lt;br /&gt; from aa, bb &lt;br /&gt;where aa.id=bb.id(+) &lt;br /&gt;  and aa.val = case when (bb.id(+) is not null) then 2 end&lt;br /&gt;;&lt;br /&gt;-----------------------------------&lt;br /&gt;| Id  | Operation          | Name |&lt;br /&gt;-----------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT   |      |&lt;br /&gt;|*  1 |  HASH JOIN OUTER   |      |&lt;br /&gt;|   2 |   TABLE ACCESS FULL| AA   |&lt;br /&gt;|   3 |   TABLE ACCESS FULL| BB   |&lt;br /&gt;-----------------------------------&lt;br /&gt;&lt;br /&gt;Predicate Information (identified by operation id):&lt;br /&gt;---------------------------------------------------&lt;br /&gt;&lt;br /&gt;   1 - access("AA"."ID"="BB"."ID" AND "AA"."VAL"=CASE  WHEN ("BB"."ID"&lt;br /&gt;              IS NOT NULL) THEN 2 END )&lt;br /&gt;&lt;/PRE&gt;The results are what I was requesting. This may be rewoten back to ANSI join that is understood also by 11.1.0.7 optimizer and the execution goes to a hash join path. &lt;PRE&gt;&lt;br /&gt;select aa.*,bb.* &lt;br /&gt;  from aa &lt;br /&gt;  left outer join bb &lt;br /&gt;    on aa.id=bb.id &lt;br /&gt;   and aa.val = case when (bb.id is not null) then 2 end&lt;br /&gt;;&lt;br /&gt;&lt;/PRE&gt;I am satisfied with the results. Well throw another problem to the optimizers. How about nulls. Change the "and aa.val =" to "and aa.val is null" and even 11.2.0.3 is not able to go to a hash join plan. Here is an problematic nested loops access path query and a dirty trick on a way to a hash path.&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;select aa.*,bb.*&lt;br /&gt;  from aa &lt;br /&gt;  left outer join bb &lt;br /&gt;    on aa.id=bb.id &lt;br /&gt;   and aa.val is null&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;select * &lt;br /&gt;  from aa &lt;br /&gt;  left outer join bb &lt;br /&gt;    on aa.id=bb.id &lt;br /&gt;   and coalesce(nullif(aa.val,bb.id),aa.val) is null&lt;br /&gt;;&lt;br /&gt;&lt;/PRE&gt;&lt;BR/&gt;&lt;BR/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-8642475249408454020?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/8642475249408454020/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/11/filtering-outer-join-to-hash-join-plan.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8642475249408454020'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8642475249408454020'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/11/filtering-outer-join-to-hash-join-plan.html' title='Filtering outer join to hash join plan'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-3453839249349041245</id><published>2011-11-17T19:06:00.001+02:00</published><updated>2011-11-18T08:44:29.451+02:00</updated><title type='text'>Skip locked</title><content type='html'>&lt;br /&gt;SQL SELECT&amp;nbsp;&lt;a href="http://download.oracle.com/docs/cd/E11882_01/server.112/e26088/statements_10002.htm#i2126016"&gt;SKIP LOCKED&lt;/a&gt;&amp;nbsp;not mentioned in &lt;a href="http://download.oracle.com/docs/cd/E11882_01/server.112/e26088/wnsql.htm#sthref3"&gt;new features&lt;/a&gt; part of the SQL document. Seems to be there already in 11gr1.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; create table skiplocked as select  level n from dual connect by level &lt; 3;&lt;br /&gt;&lt;br /&gt;Table created.&lt;br /&gt;&lt;br /&gt;SQL&gt; select * from skiplocked where n=1 for update;&lt;br /&gt;&lt;br /&gt;         N&lt;br /&gt;----------&lt;br /&gt;         1&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;At the same time another session&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SQL&gt; select * from skiplocked;&lt;br /&gt;&lt;br /&gt;         N&lt;br /&gt;----------&lt;br /&gt;         1&lt;br /&gt;         2&lt;br /&gt;&lt;br /&gt;SQL&gt; select * from skiplocked for update &lt;b&gt;skip locked&lt;/b&gt;;&lt;br /&gt;&lt;br /&gt;         N&lt;br /&gt;----------&lt;br /&gt;         2&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As the 11gr1 have been around for a while. Rob Van Wijk has written something about the feature.  &lt;br /&gt;&lt;a href="http://rwijk.blogspot.com/2007/12/parallellism-in-skip-locked-scenario.html"&gt;http://rwijk.blogspot.com/2007/12/parallellism-in-skip-locked-scenario.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://rwijk.blogspot.com/2009/02/for-update-skip-locked.html"&gt;http://rwijk.blogspot.com/2009/02/for-update-skip-locked.html&lt;/a&gt;&lt;br /&gt;"when using FOR UPDATE SKIP LOCKED, records are locked when they are fetched, not when the cursor is opened" Need to read those again when the need for this feature comes...&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-3453839249349041245?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/3453839249349041245/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/11/skip-locked.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3453839249349041245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3453839249349041245'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/11/skip-locked.html' title='Skip locked'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6865567199579713841</id><published>2011-11-17T16:57:00.001+02:00</published><updated>2011-11-18T08:24:17.795+02:00</updated><title type='text'>Installing an agent and not a free lunch</title><content type='html'>Installing an Cloud Control 12 agent using &lt;a href="http://download.oracle.com/docs/cd/E24628_01/install.121/e24089/install_agent_usng_rpm.htm#CACIBJBI"&gt;rpm method&lt;/a&gt;. So not letting the Cloud Control do the agent installation, but do it manually at the agent node.While generating the rpm &lt;PRE&gt;&lt;br /&gt;$OMS_HOME/bin/emcli get_agentimage_rpm -destination=/tmp -platform="Linux x86-64"&lt;br /&gt;&lt;/PRE&gt;I got an error &lt;PRE&gt;&lt;br /&gt;Agent image to rpm conversion failed&lt;br /&gt;&lt;/PRE&gt;and the logfile stating&lt;PRE&gt;&lt;br /&gt;Directory /usr/lib/oracle doesnt exist. Please create the directory with write permissions and then retry the emcli command.&lt;br /&gt;&lt;/PRE&gt;Well that is mentioned in the document Prerequisites, but This requirement is for the server OMS side.So as a root before issuing the command:&lt;PRE&gt;&lt;br /&gt;mkdir /usr/lib/oracle&lt;br /&gt;chown oracle:oinstall /usr/lib/oracle&lt;br /&gt;&lt;/PRE&gt;Also note that Editing agent.properties File &lt;i&gt;(Only for Virtual Hosts)&lt;/i&gt; means here &lt;i&gt;(Mandatory). &lt;/i&gt;Put the agent node host name there.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;ORACLE_HOSTNAME(Only for Virtual Hosts) Enter the virtual host name where you want to install the Management Agent.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And before issuing the &amp;nbsp;make sure the machines see each other. After installed the agent I had a small issue with machine naming at /etc/hosts. The installed agent and host appeared yellow "Pending"&amp;nbsp;at the&amp;nbsp;summary pie chart. After fixing the visibity of the agent machine emcli resyncAgent fixed the issue.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;$OMS_HOME/bin/emcli resyncAgent -agent="agentname:3872"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Would it be cool to have following situation possible:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-upfssGpNfYE/TsUgsbdkEJI/AAAAAAAAAAg/qBmcTFBqbbU/s1600/cloudcontrolxemonitoring.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="169" src="http://1.bp.blogspot.com/-upfssGpNfYE/TsUgsbdkEJI/AAAAAAAAAAg/qBmcTFBqbbU/s320/cloudcontrolxemonitoring.PNG" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;But there is no such thing as a free lunch. XE &lt;a href="http://download.oracle.com/docs/cd/E17781_01/license.112/e18068/toc.htm#BABJIJCJ"&gt;Options and Major Features Not Included ... Tuning Pack&lt;/a&gt;Nice to see that XE 11g installation changes the default control_management_pack_access DIAGNOSTIC+TUNING to NONE by default. It is changed actually with a comment that the default is changed because not an EE installation.&lt;br /&gt;&lt;br /&gt;I would not have guessed before starting to install an agent to end up browsing licensing documentation. Seems like Even in PE:&amp;nbsp;&lt;a href="http://download.oracle.com/docs/cd/E11882_01/license.112/e10594/editions.htm#DBLIC110"&gt;The Management Packs are not included in Personal Edition&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Next to the&amp;nbsp;&lt;a href="http://download.oracle.com/docs/cd/E24628_01/doc.121/e24473/self_update.htm#CACFAIFI"&gt;offline agent loading&lt;/a&gt;&amp;nbsp;and generating&amp;nbsp;&lt;span class="Apple-style-span" style="background-color: white; font-family: monospace; font-size: 12px;"&gt;oracle-agt-12.1.0.1.0-1.0.i386.rpm&amp;nbsp;&lt;/span&gt;as the Cloud Control has only the&amp;nbsp;&lt;span class="Apple-style-span" style="background-color: white; font-family: monospace; font-size: 12px;"&gt;oracle-agt-12.1.0.1.0-1.0.x86_64.rpm&amp;nbsp;&lt;/span&gt;available. As i would like to try out agent installation also to a&amp;nbsp;&lt;span class="Apple-style-span" style="background-color: white; font-family: monospace; font-size: 12px;"&gt;-platform="Linux x86"&amp;nbsp;&lt;/span&gt;Lets see how that goes in the future...&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6865567199579713841?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6865567199579713841/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/11/installing-agent-and-not-free-lunch.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6865567199579713841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6865567199579713841'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/11/installing-agent-and-not-free-lunch.html' title='Installing an agent and not a free lunch'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-upfssGpNfYE/TsUgsbdkEJI/AAAAAAAAAAg/qBmcTFBqbbU/s72-c/cloudcontrolxemonitoring.PNG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-4435591368982711728</id><published>2011-11-03T23:53:00.001+02:00</published><updated>2011-11-04T14:16:37.826+02:00</updated><title type='text'>Information overload</title><content type='html'>More than two days of &lt;a href="http://jonathanlewis.wordpress.com"&gt;Jonathan Lewis&lt;/a&gt; an then some other &lt;a href="http://www.ougf.fi"&gt;Ougf autumn seminar&lt;/a&gt; presentations. Feels like I am a beginner. I actually do not know enough. There is so much to learn about the basics. The change vector in Oracle. To learn the basics today it is much harder to figure out today than ten years ago. There is so many performance improvements disturbing the basic calculation based on numbers in simple tests. &lt;P/&gt;Mark to your calendars two last days at the end of may 2012. There will be a Ougf seminar in Hämeenlinna. Just another time to feel closer as a beginner. And better yet learn things to unlearn...&lt;P/&gt;Well just a tought. Lending an example from Jonathans teaching. Should the bind name be a part to be considered a part of sql text by optimizer?&lt;PRE&gt;&lt;br /&gt;drop table t1;&lt;br /&gt;&lt;br /&gt;drop table t2;&lt;br /&gt;&lt;br /&gt;create table t1(n1 number, n2 number);&lt;br /&gt;&lt;br /&gt;create table t2(n1 number, n2 number);&lt;br /&gt;&lt;br /&gt;create index t1_i1 on t1(n1);&lt;br /&gt;&lt;br /&gt;create index t2_i1 on t2(n1);&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;First without binds.&lt;PRE&gt;&lt;br /&gt; &lt;br /&gt;select t1.n2,t2.n2&lt;br /&gt; from t1, t2&lt;br /&gt; where t1.n1=1&lt;br /&gt;   and t2.n1=1&lt;br /&gt;   and t1.n1=t2.n1&lt;br /&gt;;&lt;br /&gt;select * from table(dbms_xplan.display_cursor(format=&gt;'basic +predicate'));&lt;br /&gt;&lt;br /&gt;EXPLAINED SQL STATEMENT:&lt;br /&gt;------------------------&lt;br /&gt;select t1.n2,t2.n2  from t1, t2  where t1.n1=1    and t2.n1=1    and &lt;br /&gt;t1.n1=t2.n1&lt;br /&gt; &lt;br /&gt;Plan hash value: 1051316565&lt;br /&gt; &lt;br /&gt;-----------------------------------------------&lt;br /&gt;| Id  | Operation                     | Name  |&lt;br /&gt;-----------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT              |       |&lt;br /&gt;|   1 |  NESTED LOOPS                 |       |&lt;br /&gt;|   2 |   NESTED LOOPS                |       |&lt;br /&gt;|   3 |    TABLE ACCESS BY INDEX ROWID| T1    |&lt;br /&gt;|*  4 |     INDEX RANGE SCAN          | T1_I1 |&lt;br /&gt;|*  5 |    INDEX RANGE SCAN           | T2_I1 |&lt;br /&gt;|   6 |   TABLE ACCESS BY INDEX ROWID | T2    |&lt;br /&gt;-----------------------------------------------&lt;br /&gt; &lt;br /&gt;Predicate Information (identified by operation id):&lt;br /&gt;---------------------------------------------------&lt;br /&gt; &lt;br /&gt;   4 - access("T1"."N1"=1)&lt;br /&gt;   5 - access("T1"."N1"="T2"."N1")&lt;br /&gt;       filter("T2"."N1"=1)&lt;br /&gt; &lt;/PRE&gt; Nice looking plan.and now with binds.&lt;PRE&gt;&lt;br /&gt;select t1.n2,t2.n2&lt;br /&gt; from t1, t2&lt;br /&gt; where t1.n1=:b1&lt;br /&gt;   and t2.n1=:b1&lt;br /&gt;   and t1.n1=t2.n1&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;select * from table(dbms_xplan.display_cursor(format=&gt;'basic +predicate'));&lt;br /&gt;&lt;br /&gt;EXPLAINED SQL STATEMENT:&lt;br /&gt;------------------------&lt;br /&gt;select t1.n2,t2.n2  from t1, t2  where t1.n1=:b1    and t2.n1=:b1    &lt;br /&gt;and t1.n1=t2.n1&lt;br /&gt; &lt;br /&gt;Plan hash value: 810726339&lt;br /&gt; &lt;br /&gt;------------------------------------------------&lt;br /&gt;| Id  | Operation                      | Name  |&lt;br /&gt;------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT               |       |&lt;br /&gt;|*  1 |  FILTER                        |       |&lt;br /&gt;|   2 |   MERGE JOIN CARTESIAN         |       |&lt;br /&gt;|   3 |    TABLE ACCESS BY INDEX ROWID | T1    |&lt;br /&gt;|*  4 |     INDEX RANGE SCAN           | T1_I1 |&lt;br /&gt;|   5 |    BUFFER SORT                 |       |&lt;br /&gt;|   6 |     TABLE ACCESS BY INDEX ROWID| T2    |&lt;br /&gt;|*  7 |      INDEX RANGE SCAN          | T2_I1 |&lt;br /&gt;------------------------------------------------&lt;br /&gt; &lt;br /&gt;Predicate Information (identified by operation id):&lt;br /&gt;---------------------------------------------------&lt;br /&gt; &lt;br /&gt;   1 - filter(TO_NUMBER(:B1)=TO_NUMBER(:B1))&lt;br /&gt;   4 - access("T1"."N1"=TO_NUMBER(:B1))&lt;br /&gt;       filter("T1"."N1"=TO_NUMBER(:B1))&lt;br /&gt;   7 - access("T2"."N1"=TO_NUMBER(:B1))&lt;br /&gt;       filter("T2"."N1"=TO_NUMBER(:B1))&lt;br /&gt; &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;select t1.n2,t2.n2&lt;br /&gt; from t1, t2&lt;br /&gt; where t1.n1=1&lt;br /&gt;   and t2.n1=1&lt;br /&gt;   and t1.n1=t2.n1&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;Plan changed. Oracle knows :B1 should be :B1   1 - filter(TO_NUMBER(:B1)=TO_NUMBER(:B1))But why the plan changed? The bind might be null. And NUL is not equalt to NULL. How about sql monitor report.&lt;PRE&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;SQL Monitoring Report&lt;br /&gt;&lt;br /&gt;SQL Text&lt;br /&gt;------------------------------&lt;br /&gt;select /*+monitor*/t1.n2,t2.n2 from t1, t2 where t1.n1=:b1 and t2.n1=:b1 and t1.n1=t2.n1&lt;br /&gt;&lt;br /&gt;Global Information&lt;br /&gt;------------------------------&lt;br /&gt; Status              :  DONE (ALL ROWS)     &lt;br /&gt; Instance ID         :  1                   &lt;br /&gt; Session             :  RAFU (28:21)        &lt;br /&gt; SQL ID              :  dm8z90v1mk8tb       &lt;br /&gt; SQL Execution ID    :  16777217            &lt;br /&gt; Execution Started   :  11/03/2011 13:54:27 &lt;br /&gt; First Refresh Time  :  11/03/2011 13:54:27 &lt;br /&gt; Last Refresh Time   :  11/03/2011 13:54:27 &lt;br /&gt; Duration            :  .002418s            &lt;br /&gt; Module/Action       :  SQL Developer/-     &lt;br /&gt; Service             :  SYS$USERS           &lt;br /&gt; Program             :  SQL Developer       &lt;br /&gt; Fetch Calls         :  1                   &lt;br /&gt;&lt;br /&gt;Binds&lt;br /&gt;========================================================================================================================&lt;br /&gt;| Name | Position |     Type     |                                        Value                                        |&lt;br /&gt;========================================================================================================================&lt;br /&gt;| :B1  |        1 | VARCHAR2(32) | 1                                                                                   |&lt;br /&gt;| :B1  |        2 | VARCHAR2(32) | 1                                                                                   |&lt;br /&gt;========================================================================================================================&lt;br /&gt;&lt;br /&gt;Global Stats&lt;br /&gt;==============================&lt;br /&gt;| Elapsed |  Other   | Fetch |&lt;br /&gt;| Time(s) | Waits(s) | Calls |&lt;br /&gt;==============================&lt;br /&gt;|    0.00 |     0.00 |     1 |&lt;br /&gt;==============================&lt;br /&gt;&lt;br /&gt;SQL Plan Monitoring Details (Plan Hash Value=810726339)&lt;br /&gt;=======================================================================================================================================&lt;br /&gt;| Id |            Operation             | Name  |  Rows   | Cost |   Time    | Start  | Execs |   Rows   | Activity | Activity Detail |&lt;br /&gt;|    |                                  |       | (Estim) |      | Active(s) | Active |       | (Actual) |   (%)    |   (# samples)   |&lt;br /&gt;=======================================================================================================================================&lt;br /&gt;|  0 | SELECT STATEMENT                 |       |         |      |           |        |     1 |          |          |                 |&lt;br /&gt;|  1 |   FILTER                         |       |         |      |           |        |     1 |          |          |                 |&lt;br /&gt;|  2 |    MERGE JOIN CARTESIAN          |       |       1 |    1 |           |        |     1 |          |          |                 |&lt;br /&gt;|  3 |     TABLE ACCESS BY INDEX ROWID  | T1    |       1 |    1 |           |        |     1 |          |          |                 |&lt;br /&gt;|  4 |      INDEX RANGE SCAN            | T1_I1 |       1 |    1 |           |        |       |          |          |                 |&lt;br /&gt;|  5 |     BUFFER SORT                  |       |       1 |      |           |        |       |          |          |                 |&lt;br /&gt;|  6 |      TABLE ACCESS BY INDEX ROWID | T2    |       1 |      |           |        |       |          |          |                 |&lt;br /&gt;|  7 |       INDEX RANGE SCAN           | T2_I1 |       1 |      |           |        |       |          |          |                 |&lt;br /&gt;=======================================================================================================================================&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;B1 is named nicely. But through jdbc seems like the bind variable naming is lost at some point. A named bind becomes named like :B1 and :B2 all thou there was only one name while binding.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-4435591368982711728?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/4435591368982711728/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/11/information-overload.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/4435591368982711728'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/4435591368982711728'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/11/information-overload.html' title='Information overload'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-8755480535212023700</id><published>2011-10-31T16:05:00.000+02:00</published><updated>2011-10-31T16:28:04.965+02:00</updated><title type='text'>Variable inlist</title><content type='html'>There comes every now and then discussions about how to pass varying in list to a SQL statement as a single bind. Just currently there is such discussion going on at &lt;a href="http://www.freelists.org/post/oracle-l/Large-IN-LIST-in-an-OBIEE-query"&gt;oracle-l mailing list "Large IN LIST in an OBIEE query"&lt;/a&gt;. Also several discussions may be found in &lt;a href="http://forums.oracle.com/"&gt;Oracle discussion forums&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;One problem with these varying in lists is that the SQL query is different for every amount of values passed to an in list.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;where col in (?,?);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;where col in (?,?,?);&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;Another problem is that an in list accepts only 1000 different values. This may be overcome using OR:&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;where col in (?,?,...,?) --1000 placeholders&lt;br /&gt;       or col in (?,?,...,?) --1000 placeholders&lt;br /&gt;       or col in (?,?,?);&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;But that is just plain old stupid. It seems to be the thing that comes to a developers mind first. As the approach is seen too often.&lt;br /&gt;&lt;br /&gt;All kinds of single string passing approaches can be found using Google. With those there is an issue of maximum length 4000 bytes of varchar2 datatype.&lt;br /&gt;&lt;br /&gt;One approach is to create an temp table, populate that before executing a query and using the temp table as a normal table in the query. Problems: Two round trips to the database. How to populate the temp table efficiently.&lt;br /&gt;&lt;br /&gt;It was two years ago I attended Tanel Poder Advanced Oracle Troubleshooting Seminar. He mentioned an approach using SQL Collection types and table function to implement the varying inlist with just one bind. Actually seems like he is having his seminar starting just today&lt;a href="http://blog.tanelpoder.com/seminar/"&gt;http://blog.tanelpoder.com/seminar/&lt;/a&gt;. Lucky you attending. This week I will have a pleasure to attend Jonathan Lewis seminar in Helsinki.&lt;br /&gt;&lt;br /&gt;Just a bit earlier I wrote about how to populate a table efficiently &lt;a href="http://rafudb.blogspot.com/2009/08/load-using-java.html"&gt;using Java&lt;/a&gt;. This approach may be used to populate the temp table. But why do that when you can do it all in a single call as Tanel described.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;create type numbers is table of number;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;And Map the NUMBERS type to  ArrayDescriptor.createDescriptorA test java source &lt;a href="http://iki.fi/rafu/rafuondb/inlist.java"&gt;inlist.java&lt;/a&gt;. &lt;pre&gt;&lt;br /&gt;&lt;br /&gt;        ArrayDescriptor ad = ArrayDescriptor.createDescriptor("NUMBERS", c);&lt;br /&gt;        ARRAY a = new ARRAY(ad, c, elems.toArray());&lt;br /&gt;        OraclePreparedStatement ops &lt;br /&gt;          = (OraclePreparedStatement)c.prepareStatement(&lt;br /&gt;                 "select /*+gather_plan_statistics*/ count(*) cou"+&lt;br /&gt;                 "   from inlist_test "+&lt;br /&gt;                 "  where num in ( " +&lt;br /&gt;                 "        select column_value " +&lt;br /&gt;                 "          from table(?))");&lt;br /&gt;        ops.setARRAY(1, a);&lt;br /&gt;&lt;br /&gt;        ResultSet rs = ops.executeQuery();&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;This approach works also for another types of Collections Dates, Strings and so . Just create own table of type for each needed. Readily availabel SYS.ODCINUMBERLIST seems to be safe to use with Collections smaller than about 32k. So no additional database objects need to be greated.&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;ArrayDescriptor ad = ArrayDescriptor.createDescriptor("SYS.ODCINUMBERLIST", c);&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;One problem in the discussions have been how the optimizer sees the cardinalities of the collection. Here are three different plans from 11.2.0.2 depending on the Collection and table size. As you can see quite large collections may be passed to the database using this technique. Plan 1497893883 is generated using one million numbers in the inlist. With large Collections be aware of the memory consumption I mentioned in the &lt;a href="http://rafudb.blogspot.com/2009/08/load-using-java.html"&gt;using Java&lt;/a&gt; post.&lt;pre&gt;&lt;br /&gt;SQL_ID  fzb8ysr291xz3, child number 0&lt;br /&gt;-------------------------------------&lt;br /&gt;select /*+gather_plan_statistics*/ count(*) cou   from inlist_test   &lt;br /&gt;where num in (         select column_value           from table(:1 ))&lt;br /&gt; &lt;br /&gt;Plan hash value: 4131715231&lt;br /&gt; &lt;br /&gt;----------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation                           | Name        | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |&lt;br /&gt;----------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT                    |             |      1 |        |      1 |00:00:00.01 |       3 |       |       |          |&lt;br /&gt;|   1 |  SORT AGGREGATE                     |             |      1 |      1 |      1 |00:00:00.01 |       3 |       |       |          |&lt;br /&gt;|*  2 |   HASH JOIN SEMI                    |             |      1 |      1 |     24 |00:00:00.01 |       3 |  1517K|  1517K| 1308K (0)|&lt;br /&gt;|   3 |    TABLE ACCESS FULL                | INLIST_TEST |      1 |     99 |     99 |00:00:00.01 |       3 |       |       |          |&lt;br /&gt;|   4 |    COLLECTION ITERATOR PICKLER FETCH|             |      1 |     25 |     25 |00:00:00.01 |       0 |       |       |          |&lt;br /&gt;----------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;Plan hash value: 1497893883&lt;br /&gt; &lt;br /&gt;-------------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation                           | Name        | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |&lt;br /&gt;-------------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT                    |             |      1 |        |      1 |00:00:01.15 |    1528 |   1262 |       |       |          |&lt;br /&gt;|   1 |  SORT AGGREGATE                     |             |      1 |      1 |      1 |00:00:01.15 |    1528 |   1262 |       |       |          |&lt;br /&gt;|*  2 |   HASH JOIN RIGHT SEMI              |             |      1 |      1 |    999K|00:00:04.22 |    1528 |   1262 |    34M|  6431K|   48M (0)|&lt;br /&gt;|   3 |    COLLECTION ITERATOR PICKLER FETCH|             |      1 |   1000K|   1000K|00:00:00.71 |       0 |      0 |       |       |          |&lt;br /&gt;|   4 |    TABLE ACCESS FULL                | INLIST_TEST |      1 |    893K|    999K|00:00:00.69 |    1528 |   1262 |       |       |          |&lt;br /&gt;-------------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt; &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;Plan hash value: 2750379354&lt;br /&gt; &lt;br /&gt;--------------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation                            | Name        | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |&lt;br /&gt;--------------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT                     |             |      1 |        |      1 |00:00:00.45 |    1528 |   1262 |       |       |          |&lt;br /&gt;|   1 |  SORT AGGREGATE                      |             |      1 |      1 |      1 |00:00:00.45 |    1528 |   1262 |       |       |          |&lt;br /&gt;|*  2 |   HASH JOIN                          |             |      1 |   3125 |  99999 |00:00:00.44 |    1528 |   1262 |  3749K|  1936K| 5625K (0)|&lt;br /&gt;|   3 |    SORT UNIQUE                       |             |      1 |    100K|    100K|00:00:00.11 |       0 |      0 |  4588K|   893K| 4078K (0)|&lt;br /&gt;|   4 |     COLLECTION ITERATOR PICKLER FETCH|             |      1 |    100K|    100K|00:00:00.07 |       0 |      0 |       |       |          |&lt;br /&gt;|   5 |    TABLE ACCESS FULL                 | INLIST_TEST |      1 |    893K|    999K|00:00:00.68 |    1528 |   1262 |       |       |          |&lt;br /&gt;--------------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt; &lt;br /&gt;Predicate Information (identified by operation id):&lt;br /&gt;---------------------------------------------------&lt;br /&gt; &lt;br /&gt;   2 - access("NUM"=VALUE(KOKBF$))&lt;br /&gt; &lt;br /&gt;Note&lt;br /&gt;-----&lt;br /&gt;   - dynamic sampling used for this statement (level=2)&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-8755480535212023700?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/8755480535212023700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/10/variable-inlist.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8755480535212023700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8755480535212023700'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/10/variable-inlist.html' title='Variable inlist'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-9201282685008585500</id><published>2011-10-25T19:27:00.000+03:00</published><updated>2011-10-25T19:27:33.384+03:00</updated><title type='text'>Congratulations to the winners</title><content type='html'>I received just an email from Iggy Fernandez. My &lt;a href="http://rafudb.blogspot.com/2011/02/nocoug-second-sql-challenge.html"&gt;answer&lt;/a&gt; was not in the set of winners.  Congratulations to all three. The challenge might be nice rehearsal to solve using Spatial Network Data Model SQL extension. The email as received:&lt;br /&gt;&lt;br /&gt;The Second International NoCOUG SQL Challenge was published on 2/13/11 in the February 2011 issue of the &lt;em&gt;NoCOUG Journal&lt;/em&gt; (&lt;a href="http://bit.ly/gVNZsW" target="_blank"&gt;&lt;span style="color: #0068cf;"&gt;http://bit.ly/gVNZsW&lt;/span&gt;&lt;/a&gt;). SQL commands to create the data were provided at &lt;a href="http://bit.ly/g58WVn" target="_blank"&gt;&lt;span style="color: #0068cf;"&gt;http://bit.ly/g58WVn&lt;/span&gt;&lt;/a&gt;. The challenge was to find the secret message hidden in a seemingly random collection of words. &lt;span style="color: red;"&gt;&lt;strong&gt;The winners are Andre Araujo (Australia), Rob van Wijk (Netherlands), and Ilya Chuhnakov (Russia.)&lt;/strong&gt;&lt;/span&gt; Each winner will receive an Amazon Kindle from contest sponsor Pythian and the August Order of the Wooden Pretzel in keeping with the pronouncement of Steven Feuerstein that&lt;em&gt;“some people can perform seeming miracles with straight Es-Cue-El, but the statements end up looking like pretzels created by somebody who is experimenting with hallucinogens.”&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;The full announcement can be read in the 100th issue of the &lt;em&gt;NoCOUG Journal&lt;/em&gt; (&lt;a href="http://bit.ly/rC2gRA" target="_blank"&gt;&lt;span style="color: #0068cf;"&gt;http://bit.ly/rC2gRA&lt;/span&gt;&lt;/a&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-9201282685008585500?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/9201282685008585500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/10/congratulations-to-winners.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/9201282685008585500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/9201282685008585500'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/10/congratulations-to-winners.html' title='Congratulations to the winners'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-7983452629727648965</id><published>2011-10-21T15:30:00.004+03:00</published><updated>2011-10-21T15:33:49.086+03:00</updated><title type='text'>How many function calls and sysdate evaluated</title><content type='html'>Talking here about function calls and when sysdate is evaluated. Starting with a silly function f2 that takes a second to execute and a session that shows only the seconds out of a date type.&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; alter session set nls_date_format='ss';&lt;br /&gt;&lt;br /&gt;Session altered.&lt;br /&gt;&lt;br /&gt;SQL&gt; create or replace function f2( x in date ) return date&lt;br /&gt;  2    as&lt;br /&gt;  3    begin&lt;br /&gt;  4            dbms_lock.sleep(1);&lt;br /&gt;  5            return x;&lt;br /&gt;  6    end;&lt;br /&gt;  7  /&lt;br /&gt;&lt;br /&gt;Function created.&lt;br /&gt;&lt;br /&gt;SQL&gt; select a a, a b from (select f2(sysdate) a from dual);&lt;br /&gt;&lt;br /&gt;A  B&lt;br /&gt;-- --&lt;br /&gt;37 37&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:02.02&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;Written a query that uses the function once. And seems like sysdate is evaluated at the main query and it returns the same value for both a and b. But how come the execution time is two seconds?From the optimizer trace can be seen that the query is transformed to have two calls to the function. That explains the execution time.&lt;PRE&gt;&lt;br /&gt;Final query after transformations:******* UNPARSED QUERY IS *******&lt;br /&gt;SELECT "RAFU"."F2"() "A","RAFU"."F2"() "B" FROM "SYS"."DUAL" "DUAL"&lt;br /&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; select f2(sysdate) a, f2(sysdate) b from dual;&lt;br /&gt;&lt;br /&gt;A  B&lt;br /&gt;-- --&lt;br /&gt;39 39&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:02.02&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;Similar result. Lets change the function to have its own cursor.&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; create or replace function f3 return date&lt;br /&gt;  2    as&lt;br /&gt;  3    x date;&lt;br /&gt;  4    begin&lt;br /&gt;  5            dbms_lock.sleep(1);&lt;br /&gt;  6            select sysdate into x from dual;&lt;br /&gt;  7            return x;&lt;br /&gt;  8    end;&lt;br /&gt;  9  /&lt;br /&gt;&lt;br /&gt;Function created.&lt;br /&gt;&lt;br /&gt;SQL&gt; select a a, a b from (select f3() a from dual);&lt;br /&gt;&lt;br /&gt;A  B&lt;br /&gt;-- --&lt;br /&gt;42 43&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:02.02&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;Execution time the same and the result changed. The sysdate is evaluated at the time cursor in the function is called. Remember the query transformation. The transformation may be avoided and the function is called actually only once. &lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; select a a, a b from (select /*+no_merge*/ f3() a from dual);&lt;br /&gt;&lt;br /&gt;A  B&lt;br /&gt;-- --&lt;br /&gt;54 54&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:03.01&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;Be aware query transformations may lead to changing query results when function are mixed in a query.How about transaction isolation. Does that have influence on the issue when the function is called twice. So is the sysdate behaving like changing rownum. The changing rownum is talked in &lt;a href="http://laurentschneider.com/wordpress/2011/09/on-using-rowid.html"&gt;Laurent Schneider&lt;/a&gt; blog and comments there.&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; set transaction read only;&lt;br /&gt;&lt;br /&gt;Transaction set.&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:00.00&lt;br /&gt;SQL&gt; SELECT F3() A,F3() B FROM DUAL;&lt;br /&gt;&lt;br /&gt;A  B&lt;br /&gt;-- --&lt;br /&gt;03 04&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:02.01&lt;br /&gt;SQL&gt; rollback;&lt;br /&gt;&lt;/PRE&gt;The sysdate is not respecting the read only setting on the transaction but it is getting its value just when asked.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-7983452629727648965?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/7983452629727648965/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/10/how-many-function-calls-and-sysdate.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7983452629727648965'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7983452629727648965'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/10/how-many-function-calls-and-sysdate.html' title='How many function calls and sysdate evaluated'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-7458877162939150934</id><published>2011-09-28T11:40:00.001+03:00</published><updated>2011-09-28T11:40:34.533+03:00</updated><title type='text'>New package DBMS_XPAN?</title><content type='html'>Is this humor from error message writer?&lt;PRE&gt;&lt;br /&gt;SQL&gt; select * from table(dbms_xplan.display_cursor(format=&gt;'allsts'));&lt;br /&gt;&lt;br /&gt;PLAN_TABLE_OUTPUT&lt;br /&gt;----------------------------------------------------------------------&lt;br /&gt;Error: format 'allsts' not valid for DBMS_XPAN.DISPLAY_CURSOR()&lt;br /&gt;&lt;/PRE&gt; &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-7458877162939150934?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/7458877162939150934/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/09/new-package-dbmsxpan.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7458877162939150934'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7458877162939150934'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/09/new-package-dbmsxpan.html' title='New package DBMS_XPAN?'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-5097704692957163897</id><published>2011-09-27T15:34:00.001+03:00</published><updated>2011-09-27T15:34:12.325+03:00</updated><title type='text'>Migrating to 11.2.0.3 ORA-00976</title><content type='html'>You can have exists even in join condition in addition to what &lt;a href="http://rwijk.blogspot.com/2011/09/exists.html"&gt;Rob Van Wijk&lt;/a&gt; has writen. We have code lines that has such exists together with an connect by query.Patching an 11.2.0.2 database to 11.2.0.3In 11.2.0.2 one can run such a query. Here is one stupid example of such.&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;select d2.dummy from dual d1 left outer join dual d2 on exists (select 1 from dual connect by level &lt; 3); &lt;br /&gt;&lt;br /&gt;D&lt;br /&gt;-&lt;br /&gt;X&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;In 11.2.0.3 you get an error thrown to your face.&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;ORA-00976: Specified pseudocolumn or operator not allowed here.&lt;br /&gt;Cause: LEVEL, PRIOR, ROWNUM, CONNECT_BY_ROOT, CONNECT_BY_ISLEAF or CONNECT_BY_ISCYCLE was specified at an illegal location.&lt;br /&gt;Action: Remove LEVEL, PRIOR, ROWNUM, CONNECT_BY_ROOT, CONNECT_BY_ISLEAF or CONNECT_BY_ISCYCLE.&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;The query may be rewritten like 11.2.0.3 parser is satisfied.&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;with cte as (select 1 from dual connect by level &lt; 3)&lt;br /&gt;select d2.dummy from dual d1 left outer join dual d2 on exists (select 1 from cte);&lt;br /&gt;&lt;br /&gt;D&lt;br /&gt;-&lt;br /&gt;X&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;This is a runtime problem. Run your tests before patching production. Actually this is not just a runtime problem. We had the code inside a pl/sql procedure. The procedure is valid in 11.2.0.2 environment. After patching the procedure is still valid just waiting for the next compile or runtime problem of this code.Well there is most certainly a reason for such problem appearing. Might this be a side affect for a Bug correction 8724314 mentioned in &lt;a href="https://supporthtml.oracle.com/ep/faces/secure/km/DocumentDisplay.jspx?id=1348303.1"&gt;11.2.0.3 Patch Set - List of Bug Fixes by Problem Type [ID 1348303.1]&lt;/a&gt;. Might this usage of common table expression workaround be just a next bug waiting to appear.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-5097704692957163897?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/5097704692957163897/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/09/migrating-to-11203-ora-00976.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5097704692957163897'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5097704692957163897'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/09/migrating-to-11203-ora-00976.html' title='Migrating to 11.2.0.3 ORA-00976'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-5006826147133180415</id><published>2011-09-26T11:39:00.000+03:00</published><updated>2011-09-26T11:39:07.317+03:00</updated><title type='text'>11.2.0.3</title><content type='html'>&lt;span class="Apple-style-span" style="background-color: white; font-family: Tahoma, Arial, Helvetica, sans-serif; font-size: 13px; white-space: nowrap;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;h2 class="ml3SmallPanelHeader" style="color: black; font-size: 14px; margin-bottom: 0px; margin-top: 0px; text-decoration: none; vertical-align: middle;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit; font-weight: normal;"&gt;Just downloading Patch 10404530: 11.2.0.3.0 PATCH SET FOR ORACLE DATABASE SERVER&lt;/span&gt;&lt;/h2&gt;&lt;div&gt;&lt;br /&gt;Patches are correcting bugs and adding new features. I guess that there is a new value to &amp;nbsp;OPTIMIZER_FEATURES_ENABLED parameter coming.&lt;br /&gt;&lt;br /&gt;Time to unlearn. Tom Kyte talked at Oug Harmony 2011 last spring about caching inside a SQL query. He wrote about the same topic in &lt;a href="http://www.oraclemagazine-digital.com/oraclemagazine/20110910/?sub_id=beGSTRFSCDr5#pg77"&gt;Oracle Magazine september 2011&lt;/a&gt;. The thing seems like a candidate to be implemented in Oracle SQL engine in some future release. (I guess not yet in this 11.2.0.3). Just when a wide developer audience has learned to wrap pl/sql funtion calls inside a query to avoid multiple calls.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;The thing to be unlearned might be a bug. Causing something not to perform or do wrong behavior in certain version. In some future version the bug might&amp;nbsp;be corrected and the workaround becomes obsolete. &amp;nbsp;These are currently most often details that influence some specific situation. If you want to know the basics and more. Jonathan Lewis is comig to Finland this autumn. A two day learning session is available. Optimizing Oracle 1.-2.11.2011. And in addition Oracle User Group Finland autumn seminar 3.11.2011 seems to have pleasure to have his presentation. Agenda and registration information available to both at &lt;a href="http://www.ougf.fi/"&gt;http://www.ougf.fi/&lt;/a&gt; A lot guess working in this post. To avoid that attend.&lt;/div&gt;&lt;div&gt;&lt;div style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-5006826147133180415?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/5006826147133180415/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/09/11203.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5006826147133180415'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5006826147133180415'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/09/11203.html' title='11.2.0.3'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-1311762845027070301</id><published>2011-09-21T16:58:00.001+03:00</published><updated>2011-09-21T16:58:47.534+03:00</updated><title type='text'>Avoid temp usage while table reorg</title><content type='html'>Richard Foote blog is having questioning posts. Thanks to &lt;a href="http://richardfoote.wordpress.com/2011/09/19/big-tables-sorts-and-indexes-solution-right-on-mother/"&gt;the latest solution&lt;/a&gt; there we have a possible alternative while reorganizing a huge table.Just hit an "ORA-01652: unable to extend temp segment by 64 in tablespace TEMP" problem while doing table reorganization.Who and what sql is &lt;a href="http://rafudb.blogspot.com/2009/12/sql-tuning-reading-plans-and-temp-usage.html"&gt;consuming temp&lt;/a&gt; helps identifying the problem statement.&lt;br /&gt;&lt;pre&gt;insert /*+append*/ into targettable select * from sourcetable order by sortcolumn;&lt;br /&gt;&lt;/pre&gt;The source table has an index on sortcolumn. Using that it is possible to avoid sorting and temp usage.&lt;br /&gt;&lt;pre&gt;insert /*+append*/ into targettable select /*+index(sourcetable sortcolumn_idx)*/ * from sourcetable order by sortcolumn;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-1311762845027070301?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/1311762845027070301/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/09/avoid-temp-usage-while-table-reorg.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/1311762845027070301'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/1311762845027070301'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/09/avoid-temp-usage-while-table-reorg.html' title='Avoid temp usage while table reorg'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-3035592665354794526</id><published>2011-09-01T11:55:00.003+03:00</published><updated>2011-09-01T12:15:26.107+03:00</updated><title type='text'>Password expiring</title><content type='html'>&lt;br /&gt;Yet again... &lt;br /&gt;A new 181 days ago created 11g database instance... &lt;br /&gt;A software connection pool user is not allowed to connect to the database...&lt;br /&gt;&lt;br /&gt;ORA-28002: the password will expire within 7 days&lt;br /&gt;OR&lt;br /&gt;ORA-28001: the password has expired&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;select profile from dba_users where username = 'POOLUSER';&lt;br /&gt;&lt;br /&gt;DEFAULT&lt;br /&gt;&lt;br /&gt;create profile pool_profile limit PASSWORD_LIFE_TIME unlimited;&lt;br /&gt;&lt;br /&gt;alter user pooluser profile pool_profile; &lt;br /&gt;&lt;br /&gt;select profile from dba_users where username = 'POOLUSER';&lt;br /&gt;&lt;br /&gt;POOL_PROFILE&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-3035592665354794526?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/3035592665354794526/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/09/password-expiring.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3035592665354794526'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3035592665354794526'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/09/password-expiring.html' title='Password expiring'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-1668665673694275449</id><published>2011-08-16T17:26:00.003+03:00</published><updated>2011-08-16T17:34:27.846+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Developer'/><title type='text'>set role</title><content type='html'>Trying to get autotrace out of SQL Developer and getting error message.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;Failed to access V$MYSTAT.&lt;br /&gt;Please obtain read catalog privilege&lt;br /&gt;from your database administrator:&lt;br /&gt;grant SELECT_CATALOG_ROLE to RAFU&lt;br /&gt;grant SELECT ANY DICTIONARY toRAFU&lt;br /&gt;NOTE: you need to reconnect your current session&lt;br /&gt;in order for the settings change to have an effect&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Granted the privileges. I guess less would be enough. Weird note. Why do I need to reconnect the session? There exists SET ROLE command.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SET ROLE ALL;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;That does the job. No reconnect needed.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-1668665673694275449?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/1668665673694275449/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/08/set-role.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/1668665673694275449'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/1668665673694275449'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/08/set-role.html' title='set role'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-7704938599021896312</id><published>2011-08-10T09:54:00.002+03:00</published><updated>2011-08-10T10:47:40.121+03:00</updated><title type='text'>Crabby code</title><content type='html'>&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;ORA-00020: maximum number of processes 500 exceeded&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Connections are using DEDICATED connections. The pooling is done in the middle tier. Several pools. Connection leakage is not a database fault but it becomes to a everybody problem. While figuring out the problem, I managed to produce a following 10046 SQL trace.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;ERROR #1:err=12899 tim=1312894876206660&lt;br /&gt;WAIT #1: nam='SQL*Net break/reset to client' ela= 20 driver id=675562835 break?=1 p3=0 obj#=-1 tim=1312894876206740&lt;br /&gt;WAIT #1: nam='SQL*Net break/reset to client' ela= 303 driver id=675562835 break?=0 p3=0 obj#=-1 tim=1312894876207059&lt;br /&gt;WAIT #1: nam='SQL*Net message to client' ela= 2 driver id=675562835 #bytes=1 p3=0 obj#=-1 tim=1312894876207098&lt;br /&gt;WAIT #1: nam='SQL*Net message from client' ela= 247133 driver id=675562835 #bytes=1 p3=0 obj#=-1 tim=1312894876454273&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Using the Oracle friendly &lt;a href="http://www.miracleoy.fi/search"&gt;search&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Talking about SQL*Net break/reset to client events &lt;a href="http://blog.tanelpoder.com/2008/04/10/sqlnet-breakreset-to-client/"&gt;Tanel Poder&lt;/a&gt; mentions &lt;span style="font-style:italic;"&gt;these breaks are caused by bad application design&lt;/span&gt;. This is something I was trying to find out, but he is talking about MERGE statements. My trace included only inserts.  &lt;br /&gt;&lt;br /&gt;In the &lt;a href="http://www.adellera.it/xtrace/manual/xtrace_manual.html"&gt;Xtrace manual&lt;/a&gt; it is mentioned  &lt;span style="font-style:italic;"&gt;"err" being equal to 12899 (ORA-12899 is "value too large for column"):&lt;/span&gt; That makes sense.&lt;br /&gt;&lt;br /&gt;Luckily I had taken the trace with binds. And could point out the actual column causing the root problem. Only the first 255 characters of the bind values seems to be populated to the trace. The problem column was larger in this case. Using My Oracle support page &lt;a href="https://supporthtml.oracle.com/ep/faces/secure/km/DocumentDisplay.jspx?id=39817.1&amp;h=Y"&gt;Interpreting Raw SQL_TRACE and DBMS_SUPPORT.START_TRACE output [ID 39817.1]&lt;/a&gt; it is possible to read the trace. In the bind part &lt;span style="font-style:italic;"&gt;avl	        Actual value length (array length too).&lt;/span&gt;. Compared that to the column size at the position of the bind in the insert statement and the root problem was found. &lt;br /&gt;&lt;br /&gt;About bad application design &lt;br /&gt; * The application should know how long values can be inserted to each column. &lt;br /&gt; * If the application receives an error it should have an error handler that releases the reserved resources. This time the unreleased resource was a database connection.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-7704938599021896312?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/7704938599021896312/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/08/crabby-code.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7704938599021896312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7704938599021896312'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/08/crabby-code.html' title='Crabby code'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-8505811359298906658</id><published>2011-06-09T00:07:00.007+03:00</published><updated>2011-06-09T02:34:57.565+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='11.2'/><category scheme='http://www.blogger.com/atom/ns#' term='case-insensitive'/><title type='text'>Major</title><content type='html'>Today I did something Donald Duck would do. A couple years ago I built a house. Here are two doors to leave the house, one in front and also a back door. There are wooden stairs in the front door and a wooden terrace outside the back door. I just oiled the front stairs and just after that continued oiling at the back terrace. Now I am stuck inside for a while. It is time to open a beer and think of something else done today. &lt;a href="http://www.karhu.fi/"&gt;Karhu&lt;/a&gt; has some virtual fishing to do. &lt;br /&gt;&lt;br /&gt;Julian Dontcheff mentioned a while ago about &lt;a href="http://juliandontcheff.wordpress.com/2011/05/05/patching-the-11-2-0-2-database/"&gt;11.2.0.2 that it should actually be called 11R3&lt;/a&gt;.  I was reading my oracle support. The issue in my spontaneous online demonstration in &lt;a href="http://rafudb.blogspot.com/2011/05/oug-harmony-2011.html"&gt;What is bugging me&lt;/a&gt; presentation is noticed. My demonstration was about "No results with function based indexes and OR expansion". Now there is a document in MOS "Things to Consider Before Upgrade to 11.2.0.2 Database Performance [ID 1320966.1]" updated 7.6.2011. On off patch is recommended as Oracle does not want to interfere optimizer with CPU or PSU patching. The fifth number in the version numbering. So are those four letters actually something that should be considered major version. Well 11.2.0.2 has so many other changes than the optimizer ones that it could be a 11R3. Just see the list of new features in 11.2.0.2 list in the documentation. &lt;a href="http://download.oracle.com/docs/cd/E11882_01/server.112/e17110/initparams164.htm#REFRN10141"&gt;OPTIMIZER_FEATURES_ENABLED&lt;/a&gt; It has already been from version 10.1.0.3 and 9.2.0.8 that the fourth number have had a meaning. Actually 11.2.0.2 is missing there. Yet another place to submit a user comment about the documentation. &lt;br /&gt;&lt;br /&gt;While writing this post it seems like the 1320966.1 document is vanishing or is it just something about the flashy interface... The patch recommended to install was 9776940. Contact support before installing... Another thing mentioned there was the 11.2.0.3 patchset due out later this year.&lt;br /&gt;&lt;br /&gt;Yet another thing. During last week there has been a slight peak in the visitor count of my blog. After Jonathan Lewis has made an &lt;a href="http://jonathanlewis.wordpress.com/2011/06/03/merge-argh/"&gt;Argh!&lt;/a&gt; issue about &lt;a href="http://rafudb.blogspot.com/2011/03/merge-ignores-check-constraint.html"&gt;merge ignores check constraint&lt;/a&gt; and someone linking that post to his pages. Yes it actually is an Argh issue. &lt;br /&gt;&lt;br /&gt;Actually yet another Argh! issue might be visualized as a snip &lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-UzKeaO_e_Fo/TfABNq9lwUI/AAAAAAAAAAY/z2_AbH_MteY/s1600/developmentworking.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 167px; height: 14px;" src="http://2.bp.blogspot.com/-UzKeaO_e_Fo/TfABNq9lwUI/AAAAAAAAAAY/z2_AbH_MteY/s320/developmentworking.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5615990069713551682" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-8505811359298906658?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/8505811359298906658/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/06/major.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8505811359298906658'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8505811359298906658'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/06/major.html' title='Major'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-UzKeaO_e_Fo/TfABNq9lwUI/AAAAAAAAAAY/z2_AbH_MteY/s72-c/developmentworking.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-5865753869913724466</id><published>2011-05-20T17:04:00.003+03:00</published><updated>2011-05-20T18:35:14.640+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ougf; sql'/><title type='text'>OUG Harmony 2011</title><content type='html'>Just going home from OUG Harmony seminar. I took the room of a cancelled session and gave a presentation that I put together after Thursday dinner. I tittled the presentation "What is bugging me". So satisfied with other presentations I attended. Eg now I know indexing possibilities in MySQL. &lt;br /&gt;&lt;br /&gt;In my presentation I got to show an email from my report on oracle documentation. The issue Tom Kyte mentioned in his keynote speak. There is a feedback possibility in every page in online documentation pages. It is working as Tom mentioned.&lt;br /&gt;&lt;br /&gt;Also mentioned beta testing possibility. Currently &lt;a href="http://rafudb.blogspot.com/2011/04/112-xe-beta.html"&gt;11.2 XE&lt;/a&gt; available.&lt;br /&gt;&lt;br /&gt;One issue was dealing with ora_rowscn. I noticed that my oracle support pages does have only one workaround to a Bug 9360157: WRONG RESULTS WHEN USING ORA_ROWSCN PSEUDOCOLUMN USING ANSI JOIN&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The buggy way:&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;select dep.n,dep.ora_rowscn  &lt;br /&gt;  from testnorowdep nodep  &lt;br /&gt; &lt;span style="font-weight:bold;"&gt;inner join&lt;/span&gt; testrowdep dep on dep.n=nodep.n&lt;br /&gt; &lt;span style="font-weight:bold;"&gt; where&lt;/span&gt; dep.&lt;span style="font-weight:bold;"&gt;ora_rowscn&lt;/span&gt; &gt; :scn ; &lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;The mentioned workaround SQL 92 join way - do not use ansi join.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;select dep.n,dep.ora_rowscn  &lt;br /&gt;  from testnorowdep nodep  , testrowdep dep  &lt;br /&gt; where dep.n=nodep.n &lt;br /&gt;   and dep.ora_rowscn &gt; :scn;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;An additional workaround - use ora_scn in join condition&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;  select dep.n,dep.ora_rowscn &lt;br /&gt;   from testnorowdep nodep  &lt;br /&gt; inner join testrowdep dep &lt;br /&gt;    on dep.n=nodep.n &lt;br /&gt;   &lt;span style="font-weight:bold;"&gt; and&lt;/span&gt; dep.ora_rowscn &gt; :scn;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-5865753869913724466?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/5865753869913724466/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/05/oug-harmony-2011.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5865753869913724466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5865753869913724466'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/05/oug-harmony-2011.html' title='OUG Harmony 2011'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6901362440940203021</id><published>2011-05-09T17:39:00.002+03:00</published><updated>2011-05-09T17:47:15.240+03:00</updated><title type='text'>BAUD</title><content type='html'>&lt;a href="http://rafudb.blogspot.com/2011/04/date-variable-in-sqlplus.html"&gt;Earlier &lt;/a&gt; I wrote about sqlplus client tool and date datatype. This post is about presenting dates. &lt;br /&gt;&lt;br /&gt;"BAUD: Battle against Unclear Dataformats" &lt;a href="https://twitter.com/pdevisser"&gt;Piet de Visser&lt;/a&gt; commenting on &lt;a href="http://twitter.com/alexgorbachev"&gt;Alex Gorbachev&lt;/a&gt; tweet&lt;br /&gt;"In the times of total globalization why people still battle with different date formats like 02/03/11 vs 03/02/11 - solution is 03-Feb-2011"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The solution is not alone 03-Feb-2011. NLS_LANGUAGE or NLS_DATE_LANGUAGE need to be fixed also.&lt;br /&gt;&lt;br /&gt;Let us assume your date string is 03-Mar-2011. It might be that your session is talking POLISH.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; alter session set nls_date_format='yyyy-mm-dd';&lt;br /&gt;&lt;br /&gt;SQL&gt; alter session set nls_language='POLISH';&lt;br /&gt;&lt;br /&gt;SQL&gt; select to_date('01-mar-2011','dd-mon-yyyy') from dual;&lt;br /&gt;&lt;br /&gt;2011-03-01&lt;br /&gt;&lt;br /&gt;SQL&gt; alter session set nls_language='AMERICAN';&lt;br /&gt;&lt;br /&gt;SQL&gt; select to_date('01-mar-2011','dd-mon-yyyy') from dual;&lt;br /&gt;&lt;br /&gt;2011-03-01&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Ok that is fine. But if your data is in POLISH and you just happen to read a string in CROATIAN...&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; select to_date('01-lip-2011','dd-mon-yyyy','NLS_DATE_LANGUAGE=CROATIAN') from dual;&lt;br /&gt;&lt;br /&gt;2011-06-01&lt;br /&gt;&lt;br /&gt;SQL&gt; select to_date('01-lip-2011','dd-mon-yyyy','NLS_DATE_LANGUAGE=POLISH') from dual;&lt;br /&gt;&lt;br /&gt;2011-07-01&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;There are also another similar month abbreviations that may be converted to different months depending on language.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; alter session set nls_date_format='yyyy-mm-dd';&lt;br /&gt;&lt;br /&gt;SQL&gt; select to_date('01-lis-2011','dd-mon-yyyy','NLS_DATE_LANGUAGE=CROATIAN') from dual;&lt;br /&gt;&lt;br /&gt;2011-10-01&lt;br /&gt;&lt;br /&gt;SQL&gt; select to_date('01-lis-2011','dd-mon-yyyy','NLS_DATE_LANGUAGE=CZECH') from dual;&lt;br /&gt;&lt;br /&gt;2011-11-01&lt;br /&gt;&lt;br /&gt;SQL&gt; select to_date('01-lis-2011','dd-mon-yyyy','NLS_DATE_LANGUAGE=POLISH') from dual;&lt;br /&gt;&lt;br /&gt;2011-11-01&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; select to_date('01-srp-2011','dd-mon-yyyy','NLS_DATE_LANGUAGE=CROATIAN') from dual;&lt;br /&gt;&lt;br /&gt;2011-07-01&lt;br /&gt;&lt;br /&gt;SQL&gt; select to_date('01-srp-2011','dd-mon-yyyy','NLS_DATE_LANGUAGE=CZECH') from dual;&lt;br /&gt;&lt;br /&gt;2011-08-01&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So in case of Feb, is it in AMERICAN, DANISH, DUTCH, ENGLISH, GERMAN, GERMAN DIN, ICELANDIC, ITALIAN, LATIN AMERICAN SPANISH, LATIN SERBIAN, LATVIAN, MALAY, MEXICAN SPANISH, NORWEGIAN, ROMANIAN, SLOVAK, SLOVENIAN, SPANISH or SWEDISH?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6901362440940203021?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6901362440940203021/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/05/baud.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6901362440940203021'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6901362440940203021'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/05/baud.html' title='BAUD'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-2163936249059382364</id><published>2011-05-06T10:54:00.004+03:00</published><updated>2011-05-06T11:15:45.904+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='modeling'/><title type='text'>many to many access path -view</title><content type='html'>Having a many to many relationship. It is the access path from one table to another. Lets call them cust, ord and prod tables. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;cust 1-* ord *-1 prod&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;There is a need to query prod that has an access path to a certain cust. And we need a database view to implement this. So we want prod out and give a cust to the query as a parameter. The first impression to a developer is to do joins to ord table. That would lead to duplicates in the result. Something that is not desired. It is possible to implement a fine performing view without those duplicates. Here is an example of such.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;create table cust (cust_id number constraint cust_pk primary key, cname varchar2(20) not null);&lt;br /&gt;&lt;br /&gt;create table prod (prod_id number constraint prod_pk primary key, pname varchar2(20) not null);&lt;br /&gt;&lt;br /&gt;create table ord ( ord_id number constraint ord_pk primary key&lt;br /&gt;                 , cust_id constraint ord_cust_fk references cust not null&lt;br /&gt;                 , prod_id constraint ord_prod_pk references prod not null&lt;br /&gt;                 , amount number not null);&lt;br /&gt;&lt;br /&gt;create index ord_cust_fk_idx on ord(cust_id,prod_id);&lt;br /&gt;&lt;br /&gt;create or replace view custprod as&lt;br /&gt;select cust.cust_id&lt;br /&gt;     , cust.cname&lt;br /&gt;     , prod.prod_id&lt;br /&gt;     , prod.pname&lt;br /&gt;  from &lt;span style="font-weight:bold;"&gt;cust,prod&lt;/span&gt;&lt;br /&gt; where &lt;span style="font-weight:bold;"&gt;exists&lt;/span&gt; (select 1 from &lt;span style="font-weight:bold;"&gt;ord&lt;/span&gt; where ord.prod_id=prod.prod_id and ord.cust_id=cust.cust_id)&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;select prod_id,pname from custprod where cust_id = :cust;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;So there it is. Take only those rows to the from clause you want results from. Use exists on another parts of the access path.&lt;br /&gt;Some data and a query plan.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;insert all into cust(cust_id,cname) values (le,le||le)&lt;br /&gt;           into prod(prod_id,pname) values (le,le||le)&lt;br /&gt; select level le from dual connect by level &lt; 1000; &lt;br /&gt;&lt;br /&gt;begin &lt;br /&gt; dbms_stats.gather_table_stats(user,'PROD');&lt;br /&gt; dbms_stats.gather_table_stats(user,'CUST');&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;insert into ord select rownum,cust_id,prod_id,mod(cust_id,prod_id) from cust, prod where cust_id &lt;= prod_id;&lt;br /&gt;&lt;br /&gt;begin &lt;br /&gt; dbms_stats.gather_table_stats(user,'ORD');&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select prod_id,pname from custprod where cust_id = :cust;&lt;br /&gt;&lt;br /&gt;--------------------------------------------------------&lt;br /&gt;| Id  | Operation                    | Name            |&lt;br /&gt;--------------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT             |                 |&lt;br /&gt;|   1 |  NESTED LOOPS                |                 |&lt;br /&gt;|   2 |   NESTED LOOPS               |                 |&lt;br /&gt;|   3 |    NESTED LOOPS              |                 |&lt;br /&gt;|   4 |     INDEX UNIQUE SCAN        | CUST_PK         |&lt;br /&gt;|   5 |     SORT UNIQUE              |                 |&lt;br /&gt;|   6 |      INDEX RANGE SCAN        | ORD_CUST_FK_IDX |&lt;br /&gt;|   7 |    INDEX UNIQUE SCAN         | PROD_PK         |&lt;br /&gt;|   8 |   TABLE ACCESS BY INDEX ROWID| PROD            |&lt;br /&gt;--------------------------------------------------------&lt;br /&gt;&lt;br /&gt;drop table ord;&lt;br /&gt;&lt;br /&gt;drop table prod;&lt;br /&gt;&lt;br /&gt;drop table cust;&lt;br /&gt;&lt;br /&gt;drop view custprod;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-2163936249059382364?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/2163936249059382364/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/05/many-to-many-access-path-view.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2163936249059382364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2163936249059382364'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/05/many-to-many-access-path-view.html' title='many to many access path -view'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-5466389674109527774</id><published>2011-05-04T23:30:00.003+03:00</published><updated>2011-05-04T23:39:18.118+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='denormalization'/><title type='text'>Denormalize for Safety</title><content type='html'>12.5.2011 the last day to register to &lt;a href="http://ougf.fi/index.php?lang=en"&gt;OUG Harmony 2011&lt;/a&gt; 19-20.5.2011, Paasitorni, Helsinki. &lt;a href="http://ougf.fi/index.php?option=com_docman&amp;task=doc_download&amp;gid=383&amp;lang=en"&gt;Agenda&lt;/a&gt; worth reading.&lt;br /&gt;&lt;br /&gt;Just posted a kind of denormalize for safety post to &lt;a href="http://forums.oracle.com/forums/thread.jspa?messageID=9565440#9565440"&gt;Oracle SQL forum&lt;/a&gt;. Using the ideas i wrote earlier &lt;a href="http://rafudb.blogspot.com/2009/09/denormalize-safely.html"&gt;denormalize safely&lt;/a&gt; and presented in OUGF seminar autumn.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-5466389674109527774?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/5466389674109527774/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/05/denormalize-for-safety.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5466389674109527774'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5466389674109527774'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/05/denormalize-for-safety.html' title='Denormalize for Safety'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-4527381190666571018</id><published>2011-04-13T08:23:00.003+03:00</published><updated>2011-04-13T09:06:38.927+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='sqlplus'/><title type='text'>Date variable in sqlplus</title><content type='html'>Having a huge query including several temporal joins and &lt;a href="http://rafudb.blogspot.com/2009/04/sum-over-time.html"&gt;sum over time&lt;/a&gt; and several date type binds. I want to execute that query using sqlplus. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; variable til date&lt;br /&gt;Usage: VAR[IABLE] [ &lt;variable&gt; [ NUMBER | CHAR | CHAR (n [CHAR|BYTE]) |&lt;br /&gt;                    VARCHAR2 (n [CHAR|BYTE]) | NCHAR | NCHAR (n) |&lt;br /&gt;                    NVARCHAR2 (n) | CLOB | NCLOB | BLOB | BFILE&lt;br /&gt;                    REFCURSOR | BINARY_FLOAT | BINARY_DOUBLE ] ]&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Using binds in sqlplus by &lt;a href="http://blog.tanelpoder.com/2011/04/10/running-select-into-bind_variable-from-sql/"&gt;Tanel Poder&lt;/a&gt; and &lt;a href="http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:2939749100346967872"&gt;askTom&lt;/a&gt; discussing missing date variable support in sqlplus. Putting those together. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; variable fro varchar2(10)&lt;br /&gt;SQL&gt; exec select sysdate into :fro from dual;&lt;br /&gt;&lt;br /&gt;PL/SQL procedure successfully completed.&lt;br /&gt;&lt;br /&gt;SQL&gt; select 1 from dual where :fro &lt; sysdate;&lt;br /&gt;&lt;br /&gt;         1&lt;br /&gt;----------&lt;br /&gt;         1&lt;br /&gt;&lt;br /&gt;SQL&gt; print fro&lt;br /&gt;&lt;br /&gt;FRO&lt;br /&gt;--------------------------------&lt;br /&gt;13.04.2011&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Be aware about possible changes in execution plan caused by datatype conversions. Read the &lt;a href="http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:2939749100346967872"&gt;askTom&lt;/a&gt; discussion.&lt;br /&gt;&lt;br /&gt;Changing NLS_DATE_FORMAT&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; alter session set nls_territory=america;&lt;br /&gt;&lt;br /&gt;Session altered.&lt;br /&gt;&lt;br /&gt;SQL&gt; select 1 from dual where :fro &lt; sysdate;&lt;br /&gt;select 1 from dual where :fro &lt; sysdate&lt;br /&gt;                          *&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-01843: not a valid month&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; exec select sysdate into :fro from dual;&lt;br /&gt;&lt;br /&gt;PL/SQL procedure successfully completed.&lt;br /&gt;&lt;br /&gt;SQL&gt; select 1 from dual where :fro &lt; sysdate;&lt;br /&gt;&lt;br /&gt;         1&lt;br /&gt;----------&lt;br /&gt;         1&lt;br /&gt;&lt;br /&gt;SQL&gt; print fro&lt;br /&gt;&lt;br /&gt;FRO&lt;br /&gt;--------------------------------&lt;br /&gt;13-APR-11&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;And yet another aspect about date formats&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; select 1 from dual where :fro = trunc(sysdate);&lt;br /&gt;&lt;br /&gt;         1&lt;br /&gt;----------&lt;br /&gt;         1&lt;br /&gt;&lt;br /&gt;SQL&gt; alter session set nls_date_format='yyyymmdd hh24mi';&lt;br /&gt;&lt;br /&gt;Session altered.&lt;br /&gt;&lt;br /&gt;SQL&gt; exec select sysdate into :fro from dual;&lt;br /&gt;BEGIN select sysdate into :fro from dual; END;&lt;br /&gt;&lt;br /&gt;*&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-06502: PL/SQL: numeric or value error: character string buffer too small&lt;br /&gt;ORA-06512: at line 1&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; variable fro varchar2(13)&lt;br /&gt;SQL&gt; exec select sysdate into :fro from dual;&lt;br /&gt;&lt;br /&gt;PL/SQL procedure successfully completed.&lt;br /&gt;&lt;br /&gt;SQL&gt; select 1 from dual where :fro = trunc(sysdate);&lt;br /&gt;&lt;br /&gt;no rows selected&lt;br /&gt;&lt;br /&gt;SQL&gt; print fro&lt;br /&gt;&lt;br /&gt;FRO&lt;br /&gt;--------------------------------&lt;br /&gt;20110413 0902&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-4527381190666571018?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/4527381190666571018/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/04/date-variable-in-sqlplus.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/4527381190666571018'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/4527381190666571018'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/04/date-variable-in-sqlplus.html' title='Date variable in sqlplus'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-1850392902736593177</id><published>2011-04-01T23:36:00.002+03:00</published><updated>2011-04-01T23:58:31.460+03:00</updated><title type='text'>11.2 XE beta and SQL Developer 3</title><content type='html'>&lt;a href="http://www.oracle.com/technetwork/database/express-edition/overview/index.html"&gt;11.2 XE beta&lt;/a&gt; available.&lt;br /&gt;&lt;br /&gt;And seems like not a april fool &lt;A href=http://blog.tanelpoder.com/2011/04/01/oracle-database-xe-express-edition-11-2-beta-is-out/&gt;Tanel Poder describing&lt;/A&gt; features.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://download.oracle.com/docs/cd/E17781_01/index.htm"&gt;Documentation&lt;/a&gt; available. And a dedicated &lt;a href="http://forums.oracle.com/forums/forum.jspa?forumID=1378&amp;start=0"&gt;discussion forum&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.oracle.com/technetwork/developer-tools/sql-developer/downloads/index.html"&gt;SQL Deveoper 3&lt;/a&gt; beta days seems to be over&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-1850392902736593177?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/1850392902736593177/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/04/112-xe-beta.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/1850392902736593177'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/1850392902736593177'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/04/112-xe-beta.html' title='11.2 XE beta and SQL Developer 3'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-3076424956756629551</id><published>2011-04-01T11:28:00.002+03:00</published><updated>2011-04-01T11:43:12.963+03:00</updated><title type='text'>Descending index is function based</title><content type='html'>Descendin index is implemented as function based index in Oracle. This is &lt;a href="http://download.oracle.com/docs/cd/E11882_01/server.112/e17118/statements_5012.htm#i2078657"&gt; documented&lt;/a&gt; and &lt;a href="http://forums.oracle.com/forums/thread.jspa?threadID=1019841"&gt;discussed&lt;/a&gt;. &lt;br /&gt;Nulls may lead to a surprise with a desc unique index.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; create table a(a varchar2(2 char), b varchar2(2 char) );&lt;br /&gt;&lt;br /&gt;Table created.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select table_name,column_name,data_type,data_length from user_tab_cols where table_name = 'A';&lt;br /&gt;&lt;br /&gt;TABLE_NAME                     COLUMN_NAME                    DATA_TYPE&lt;br /&gt;------------------------------ ------------------------------ --------------------------------------&lt;br /&gt;A                              A                              VARCHAR2&lt;br /&gt;A                              B                              VARCHAR2&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; create unique index a_idx on a (a,b desc);&lt;br /&gt;&lt;br /&gt;Index created.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select table_name,column_name,data_type,data_length from user_tab_cols where table_name = 'A';&lt;br /&gt;&lt;br /&gt;TABLE_NAME                     COLUMN_NAME                    DATA_TYPE&lt;br /&gt;------------------------------ ------------------------------ --------------------------------------&lt;br /&gt;A                              A                              VARCHAR2&lt;br /&gt;A                              B                              VARCHAR2&lt;br /&gt;A                              SYS_NC00003$                   RAW&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select index_type from user_indexes where index_name = 'A_IDX';&lt;br /&gt;&lt;br /&gt;INDEX_TYPE&lt;br /&gt;---------------------------&lt;br /&gt;FUNCTION-BASED NORMAL&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select * from user_ind_columns where index_name = 'A_IDX';&lt;br /&gt;&lt;br /&gt;INDEX_NAME                     TABLE_NAME&lt;br /&gt;------------------------------ ------------------------------&lt;br /&gt;COLUMN_NAME&lt;br /&gt;----------------------------------------------------------------------------------------------------&lt;br /&gt;COLUMN_POSITION COLUMN_LENGTH CHAR_LENGTH DESC&lt;br /&gt;--------------- ------------- ----------- ----&lt;br /&gt;A_IDX                          A&lt;br /&gt;A&lt;br /&gt;              1             8           2 ASC&lt;br /&gt;&lt;br /&gt;A_IDX                          A&lt;br /&gt;SYS_NC00003$&lt;br /&gt;              2            13           0 DESC&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select * from USER_IND_EXPRESSIONS where index_name = 'A_IDX';&lt;br /&gt;&lt;br /&gt;INDEX_NAME                     TABLE_NAME                     COLUMN_EXPRESSION&lt;br /&gt;------------------------------ ------------------------------ --------------------------------------&lt;br /&gt;A_IDX                          A                              "B"&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; insert into a values(null,null);&lt;br /&gt;&lt;br /&gt;1 row created.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; insert into a values(null,null);&lt;br /&gt;insert into a values(null,null)&lt;br /&gt;*&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-00001: unique constraint (KIOS.A_IDX) violated&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; drop index a_idx;&lt;br /&gt;&lt;br /&gt;Index dropped.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; create unique index a_idx on a (a,b);&lt;br /&gt;&lt;br /&gt;Index created.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; insert into a values(null,null);&lt;br /&gt;&lt;br /&gt;1 row created.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; insert into a values(null,null);&lt;br /&gt;&lt;br /&gt;1 row created.&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-3076424956756629551?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/3076424956756629551/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/04/descending-index-is-function-based.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3076424956756629551'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3076424956756629551'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/04/descending-index-is-function-based.html' title='Descending index is function based'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-8352529765614729485</id><published>2011-04-01T11:15:00.002+03:00</published><updated>2011-04-01T11:17:30.196+03:00</updated><title type='text'>Installing</title><content type='html'>Just to remember. Have to try next time when installing a new computer.&lt;br /&gt;&lt;a href="http://ninite.com"&gt;http://ninite.com&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-8352529765614729485?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/8352529765614729485/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/04/installing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8352529765614729485'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8352529765614729485'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/04/installing.html' title='Installing'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-2825595940666254580</id><published>2011-03-25T08:19:00.006+02:00</published><updated>2011-09-12T11:22:54.783+03:00</updated><title type='text'>Greatest Common Divisor</title><content type='html'>Need a greatest common divisor function? &lt;a href="http://vadimtropashko.files.wordpress.com/2007/02/ch3.pdf"&gt;Vadim Tropashko&lt;/a&gt; has written a SQL implementation of such. Here it is wrapped inside a function. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;create or replace function greatest_common_div(n1 number, n2 number) &lt;br /&gt;return number &lt;br /&gt;as&lt;br /&gt;ret number;&lt;br /&gt;begin&lt;br /&gt;with NumberSet as ( &lt;br /&gt;select column_value Element from table(sys.odcinumberlist( n1, n2 ))&lt;br /&gt;), Integers as (&lt;br /&gt;select level num# from dual connect by level &lt;= least( n1, n2 )&lt;br /&gt;)&lt;br /&gt;select max(Divisor) into ret &lt;br /&gt;from (&lt;br /&gt;  select Divisor&lt;br /&gt;    from (&lt;br /&gt;    select num# as Divisor from Integers &lt;br /&gt;    where num# &lt;= (select min(Element) from NumberSet)&lt;br /&gt;  ), NumberSet &lt;br /&gt;  where mod(Element, Divisor)=0&lt;br /&gt;  group by Divisor&lt;br /&gt; having count(*) = (select count(*) from NumberSet)&lt;br /&gt;);&lt;br /&gt;return ret;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select greatest_common_div(15,123) from dual;&lt;br /&gt;&lt;br /&gt;3&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;And a 11.2 version. Idea borrowed from &lt;a href="http://wiki.postgresql.org/wiki/Greatest_Common_Divisor"&gt;http://wiki.postgresql.org&lt;/a&gt;. This is a better performing one as it handles only two numbers.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;create or replace function greatest_common_div2(n1 number, n2 number) &lt;br /&gt;return number &lt;br /&gt;as&lt;br /&gt;ret number;&lt;br /&gt;begin&lt;br /&gt;WITH t(a,b) AS (&lt;br /&gt;    select n1, n2 from dual&lt;br /&gt;UNION ALL&lt;br /&gt;    SELECT b, mod(a,b) FROM t&lt;br /&gt;    WHERE b &gt; 0&lt;br /&gt;)&lt;br /&gt;SELECT a into ret&lt;br /&gt;  FROM t &lt;br /&gt; WHERE b = 0&lt;br /&gt;;&lt;br /&gt;return ret;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;And the same without pl/sql to sql context switch. &lt;i&gt;Added 12.9.2011&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;create or replace function greatest_common_div3(n1 number, n2 number) &lt;br /&gt;return number &lt;br /&gt;as&lt;br /&gt;ret number;&lt;br /&gt;begin&lt;br /&gt;ret := n1;&lt;br /&gt;if (n2 != 0) then &lt;br /&gt; ret := greatest_common_div3(n2,mod(n1,n2));&lt;br /&gt;end if;&lt;br /&gt;return ret;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;with numbers as (select level num from dual connect by level &lt; 100)&lt;br /&gt;, test as (&lt;br /&gt;select a.num a&lt;br /&gt;     , b.num b&lt;br /&gt;     , greatest_common_div(a.num,b.num) gcd&lt;br /&gt;     , greatest_common_div2(a.num,b.num) gcd2&lt;br /&gt;     , greatest_common_div3(a.num,b.num) gcd3&lt;br /&gt; from numbers a, numbers b&lt;br /&gt;)&lt;br /&gt;select * from test where gcd!=gcd2 or gcd!=gcd3&lt;br /&gt;;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Update 28.3.2011&lt;/i&gt;&lt;br /&gt;Added an user defined aggregate also.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;CREATE OR REPLACE TYPE t_gcd_agg AS OBJECT&lt;br /&gt;(&lt;br /&gt;  g_number  number,&lt;br /&gt;  STATIC FUNCTION ODCIAggregateInitialize(sctx  IN OUT  t_gcd_agg)&lt;br /&gt;    RETURN NUMBER,&lt;br /&gt;  MEMBER FUNCTION ODCIAggregateIterate(self   IN OUT  t_gcd_agg,&lt;br /&gt;                                       value  IN      number )&lt;br /&gt;     RETURN NUMBER,&lt;br /&gt;  MEMBER FUNCTION ODCIAggregateTerminate(self         IN   t_gcd_agg,&lt;br /&gt;                                         returnValue  OUT  number,&lt;br /&gt;                                         flags        IN   NUMBER)&lt;br /&gt;    RETURN NUMBER,&lt;br /&gt;  MEMBER FUNCTION ODCIAggregateMerge(self  IN OUT  t_gcd_agg,&lt;br /&gt;                                     ctx2  IN      t_gcd_agg)&lt;br /&gt;    RETURN NUMBER&lt;br /&gt;);&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;CREATE OR REPLACE TYPE BODY t_gcd_agg IS&lt;br /&gt;  STATIC FUNCTION ODCIAggregateInitialize(sctx  IN OUT  t_gcd_agg)&lt;br /&gt;    RETURN NUMBER IS&lt;br /&gt;  BEGIN&lt;br /&gt;    sctx := t_gcd_agg(NULL);&lt;br /&gt;    RETURN ODCIConst.Success;&lt;br /&gt;  END;&lt;br /&gt;  MEMBER FUNCTION ODCIAggregateIterate(self   IN OUT  t_gcd_agg,&lt;br /&gt;                                       value  IN      number )&lt;br /&gt;    RETURN NUMBER IS&lt;br /&gt;  BEGIN&lt;br /&gt;    SELF.g_number := greatest_common_div3(case when self.g_number is null then value else self.g_number end, value);&lt;br /&gt;    RETURN ODCIConst.Success;&lt;br /&gt;  END;&lt;br /&gt;  MEMBER FUNCTION ODCIAggregateTerminate(self         IN   t_gcd_agg,&lt;br /&gt;                                         returnValue  OUT  number,&lt;br /&gt;                                         flags        IN   NUMBER)&lt;br /&gt;    RETURN NUMBER IS&lt;br /&gt;  BEGIN&lt;br /&gt;    returnValue := SELF.g_number;&lt;br /&gt;    RETURN ODCIConst.Success;&lt;br /&gt;  END;&lt;br /&gt;  MEMBER FUNCTION ODCIAggregateMerge(self  IN OUT  t_gcd_agg,&lt;br /&gt;                                     ctx2  IN      t_gcd_agg)&lt;br /&gt;    RETURN NUMBER IS&lt;br /&gt;  BEGIN&lt;br /&gt;    SELF.g_number := greatest_common_div3(case when self.g_number is null then ctx2.g_number else self.g_number end&lt;br /&gt;                                        , case when ctx2.g_number is null then self.g_number else ctx2.g_number end);&lt;br /&gt;    RETURN ODCIConst.Success;&lt;br /&gt;  END;&lt;br /&gt;END;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;CREATE OR REPLACE FUNCTION gcd (p_input VARCHAR2)&lt;br /&gt;RETURN VARCHAR2&lt;br /&gt;PARALLEL_ENABLE AGGREGATE USING t_gcd_agg;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;select gcd(column_value) from table(sys.odcinumberlist(4,8,34));&lt;br /&gt;&lt;br /&gt;2&lt;br /&gt;&lt;br /&gt;with test as (&lt;br /&gt;select 'a' a, 4 n from dual union all&lt;br /&gt;select 'a' a, 6 n from dual union all&lt;br /&gt;select 'b' a, 30 n from dual union all&lt;br /&gt;select 'b' a, 60 n from dual union all&lt;br /&gt;select 'b' a, 96 n from dual&lt;br /&gt;)&lt;br /&gt;select a,gcd(n) &lt;br /&gt;from test &lt;br /&gt;group by a;&lt;br /&gt;&lt;br /&gt;a 2&lt;br /&gt;b 6&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-2825595940666254580?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/2825595940666254580/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/03/greatest-common-divisor.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2825595940666254580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2825595940666254580'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/03/greatest-common-divisor.html' title='Greatest Common Divisor'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-7062867000793895953</id><published>2011-03-16T16:32:00.002+02:00</published><updated>2011-03-16T16:34:24.325+02:00</updated><title type='text'>grep in windows</title><content type='html'>Missing grep in windows.&lt;br /&gt;Power shell to the rescue.&lt;br /&gt;&lt;br /&gt;findstr -s "search_string" files&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-7062867000793895953?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/7062867000793895953/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/03/grep-in-windows.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7062867000793895953'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7062867000793895953'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/03/grep-in-windows.html' title='grep in windows'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-483203529292280126</id><published>2011-03-11T11:35:00.002+02:00</published><updated>2011-03-11T13:08:24.657+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='opatch'/><title type='text'>Merge ignores check constraint</title><content type='html'>It was a while ago when we noticed that our enabled and validated constraints were not respected by our 11.2.0.1 database. The reason for this appeared to be a merge clause updating the rows and ignoring the constraints. A bug 9285259 was created.&lt;br /&gt;Now the bug will be fixed in version 12.1 and hopefully 11.2.0.3 also. There is a patch available on top of 11.2.0.2 version. The patch installed online. Now we are receiving ORA-02290: check constraint violated as supposed. Also workaround was introduced. Our merge clause had only update part. By adding insert or delete part to the merge the constraint is noticed without the patch.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-483203529292280126?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/483203529292280126/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/03/merge-ignores-check-constraint.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/483203529292280126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/483203529292280126'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/03/merge-ignores-check-constraint.html' title='Merge ignores check constraint'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6032673067327111445</id><published>2011-03-09T17:01:00.002+02:00</published><updated>2011-03-09T17:11:16.400+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>Removing duplicates</title><content type='html'>From &lt;a href="asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:15258974323143"&gt;asktom&lt;/a&gt; one can find an example removing duplicates. Here is another. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;create table duplicates (n int);&lt;br /&gt;&lt;br /&gt;insert into duplicates select level from dual connect by level &lt; 100;&lt;br /&gt;&lt;br /&gt;insert into duplicates select level from dual connect by level &lt; 50;&lt;br /&gt;&lt;br /&gt;delete from duplicates where rowid in (&lt;br /&gt;select rid from (&lt;br /&gt;select rowid rid, first_value(rowid)over(partition by n) frid, dup.*&lt;br /&gt;from duplicates dup&lt;br /&gt;) where frid != rid&lt;br /&gt;)&lt;br /&gt;;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6032673067327111445?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6032673067327111445/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/03/removing-duplicates.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6032673067327111445'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6032673067327111445'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/03/removing-duplicates.html' title='Removing duplicates'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-2578772524935493290</id><published>2011-03-03T09:27:00.003+02:00</published><updated>2011-03-03T11:53:59.871+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jdbc'/><title type='text'>Deprecation</title><content type='html'>During last two weeks I have noticed twice the use of oracle.jdbc.driver.OracleDriver with 11g version. It has been almost five years ago when the Oracle jdbc driver package "oracle.jdbc.driver." &lt;a href="http://forums.oracle.com/forums/ann.jspa?annID=201"&gt;deprecated&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;With 11g please use &lt;span style="font-weight:bold;"&gt;oracle.jdbc.OracleDriver&lt;/span&gt; instead of the deprecated oracle.jdbc.driver.OracleDriver. &lt;br /&gt;&lt;br /&gt;This might be found in your application server connection pool settings, project jdbc.properties or hard coded something like java.lang.Class.forName("oracle.jdbc.driver.OracleDriver");&lt;br /&gt;as it should be &lt;br /&gt;java.lang.Class.forName("oracle.jdbc.OracleDriver");&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-2578772524935493290?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/2578772524935493290/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/03/deprecation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2578772524935493290'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2578772524935493290'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/03/deprecation.html' title='Deprecation'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-3778413124819913176</id><published>2011-02-28T19:00:00.008+02:00</published><updated>2011-03-08T20:29:56.278+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>NOCOUG Second SQL Challenge</title><content type='html'>Working with &lt;a href="http://bit.ly/gVNZsW"&gt;the second NoCOUg SQL Challenge&lt;/a&gt;. In the magazine there can be found also "advice for an Oracle Beginner" articles - worth reading.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-iPubT5-ABFM/TWwMlErkPQI/AAAAAAAAAAM/bfk3j1wagk4/s1600/lod.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 126px;" src="http://3.bp.blogspot.com/-iPubT5-ABFM/TWwMlErkPQI/AAAAAAAAAAM/bfk3j1wagk4/s320/lod.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5578847869456366850" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here is my five cents to towards the problem. Another answers may be found from &lt;a href="http://iggyfernandez.wordpress.com/2011/02/13/hot-off-the-press-the-nocoug-journal-and-the-second-international-nocoug-sql-challenge%E2%80%8F/"&gt;Iggy Fernandez blog&lt;/a&gt; comments.&lt;br /&gt;&lt;br /&gt;When I found the challenge, there were already some published answers to the riddle. So I started with minimizing the starting set. Got rid of nulls in the first place. And after a while ended up with a hierarchical query. On a way I draw a Graphviz picture of the riddle data. Maybe that visualizes some paths I was trying to follow trying to figure out alternative solutions. &lt;a href="http://bit.ly/g58WVn"&gt;SQL commands for creating the required data&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;with aa as (&lt;br /&gt;select word1, word2, word3, word2 gr&lt;br /&gt;  from riddle&lt;br /&gt; where word1 is not null&lt;br /&gt;), bb as (&lt;br /&gt;select gr,pre,word&lt;br /&gt;  from aa&lt;br /&gt;unpivot (word for pre in (word1 as 1, word2 as 2, word3 as 3))&lt;br /&gt;), cc as (&lt;br /&gt;select gr,pre,word&lt;br /&gt;     , first_value(case when pre = 3 and word != gr then gr end ignore nulls)over(partition by word) bg&lt;br /&gt;     , first_value(case when pre = 1 and word != gr then gr end ignore nulls)over(partition by word) ag&lt;br /&gt;     , min(pre)over(partition by word) mi&lt;br /&gt;     , max(pre)over(partition by word) ma&lt;br /&gt;  from bb&lt;br /&gt;), dd (gr,mi,ma,pre,word,ord)as (&lt;br /&gt;select gr,mi,ma,pre,word,cast(2 as varchar2(10))&lt;br /&gt;  from cc&lt;br /&gt; where cc.pre=2 and cc.bg is null and cc.ag is null&lt;br /&gt; union all&lt;br /&gt;select cc.gr,cc.mi,cc.ma,cc.pre,cc.word&lt;br /&gt;     , dd.ord||case when cc.pre = 1 then cc.mi else cc.ma end&lt;br /&gt;from dd inner join cc on cc.pre in (1,3) and dd.word = cc.gr&lt;br /&gt;)&lt;br /&gt;select listagg(dd.word,' ')within group(order by rpad(dd.ord,10,'2'))&lt;br /&gt;  from dd&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Update 8.3.2011&lt;/span&gt; &lt;br /&gt;Ordering with rpad seems like so borrowed from the riddle_tree. So here is another solution that maintains the ordering number while browsing the tree. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;with aa as (&lt;br /&gt;select word1, word2, word3, word2 gr&lt;br /&gt;  from riddle&lt;br /&gt; where word1 is not null&lt;br /&gt;), bb as (&lt;br /&gt;select gr,pre,word&lt;br /&gt;  from aa&lt;br /&gt;unpivot (word for pre in (word1 as 1, word2 as 2, word3 as 3))&lt;br /&gt;), cc as (&lt;br /&gt;select gr,pre,word&lt;br /&gt;     , first_value(case when pre = 3 and word != gr then gr end ignore nulls)over(partition by word) bg&lt;br /&gt;     , first_value(case when pre = 1 and word != gr then gr end ignore nulls)over(partition by word) ag&lt;br /&gt;     , min(pre)over(partition by word) mi&lt;br /&gt;     , max(pre)over(partition by word) ma&lt;br /&gt;  from bb&lt;br /&gt;), dd (gr,mi,ma,pre,word,nord,lv)as (&lt;br /&gt;select gr,mi,ma,pre,word,2222222,1&lt;br /&gt;  from cc&lt;br /&gt; where cc.pre=2 and cc.bg is null and cc.ag is null&lt;br /&gt; union all&lt;br /&gt;select cc.gr,cc.mi,cc.ma,cc.pre,cc.word&lt;br /&gt;     , dd.nord+(cc.pre-2)*power(10,6-dd.lv)&lt;br /&gt;     , dd.lv+1&lt;br /&gt;from dd inner join cc on cc.pre in (1,3) and dd.word = cc.gr&lt;br /&gt;)&lt;br /&gt;select listagg(dd.word,' ')within group(order by dd.nord)&lt;br /&gt;  from dd &lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-3778413124819913176?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/3778413124819913176/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/02/nocoug-second-sql-challenge.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3778413124819913176'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3778413124819913176'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/02/nocoug-second-sql-challenge.html' title='NOCOUG Second SQL Challenge'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-iPubT5-ABFM/TWwMlErkPQI/AAAAAAAAAAM/bfk3j1wagk4/s72-c/lod.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-3354662458610866602</id><published>2011-02-23T13:53:00.003+02:00</published><updated>2011-02-23T14:02:24.800+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grants;dblink'/><title type='text'>revoke through a db link</title><content type='html'>Why would someone do such a thing? Following will end up an active a user session stuck waiting "SQL*Net message from dblink".&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;sqlplus /nolog&lt;br /&gt;&lt;br /&gt;connect / as sysdba&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;drop user a cascade;&lt;br /&gt;&lt;br /&gt;drop user b cascade;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;create user a identified by a;&lt;br /&gt;&lt;br /&gt;grant create session to a;&lt;br /&gt;&lt;br /&gt;grant create procedure to a;&lt;br /&gt;&lt;br /&gt;grant create database link to a;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;create user b identified by b;&lt;br /&gt;&lt;br /&gt;grant create session to b;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;connect a/a&lt;br /&gt;&lt;br /&gt;declare &lt;br /&gt; comm varchar2(200);&lt;br /&gt;begin &lt;br /&gt; select 'create database link b connect to b identified by b using '''||&lt;br /&gt;        sys_context('userenv','db_unique_name')||'''' into comm &lt;br /&gt;   from dual;&lt;br /&gt; execute immediate comm;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;create or replace procedure p as&lt;br /&gt;begin&lt;br /&gt;execute immediate 'revoke execute on p from b';&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;grant execute on p to b;&lt;br /&gt;&lt;br /&gt;exec a.p@b&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-3354662458610866602?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/3354662458610866602/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/02/revoke-through-db-link.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3354662458610866602'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3354662458610866602'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/02/revoke-through-db-link.html' title='revoke through a db link'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-3839925470217249625</id><published>2011-02-09T23:56:00.003+02:00</published><updated>2011-02-10T00:27:28.615+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql; null'/><title type='text'>not exists null</title><content type='html'>I wrote &lt;a href="http://rafudb.blogspot.com/2010/03/not-in-null-countdown.html"&gt;earlier about not in and null&lt;/a&gt;. Be careful also when using not exists predicate together with a sub query resulting nulls.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; select 1 from dual where not exists (select 1 from dual where 1=0);&lt;br /&gt;&lt;br /&gt;         1&lt;br /&gt;----------&lt;br /&gt;         1&lt;br /&gt;&lt;br /&gt;SQL&gt; select 1 from dual where 1=0;&lt;br /&gt;&lt;br /&gt;no rows selected&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; select 1 from dual where not exists (select max(1) from dual where 1=1);&lt;br /&gt;&lt;br /&gt;no rows selected&lt;br /&gt;&lt;br /&gt;SQL&gt; select max(1) from dual where 1=1;&lt;br /&gt;&lt;br /&gt;    MAX(1)&lt;br /&gt;----------&lt;br /&gt;         1&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; select 1 from dual where not exists (select max(1) from dual where 1=0);&lt;br /&gt;&lt;br /&gt;no rows selected&lt;br /&gt;&lt;br /&gt;SQL&gt; select max(1) from dual where 1=0;&lt;br /&gt;&lt;br /&gt;    MAX(1)&lt;br /&gt;----------&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; select 1 from dual where not exists (select null from dual);&lt;br /&gt;&lt;br /&gt;no rows selected&lt;br /&gt;&lt;br /&gt;SQL&gt; select null from dual;&lt;br /&gt;&lt;br /&gt;N&lt;br /&gt;-&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;In the sub query there is a row but it is null, unknown. So not exists null evaluates to false. More about the issue in responses to &lt;a href="http://www.freelists.org/post/oracle-l/simple-SQL-queries-give-different-results-Why"&gt;a oracle-l mailing list post&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-3839925470217249625?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/3839925470217249625/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/02/not-exists-null.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3839925470217249625'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3839925470217249625'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/02/not-exists-null.html' title='not exists null'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6815320484202527118</id><published>2011-01-28T14:06:00.016+02:00</published><updated>2011-01-28T15:22:41.660+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>ORDER SIBLINGS BY CONNECT_BY_ROOT</title><content type='html'>In this post I am dealing with a sorting problem of a recursive query and giving a guideline how to implement such ordering.&lt;br /&gt;&lt;br /&gt;We are patching an Oracle database to 11.2.0.2 and with one of our test case hit an error&lt;br /&gt;&lt;br /&gt;ORA-30007: CONNECT BY ROOT operator is not supported in the START WITH or in the CONNECT BY condition&lt;br /&gt;&lt;br /&gt;The problem query does not have connect_by_root in START WITH or CONNECT BY. But it is in order by "order siblings by connect_by_root". So the reported error is somewhat misleading.&lt;br /&gt;&lt;br /&gt;What does this order siblings by connect_by_root is trying to accomplish. The hierarchical result is ordered first by some column from a root node of the hierarchy and after that with some columns at the same level of the hierarchy.&lt;br /&gt;&lt;br /&gt;In &lt;a href="http://www.sql.ru/Forum/actualthread.aspx?bid=3&amp;amp;tid=716742&amp;amp;hl="&gt;a thread in www.sql.ru&lt;/a&gt; there may be found discussion about the same problem. With 10.2.0 ORA-00600: internal error code, arguments: [qkacon:FJswrwo] is reported. It is mentioned that giving a hint /*+ NO_CONNECT_BY_COST_BASED */ bypasses the ORA-00600 problem, but a new one is described. connect_by_root is returning nulls if the same query has siblings word in order by. So our query has problem and the newly introduced error in 11.2.0.2 is actually revealing that to us.&lt;br /&gt;&lt;br /&gt;11.2 introduced an alternative way to write hierarchical queries. Here I introduce the problematic queries with a data set having two roots. And in the end a way to implement the requirement using recursive common table expression.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;drop table emp purge;&lt;br /&gt;&lt;br /&gt;CREATE TABLE EMP&lt;br /&gt;(&lt;br /&gt;EMPNO     NUMBER(4),&lt;br /&gt;ENAME     VARCHAR2(10 BYTE),&lt;br /&gt;MGR       NUMBER(4)&lt;br /&gt;)&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;insert into emp(empno,mgr,ename) values (11,23,'SMITH');&lt;br /&gt;insert into emp(empno,mgr,ename) values (12,16,'ALLEN');&lt;br /&gt;insert into emp(empno,mgr,ename) values (13,16,'WARD');&lt;br /&gt;insert into emp(empno,mgr,ename) values (14,19,'JONES');&lt;br /&gt;insert into emp(empno,mgr,ename) values (15,16,'MARTIN');&lt;br /&gt;insert into emp(empno,mgr,ename) values (16,19,'BLAKE');&lt;br /&gt;insert into emp(empno,mgr,ename) values (17,19,'CLARK');&lt;br /&gt;insert into emp(empno,mgr,ename) values (18,null,'SCOTT');&lt;br /&gt;insert into emp(empno,mgr,ename) values (19,null,'KING');&lt;br /&gt;insert into emp(empno,mgr,ename) values (20,16,'TURNER');&lt;br /&gt;insert into emp(empno,mgr,ename) values (21,18,'ADAMS');&lt;br /&gt;insert into emp(empno,mgr,ename) values (22,16,'JAMES');&lt;br /&gt;insert into emp(empno,mgr,ename) values (23,14,'FORD');&lt;br /&gt;insert into emp(empno,mgr,ename) values (24,17,'MILLER');&lt;br /&gt;&lt;br /&gt;update emp set mgr = null where ename = 'SCOTT';&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select em.*, rpad('-',level,'-')||empno , level&lt;br /&gt;from emp em&lt;br /&gt;start with em.mgr is null&lt;br /&gt;connect by prior em.empno = em.mgr&lt;br /&gt;;&lt;br /&gt;18 SCOTT  -18 1&lt;br /&gt;21 ADAMS 18 --21 2&lt;br /&gt;19 KING  -19 1&lt;br /&gt;14 JONES 19 --14 2&lt;br /&gt;23 FORD 14 ---23 3&lt;br /&gt;11 SMITH 23 ----11 4&lt;br /&gt;16 BLAKE 19 --16 2&lt;br /&gt;12 ALLEN 16 ---12 3&lt;br /&gt;13 WARD 16 ---13 3&lt;br /&gt;15 MARTIN 16 ---15 3&lt;br /&gt;20 TURNER 16 ---20 3&lt;br /&gt;22 JAMES 16 ---22 3&lt;br /&gt;17 CLARK 19 --17 2&lt;br /&gt;24 MILLER 17 ---24 3&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Trying to add the described ordering:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;select /*+ NO_CONNECT_BY_COST_BASED */em.*, level, connect_by_root ename cbr, rpad('-',level,'-')||empno&lt;br /&gt;from emp em&lt;br /&gt;start with em.mgr is null&lt;br /&gt;connect by prior em.empno = em.mgr&lt;br /&gt;order siblings by connect_by_root ename, empno&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;18 SCOTT  1 SCOTT -18&lt;br /&gt;21 ADAMS 18 2 SCOTT --21&lt;br /&gt;19 KING  1 KING -19&lt;br /&gt;14 JONES 19 2 KING --14&lt;br /&gt;23 FORD 14 3 KING ---23&lt;br /&gt;11 SMITH 23 4 KING ----11&lt;br /&gt;16 BLAKE 19 2 KING --16&lt;br /&gt;12 ALLEN 16 3 KING ---12&lt;br /&gt;13 WARD 16 3 KING ---13&lt;br /&gt;15 MARTIN 16 3 KING ---15&lt;br /&gt;20 TURNER 16 3 KING ---20&lt;br /&gt;22 JAMES 16 3 KING ---22&lt;br /&gt;17 CLARK 19 2 KING --17&lt;br /&gt;24 MILLER 17 3 KING ---24&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Rows from KING root should be ordered before SCOTT. So using the 11.2.0.2 database the problem is noticed and the ORA-30007: CONNECT BY ROOT operator is not supported in the START WITH or in the CONNECT BY condition is thrown.&lt;br /&gt;&lt;br /&gt;How to bypass the problem with a recursive common table query:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;with cte (empno,mgr,ename,cbr,l) as (&lt;br /&gt;select empno,mgr,ename,ename cbr,1 from emp where mgr is null&lt;br /&gt;union all&lt;br /&gt;select em.empno,em.mgr,em.ename,ct.cbr,ct.l+1 from emp em inner join cte ct on em.mgr = ct.empno&lt;br /&gt;)&lt;br /&gt;SEARCH DEPTH FIRST BY cbr,empno SET rn&lt;br /&gt;select te.*, rpad('-',l,'-')||empno&lt;br /&gt;from cte te&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;19  KING KING 1 1 -19&lt;br /&gt;14 19 JONES KING 2 2 --14&lt;br /&gt;23 14 FORD KING 3 3 ---23&lt;br /&gt;11 23 SMITH KING 4 4 ----11&lt;br /&gt;16 19 BLAKE KING 2 5 --16&lt;br /&gt;12 16 ALLEN KING 3 6 ---12&lt;br /&gt;13 16 WARD KING 3 7 ---13&lt;br /&gt;15 16 MARTIN KING 3 8 ---15&lt;br /&gt;20 16 TURNER KING 3 9 ---20&lt;br /&gt;22 16 JAMES KING 3 10 ---22&lt;br /&gt;17 19 CLARK KING 2 11 --17&lt;br /&gt;24 17 MILLER KING 3 12 ---24&lt;br /&gt;18  SCOTT SCOTT 1 13 -18&lt;br /&gt;21 18 ADAMS SCOTT 2 14 --21&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Problem solved, nice feeling. Also a good taste in my mouth. Thanks to Ilkka and H. and The Yamazaki Single Malt Whisky aged 12 years Japanese whisky. Now to have some cake and buy tickets to Hakametsä Tappara ice hockey game.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6815320484202527118?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6815320484202527118/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/01/order-siblings-by-connectbyroot.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6815320484202527118'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6815320484202527118'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/01/order-siblings-by-connectbyroot.html' title='ORDER SIBLINGS BY CONNECT_BY_ROOT'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-1817541220816585411</id><published>2011-01-27T15:44:00.002+02:00</published><updated>2011-01-27T15:49:19.956+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>Partitioned Outer Join</title><content type='html'>Today was the day I had to fill some sparse data. I actually used partition by right outer join. The &lt;a href="file:///C:/oracle/doc/E11882_01/server.112/e10592/statements_10002.htm#i2177515"&gt;documentation&lt;/a&gt; example describes the problem well. Nothing much else to say about that.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-1817541220816585411?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/1817541220816585411/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/01/partitioned-outer-join.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/1817541220816585411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/1817541220816585411'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/01/partitioned-outer-join.html' title='Partitioned Outer Join'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6337561056795766101</id><published>2011-01-24T14:45:00.002+02:00</published><updated>2011-01-24T16:06:02.992+02:00</updated><title type='text'>GetClientIdentifier</title><content type='html'>Having a connection pool that connects to a schema with one username. The end users are authenticated to your application. It is possible to get the end user identifier information visible to database level v$session client_identifier column. DBMS_SESSION.SET_IDENTIFIER may be used or with JDBC setEndToEndMetrics method of the oracle.jdbc.OracleConnection.&lt;br /&gt;&lt;br /&gt;After setting client identifier information to a session it is possible to set database tracing to a client identifier. But how about your own code, how is it possible to read the client identifier information set in the session? There is no DBMS_SESSION.GET_IDENTIFIER method. One might use select to v$session view but there might be not grants to do so.&lt;br /&gt;&lt;br /&gt;Another possibility might be to user DBMS_APPLICATION_INFO.SET_CLIENT_INFO. DBMS_APPLICATION_INFO.READ_CLIENT_INFO is available. Setting client info is not available through JDBC EndToEndMetrics. Client info changes are possible to be set so the client identifier changes also. Set ALTER SYSTEM SET EVENTS 'CLIENTID_OVERWRITE'; This way the tracing by the end user becomes available.&lt;br /&gt;&lt;br /&gt;The client identifier is available through SYS_CONTEXT so the GET_IDENTIFIER may be achieved using&lt;br /&gt;select SYS_CONTEXT('userenv', 'CLIENT_IDENTIFIER') from dual;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6337561056795766101?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6337561056795766101/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2011/01/getclientidentifier.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6337561056795766101'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6337561056795766101'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2011/01/getclientidentifier.html' title='GetClientIdentifier'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-8512333715757579895</id><published>2010-12-14T21:18:00.005+02:00</published><updated>2010-12-14T21:49:42.513+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance tuning'/><title type='text'>Driving a road</title><content type='html'>At my &lt;a href="http://rafudb.blogspot.com/2010/12/many-ways-writing-query.html"&gt;last post&lt;/a&gt; I talked about different ways to write SQL. Here is an example of such situation. There are three different queries written to get the similar results out of two tables. Here I am driving a road. So the information here is kind of spatial stored in relational way.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;create table roadpoint(roadpoint_id number constraint roadpoint_pk primary key, roadnumber number not null, distance number not null);&lt;br /&gt;&lt;br /&gt;create table region(region_id number constraint region_pk primary key, startpoint references roadpoint not null, endpoint references roadpoint not null);&lt;br /&gt;&lt;br /&gt;insert into roadpoint select level,1,level*10 from dual connect by level&lt;=20000;  &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;insert into region values (1,1,2);  &lt;br /&gt;insert into region values (2,4,6);  &lt;br /&gt;insert into region values (3,7,10);  &lt;br /&gt;insert into region values (4,40,50);  &lt;br /&gt;insert into region values (5,4006,4010);  &lt;br /&gt;&lt;br /&gt;exec dbms_stats.gather_table_Stats(user,'REGION');  &lt;br /&gt;exec dbms_stats.gather_table_Stats(user,'ROADPOINT');    &lt;br /&gt;&lt;br /&gt;select * &lt;br /&gt;  from region reg, roadpoint st, roadpoint en &lt;br /&gt; where reg.startpoint = st.roadpoint_id&lt;br /&gt;   and reg.endpoint = en.roadpoint_id ;  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The problem here is that roadpoints inside region are not selected.&lt;br /&gt;&lt;br /&gt;The needed rows may be impressed with a query like following.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select reg.region_id, rp.roadpoint_id,rp.roadnumber,rp.distance&lt;br /&gt;from region reg, roadpoint rp&lt;br /&gt;where exists (select null from roadpoint st, roadpoint en where reg.startpoint = st.roadpoint_id&lt;br /&gt; and reg.endpoint = en.roadpoint_id&lt;br /&gt; and rp.distance between st.distance and en.distance&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;SQL_ID  2q2uj40br0df2, child number 0&lt;br /&gt;-------------------------------------&lt;br /&gt;select reg.region_id, rp.roadpoint_id,rp.roadnumber,rp.distance from&lt;br /&gt;region reg, roadpoint rp where exists (select null from roadpoint st,&lt;br /&gt;roadpoint en where reg.startpoint = st.roadpoint_id   and reg.endpoint&lt;br /&gt;= en.roadpoint_id   and rp.distance between st.distance and en.distance&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;Plan hash value: 2380388577&lt;br /&gt;&lt;br /&gt;-----------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation                     | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |&lt;br /&gt;-----------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT              |              |      1 |        |     25 |00:00:00.55 |     208K|       |       |          |&lt;br /&gt;|*  1 |  FILTER                       |              |      1 |        |     25 |00:00:00.55 |     208K|       |       |          |&lt;br /&gt;|   2 |   MERGE JOIN CARTESIAN        |              |      1 |    100K|    100K|00:00:00.01 |      60 |       |       |          |&lt;br /&gt;|   3 |    TABLE ACCESS FULL          | REGION       |      1 |      5 |      5 |00:00:00.01 |       7 |       |       |          |&lt;br /&gt;|   4 |    BUFFER SORT                |              |      5 |  20000 |    100K|00:00:00.01 |      53 |   690K|   486K|  613K (0)|&lt;br /&gt;|   5 |     TABLE ACCESS FULL         | ROADPOINT    |      1 |  20000 |  20000 |00:00:00.01 |      53 |       |       |          |&lt;br /&gt;|   6 |   NESTED LOOPS                |              |    100K|      1 |     25 |00:00:00.35 |     208K|       |       |          |&lt;br /&gt;|*  7 |    TABLE ACCESS BY INDEX ROWID| ROADPOINT    |    100K|      1 |   4078 |00:00:00.31 |     200K|       |       |          |&lt;br /&gt;|*  8 |     INDEX UNIQUE SCAN         | ROADPOINT_PK |    100K|      1 |    100K|00:00:00.10 |     100K|       |       |          |&lt;br /&gt;|*  9 |    TABLE ACCESS BY INDEX ROWID| ROADPOINT    |   4078 |      1 |     25 |00:00:00.01 |    8167 |       |       |          |&lt;br /&gt;|* 10 |     INDEX UNIQUE SCAN         | ROADPOINT_PK |   4078 |      1 |   4078 |00:00:00.01 |    4089 |       |       |          |&lt;br /&gt;-----------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;Predicate Information (identified by operation id):&lt;br /&gt;---------------------------------------------------&lt;br /&gt;&lt;br /&gt;  1 - filter( IS NOT NULL)&lt;br /&gt;  7 - filter("EN"."DISTANCE"&gt;=:B1)&lt;br /&gt;  8 - access("EN"."ROADPOINT_ID"=:B1)&lt;br /&gt;  9 - filter("ST"."DISTANCE"&lt;=:B1)&lt;br /&gt;  10 - access("ST"."ROADPOINT_ID"=:B1)    &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Taking a look the generated plan one might consider something else. Here are two alternative cursors c_join and c_drivetheroad. Those are measured with Tom Kytes &lt;a href="http://asktom.oracle.com/pls/asktom/ASKTOM.download_file?p_file=6551378329289980701"&gt;runstats&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;DECLARE&lt;br /&gt;  CURSOR c_join&lt;br /&gt;  IS&lt;br /&gt;select reg.region_id, rp.roadpoint_id,rp.roadnumber,rp.distance&lt;br /&gt;from region reg, roadpoint st, roadpoint en, roadpoint rp&lt;br /&gt;where reg.startpoint = st.roadpoint_id&lt;br /&gt; and reg.endpoint = en.roadpoint_id&lt;br /&gt; and rp.distance between st.distance and en.distance&lt;br /&gt;;&lt;br /&gt;--&lt;br /&gt;  CURSOR c_drivetheroad&lt;br /&gt;  IS&lt;br /&gt;select lv region_id,roadpoint_id,roadnumber,distance&lt;br /&gt;from (&lt;br /&gt;select region_id&lt;br /&gt;,last_value(region_id ignore nulls)over(partition by roadnumber order by rp.distance) lv&lt;br /&gt;,last_value(region_id ignore nulls)over(partition by roadnumber order by rp.distance desc) fv&lt;br /&gt;,staend&lt;br /&gt;,point&lt;br /&gt;,rp.roadnumber&lt;br /&gt;,roadpoint_id&lt;br /&gt;,distance&lt;br /&gt;from (&lt;br /&gt;select *&lt;br /&gt;from (&lt;br /&gt;select reg.region_id, st.distance startdistance, en.distance enddistance&lt;br /&gt;from region reg, roadpoint st, roadpoint en&lt;br /&gt;where reg.startpoint = st.roadpoint_id&lt;br /&gt; and reg.endpoint = en.roadpoint_id&lt;br /&gt;)&lt;br /&gt;unpivot (point for staend in (startdistance as '1', enddistance as '-1'))&lt;br /&gt;) re, roadpoint rp&lt;br /&gt;where re.point (+)= rp.distance&lt;br /&gt;) qw&lt;br /&gt;where lv=fv&lt;br /&gt;;&lt;br /&gt;--&lt;br /&gt;BEGIN&lt;br /&gt;   runstats_pkg.rs_start;&lt;br /&gt;  FOR i IN 1 .. 100 LOOP&lt;br /&gt;     FOR rec IN c_join LOOP&lt;br /&gt;        NULL;&lt;br /&gt;     END LOOP;&lt;br /&gt;  END LOOP;&lt;br /&gt;   runstats_pkg.rs_middle;&lt;br /&gt;  FOR i IN 1 .. 100 LOOP&lt;br /&gt;     FOR rec IN c_drivetheroad LOOP&lt;br /&gt;        NULL;&lt;br /&gt;     END LOOP;&lt;br /&gt;  END LOOP;&lt;br /&gt;   runstats_pkg.rs_stop;&lt;br /&gt;END;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Before looking at runstats results lets see the plans used. Does it seem like the first join method look like a bit easier than the second alternative. A-rows in the first one are 25 at most as those are 20000 in the second alternative.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;SQL_ID  fu5n5fqtksa7b, child number 0&lt;br /&gt;-------------------------------------&lt;br /&gt;select reg.region_id, rp.roadpoint_id,rp.roadnumber,rp.distance from&lt;br /&gt;region reg, roadpoint st, roadpoint en, roadpoint rp where&lt;br /&gt;reg.startpoint = st.roadpoint_id   and reg.endpoint = en.roadpoint_id  &lt;br /&gt;and rp.distance between st.distance and en.distance&lt;br /&gt;&lt;br /&gt;Plan hash value: 2085902882&lt;br /&gt;&lt;br /&gt;---------------------------------------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation                      | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |&lt;br /&gt;---------------------------------------------------------------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT               |              |      1 |        |     25 |00:00:00.02 |     296 |&lt;br /&gt;|   1 |  NESTED LOOPS                  |              |      1 |  25003 |     25 |00:00:00.02 |     296 |&lt;br /&gt;|   2 |   NESTED LOOPS                 |              |      1 |      5 |      5 |00:00:00.01 |      31 |&lt;br /&gt;|   3 |    NESTED LOOPS                |              |      1 |      5 |      5 |00:00:00.01 |      19 |&lt;br /&gt;|   4 |     TABLE ACCESS FULL          | REGION       |      1 |      5 |      5 |00:00:00.01 |       7 |&lt;br /&gt;|   5 |     TABLE ACCESS BY INDEX ROWID| ROADPOINT    |      5 |      1 |      5 |00:00:00.01 |      12 |&lt;br /&gt;|*  6 |      INDEX UNIQUE SCAN         | ROADPOINT_PK |      5 |      1 |      5 |00:00:00.01 |       7 |&lt;br /&gt;|   7 |    TABLE ACCESS BY INDEX ROWID | ROADPOINT    |      5 |      1 |      5 |00:00:00.01 |      12 |&lt;br /&gt;|*  8 |     INDEX UNIQUE SCAN          | ROADPOINT_PK |      5 |      1 |      5 |00:00:00.01 |       7 |&lt;br /&gt;|*  9 |   TABLE ACCESS FULL            | ROADPOINT    |      5 |   5001 |     25 |00:00:00.02 |     265 |&lt;br /&gt;---------------------------------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;Predicate Information (identified by operation id):&lt;br /&gt;---------------------------------------------------&lt;br /&gt;&lt;br /&gt;  6 - access("REG"."STARTPOINT"="ST"."ROADPOINT_ID")&lt;br /&gt;  8 - access("REG"."ENDPOINT"="EN"."ROADPOINT_ID")&lt;br /&gt;  9 - filter(("RP"."DISTANCE"&gt;="ST"."DISTANCE" AND "RP"."DISTANCE"&lt;="EN"."DISTANCE"))    &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SQL_ID  8as0wh80pucty, child number 0&lt;br /&gt;-------------------------------------&lt;br /&gt;select lv region_id,roadpoint_id,roadnumber,distance  from (  select &lt;br /&gt;region_id  ,last_value(region_id ignore nulls)over(partition by &lt;br /&gt;roadnumber order by rp.distance) lv  ,last_value(region_id ignore &lt;br /&gt;nulls)over(partition by roadnumber order by rp.distance desc) fv  &lt;br /&gt;,staend  ,point  ,rp.roadnumber  ,roadpoint_id  ,distance  from (  &lt;br /&gt;select *  from (  select reg.region_id, st.distance startdistance, &lt;br /&gt;en.distance enddistance  from region reg, roadpoint st, roadpoint en  &lt;br /&gt;where reg.startpoint = st.roadpoint_id    and reg.endpoint = &lt;br /&gt;en.roadpoint_id  )  unpivot (point for staend in (startdistance as '1', &lt;br /&gt;enddistance as '-1'))  ) re, roadpoint rp  where re.point (+)= &lt;br /&gt;rp.distance  ) qw  where lv=fv&lt;br /&gt; &lt;br /&gt;Plan hash value: 1653289237&lt;br /&gt; &lt;br /&gt;------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation                            | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |&lt;br /&gt;------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT                     |              |      1 |        |     25 |00:00:00.08 |      84 |       |       |          |&lt;br /&gt;|*  1 |  VIEW                                |              |      1 |  20000 |     25 |00:00:00.08 |      84 |       |       |          |&lt;br /&gt;|   2 |   WINDOW SORT                        |              |      1 |  20000 |  20000 |00:00:00.08 |      84 |   903K|   523K|  802K (0)|&lt;br /&gt;|   3 |    WINDOW SORT                       |              |      1 |  20000 |  20000 |00:00:00.06 |      84 |   832K|   511K|  739K (0)|&lt;br /&gt;|*  4 |     HASH JOIN RIGHT OUTER            |              |      1 |  20000 |  20000 |00:00:00.02 |      84 |   968K|   968K|  797K (0)|&lt;br /&gt;|*  5 |      VIEW                            |              |      1 |     10 |     10 |00:00:00.01 |      31 |       |       |          |&lt;br /&gt;|   6 |       UNPIVOT                        |              |      1 |        |     10 |00:00:00.01 |      31 |       |       |          |&lt;br /&gt;|   7 |        NESTED LOOPS                  |              |      1 |        |      5 |00:00:00.01 |      31 |       |       |          |&lt;br /&gt;|   8 |         NESTED LOOPS                 |              |      1 |      5 |      5 |00:00:00.01 |      26 |       |       |          |&lt;br /&gt;|   9 |          NESTED LOOPS                |              |      1 |      5 |      5 |00:00:00.01 |      19 |       |       |          |&lt;br /&gt;|  10 |           TABLE ACCESS FULL          | REGION       |      1 |      5 |      5 |00:00:00.01 |       7 |       |       |          |&lt;br /&gt;|  11 |           TABLE ACCESS BY INDEX ROWID| ROADPOINT    |      5 |      1 |      5 |00:00:00.01 |      12 |       |       |          |&lt;br /&gt;|* 12 |            INDEX UNIQUE SCAN         | ROADPOINT_PK |      5 |      1 |      5 |00:00:00.01 |       7 |       |       |          |&lt;br /&gt;|* 13 |          INDEX UNIQUE SCAN           | ROADPOINT_PK |      5 |      1 |      5 |00:00:00.01 |       7 |       |       |          |&lt;br /&gt;|  14 |         TABLE ACCESS BY INDEX ROWID  | ROADPOINT    |      5 |      1 |      5 |00:00:00.01 |       5 |       |       |          |&lt;br /&gt;|  15 |      TABLE ACCESS FULL               | ROADPOINT    |      1 |  20000 |  20000 |00:00:00.02 |      53 |       |       |          |&lt;br /&gt;------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt; &lt;br /&gt;Predicate Information (identified by operation id):&lt;br /&gt;---------------------------------------------------&lt;br /&gt; &lt;br /&gt;   1 - filter("LV"="FV")&lt;br /&gt;   4 - access("unpivot_view_014"."POINT"="RP"."DISTANCE")&lt;br /&gt;   5 - filter("unpivot_view_014"."POINT" IS NOT NULL)&lt;br /&gt;  12 - access("REG"."STARTPOINT"="ST"."ROADPOINT_ID")&lt;br /&gt;  13 - access("REG"."ENDPOINT"="EN"."ROADPOINT_ID")&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And now some runstats numbers&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;Run1 ran in 126 hsecs&lt;br /&gt;Run2 ran in 800 hsecs&lt;br /&gt;run 1 ran in 15,75% of the time&lt;br /&gt;&lt;br /&gt;Name                                  Run1        Run2        Diff&lt;br /&gt;STAT...table scan blocks gotte      25,500       5,500     -20,000&lt;br /&gt;STAT...no work - consistent re      25,955       5,714     -20,241&lt;br /&gt;STAT...consistent gets from ca      27,661       6,221     -21,440&lt;br /&gt;STAT...consistent gets              29,930       8,425     -21,505&lt;br /&gt;STAT...consistent gets from ca      29,930       8,425     -21,505&lt;br /&gt;STAT...session logical reads        29,990       8,459     -21,531&lt;br /&gt;LATCH.cache buffers chains          57,767      15,172     -42,595&lt;br /&gt;STAT...session uga memory max      123,452     410,072     286,620&lt;br /&gt;STAT...session pga memory max      131,072     524,288     393,216&lt;br /&gt;STAT...sorts (rows)                     33   4,000,000   3,999,967&lt;br /&gt;STAT...table scan rows gotten   10,000,500   2,000,500  -8,000,000&lt;br /&gt;&lt;br /&gt;Run1 latches total versus runs -- difference and pct&lt;br /&gt;Run1        Run2        Diff       Pct&lt;br /&gt;60,427      20,974     -39,453    288.10%&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We actually read less rows and sort them and use memory a bit more in the c_drivetheroad version. The cursor c_join seems to be faster in this case. But the note that the number of a-rows vs rows gotten are not in sync. Also logical reads are one magnitude more in c_join run.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-8512333715757579895?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/8512333715757579895/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/12/driving-road.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8512333715757579895'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8512333715757579895'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/12/driving-road.html' title='Driving a road'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-7973197893657545657</id><published>2010-12-09T23:58:00.004+02:00</published><updated>2010-12-10T00:07:38.648+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>Many ways writing a query</title><content type='html'>&lt;span&gt;&lt;span&gt;Iggy Fernandez is writing about SQL &lt;a href="http://iggyfernandez.wordpress.com/2010/12/07/which-query-is-better%E2%80%94part-iii-no-explain-plan-to-rule-them-all"&gt;Which Query is Better?—Part III&lt;/a&gt;. I am checking here queries from &lt;a href="http://www.dbdebunk.com/page/page/1317920.htm"&gt;the original article&lt;/a&gt; that he did not include in his post. And something else.&lt;br /&gt;&lt;br /&gt;HASH JOIN plans&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;pre&gt;&lt;br /&gt;SELECT lname&lt;div&gt;&lt;span&gt;&lt;span&gt;FROM personnel&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;WHERE 199170 = any (&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  SELECT salary &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  FROM payroll &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  WHERE personnel.empid = payroll.empid) ;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;SELECT lname&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;FROM personnel&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;WHERE 199170 in ( &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  SELECT salary &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  FROM payroll &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  WHERE personnel.empid = payroll.empid) ;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;SELECT lname&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;FROM personnel&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;WHERE empid = any (&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  SELECT empid &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  FROM payroll&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  WHERE salary = 199170);&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The HASH JOIN RIGHT SEMI plan:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SELECT lname&lt;/pre&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;FROM personnel&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;WHERE 0 &amp;lt; (&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  SELECT count(*)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  FROM payroll&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  WHERE personnel.empid = payroll.empid  AND salary = 199170);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Mr Date mentioned in EMEA Harmony 2010 about using any operator that it is behaving relationally. Even thou one should not start using it.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;Two additional queries resulting HASH JOIN plan:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;SELECT lname&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;FROM personnel, (select empid from payroll where salary = 199170) payr&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;WHERE personnel.empid = payr.empid;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;SELECT lname&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;FROM personnel inner join payroll &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;ON personnel.empid = payroll.empid and salary = 199170;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;HASH JOIN RIGHT ANTI plan also possible plan for the question here.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;SELECT lname&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;FROM personnel&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;WHERE 0 = (&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  SELECT count(*)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  FROM payroll&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  WHERE personnel.empid = payroll.empid&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  AND salary != 199170);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;div&gt;SQL_ID  b90mkx99aux26, child number 1&lt;/div&gt;&lt;div&gt;-------------------------------------&lt;/div&gt;&lt;div&gt;SELECT lname FROM personnel WHERE 0 = (SELECT count(*)   FROM payroll   &lt;/div&gt;&lt;div&gt;WHERE personnel.empid = payroll.empid   AND salary != 199170)&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;Plan hash value: 103534934&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;--------------------------------------------------------------------------------------------&lt;/div&gt;&lt;div&gt;| Id  | Operation            | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers |&lt;/div&gt;&lt;div&gt;--------------------------------------------------------------------------------------------&lt;/div&gt;&lt;div&gt;|   0 | SELECT STATEMENT     |           |      1 |        |   1004 |00:00:00.08 |     261 |&lt;/div&gt;&lt;div&gt;|*  1 |  HASH JOIN RIGHT ANTI|           |      1 |   9900 |   1004 |00:00:00.08 |     261 |&lt;/div&gt;&lt;div&gt;|*  2 |   TABLE ACCESS FULL  | PAYROLL   |      1 |   8910 |   8896 |00:00:00.01 |      38 |&lt;/div&gt;&lt;div&gt;|   3 |   TABLE ACCESS FULL  | PERSONNEL |      1 |   9900 |   9900 |00:00:00.01 |     223 |&lt;/div&gt;&lt;div&gt;--------------------------------------------------------------------------------------------&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Predicate Information (identified by operation id):&lt;/div&gt;&lt;div&gt;---------------------------------------------------&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;   1 - access("PERSONNEL"."EMPID"="PAYROLL"."EMPID")&lt;/div&gt;&lt;div&gt;   2 - filter("SALARY"!=199170)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;Without this rehersal I would not have writen anti join this way. Actually I would like to see an alternative sql resulting this plan.&lt;br /&gt;The original article talked also about indexing the salary column.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;pre&gt;&lt;br /&gt;create index payroll_salary_idx on payroll(salary);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;With this data - no changes in the query plans. Trying a fat one&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;create index payroll_salary_fat_idx on payroll(salary,empid);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;The only change in plans is that FULL TABLE SCAN of payroll changes to INDEX payroll_salary_fat_idx RANGE SCAN in some queries.The join method stays always the same.&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-7973197893657545657?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/7973197893657545657/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/12/many-ways-writing-query.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7973197893657545657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7973197893657545657'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/12/many-ways-writing-query.html' title='Many ways writing a query'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-397938672646163645</id><published>2010-10-10T16:49:00.004+03:00</published><updated>2010-10-10T17:23:47.554+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='load'/><category scheme='http://www.blogger.com/atom/ns#' term='view'/><title type='text'>Loading a collection with check option</title><content type='html'>Lets add a new requirement to inserting a collection of data. All rows inserted should be in some range. An example of such code may be found I my earlier post &lt;a href="http://rafudb.blogspot.com/2009/08/load-using-java.html"&gt;load using Java&lt;/a&gt;  &lt;br /&gt;&lt;br /&gt;We have a collection of data. At this point we do not know the values included. A new requirement should be implemented. The upper bound of values should be checked before committing the insert. Should we browse through the collection before throwing it in? &lt;br /&gt;&lt;br /&gt;Alex Nuijten just posted &lt;a href="http://nuijten.blogspot.com/2010/10/inline-view-check-option.html"&gt;Inline View Check Option&lt;/a&gt;. That could be used. So the inserting method might be something like&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;private static void insertArray(Connection c, List elems, int upperbound) &lt;br /&gt;            throws SQLException {&lt;br /&gt;        ArrayDescriptor ad = ArrayDescriptor.createDescriptor("SIT", c);&lt;br /&gt;        ARRAY a = new ARRAY(ad, c, elems.toArray());&lt;br /&gt;        OraclePreparedStatement ops &lt;br /&gt;           = (OraclePreparedStatement)c.prepareStatement(&lt;br /&gt;                        "insert into insert into " + &lt;br /&gt;                        " (select s, s2 " +&lt;br /&gt;                        "    from si where s &lt;= ? " +&lt;br /&gt;                        "    with check option) " +&lt;br /&gt;                        " select * " +&lt;br /&gt;                        "    from table(?)");&lt;br /&gt;        ops.setInt(1, upperbound);&lt;br /&gt;        ops.setARRAY(2, a);&lt;br /&gt;&lt;br /&gt;        System.out.println(ops.executeUpdate());&lt;br /&gt;        ops.close();&lt;br /&gt;        c.commit();&lt;br /&gt;    }&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;If everything is ok there is no need to browse through the collection in client side. In invalid collection situation there is the round trip to the database to get the error "ORA-01402: view WITH CHECK OPTION where-clause violation". The List implementation for elems should be the place to handle such requirement. Just had to write something about a inline view with check option feature. Maybe some day there is similar pl/sql code that might benefit this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-397938672646163645?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/397938672646163645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/10/loading-collection-with-check-option.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/397938672646163645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/397938672646163645'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/10/loading-collection-with-check-option.html' title='Loading a collection with check option'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-7698557117771722761</id><published>2010-10-07T23:21:00.003+03:00</published><updated>2010-10-07T23:33:18.646+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='data types'/><category scheme='http://www.blogger.com/atom/ns#' term='conversions'/><category scheme='http://www.blogger.com/atom/ns#' term='date'/><title type='text'>ISO year week day to date</title><content type='html'>Trying to get date out of three of numbers. Three numbers are ISO standard year, ISO standard week and number of a day in a week. The first day of a week is Monday.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;select to_date ('2010 40 4','iyyy iw d') from dual;&lt;br /&gt;&lt;br /&gt;ORA-01820: format code cannot appear in date input format&lt;br /&gt;01820. 00000 -  "format code cannot appear in date input format"&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;A date specification contained an invalid format code. Only the following&lt;br /&gt;may be specified when entering a date: year, month, day, hours, minutes, &lt;br /&gt;seconds, Julian day, A.M./P.M. and B.C./A.D.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;select to_timestamp ('2010 40 4','iyyy iw d') from dual;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Surprise, no luck, the same error. &lt;br /&gt;&lt;br /&gt;From Oracle support formely known as metalink can be found a statement that the feature has not been in such priority to be implemented. Build your own function. I am too lazy to do that. And as I know the timerange I am interested in I use brute force. Use data. We are in a database. It is built to store data. I will use that ability.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;create table isoyearweekday_to_date(&lt;br /&gt;isoyearweekday number(7) constraint isoyearweekday_to_date_pk primary key&lt;br /&gt;, dat date not null) &lt;br /&gt;organization index;&lt;br /&gt;&lt;br /&gt;insert into isoyearweekday_to_date &lt;br /&gt;select to_char(d,'iyyyiwd')&lt;br /&gt;     , d &lt;br /&gt;  from (&lt;br /&gt;   select to_date('17991231','yyyymmdd')+level d&lt;br /&gt;     from dual &lt;br /&gt;   connect by level &lt;= to_date('22000101','yyyymmdd')-to_date('18000101','yyyymmdd')+1&lt;br /&gt;  )&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;select * from isoyearweekday_to_date where isoyearweekday = 2010404&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;2010404 07.10.2010&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-7698557117771722761?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/7698557117771722761/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/10/iso-year-week-day-to-date.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7698557117771722761'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7698557117771722761'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/10/iso-year-week-day-to-date.html' title='ISO year week day to date'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6868330603638491609</id><published>2010-10-01T23:17:00.002+03:00</published><updated>2010-10-01T23:35:13.972+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='null'/><title type='text'>null - quilty or not</title><content type='html'>It is Friday evening. Watching a recording of Mentalist.&lt;br /&gt;&lt;br /&gt;true - false - null&lt;br /&gt;had some drinks - sober - a drink too much&lt;br /&gt;innocent - pulled the trigger - too drunk to remember&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6868330603638491609?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6868330603638491609/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/10/null-quilty-or-not.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6868330603638491609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6868330603638491609'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/10/null-quilty-or-not.html' title='null - quilty or not'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-5670083928870848899</id><published>2010-09-24T17:20:00.001+03:00</published><updated>2010-09-24T17:22:51.182+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='indexing'/><title type='text'>Usefull indexes</title><content type='html'>Do we actually need such indexes?&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;select owner,table_name,index_name &lt;br /&gt;  from all_indexes &lt;br /&gt; where distinct_keys &lt; 2&lt;br /&gt;   and num_rows &gt; 100;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-5670083928870848899?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/5670083928870848899/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/09/usefull-indexes.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5670083928870848899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5670083928870848899'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/09/usefull-indexes.html' title='Usefull indexes'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-351063629328784898</id><published>2010-09-20T22:06:00.002+03:00</published><updated>2010-09-20T23:01:29.336+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sqlplus'/><category scheme='http://www.blogger.com/atom/ns#' term='net'/><title type='text'>Ezconnect</title><content type='html'>Today I noticed the reason why I have not bothered to use ezconnect method with sqlplus connections. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;sqlplus system/oracle@localhost/orcl&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;I do not like to reveal my passwords on screen if possible. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;sqlplus system@localhost/orcl&lt;br /&gt;&lt;br /&gt;ERROR:&lt;br /&gt;ORA-12504: TNS:listener was not given the SERVICE_NAME in CONNECT_DATA&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Additional quotes are needed with ezconnect, when I do not want to write the password on command line.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;sqlplus system@\"localhost/orcl\"&lt;br /&gt;Enter password:&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;or&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;sqlplus /nolog&lt;br /&gt;SQL&gt; conn system@"localhost/orcl"&lt;br /&gt;Enter password:&lt;br /&gt;Connected.&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Seems like 11.2 client does not need NAMES.DIRECTORY_PATH= (ezconnect) line in sqlnet.ora anymore to use the method. 10.1, 10.2 and 11.1 version client installations need that line there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-351063629328784898?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/351063629328784898/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/09/ezconnect.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/351063629328784898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/351063629328784898'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/09/ezconnect.html' title='Ezconnect'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-4221414647197509189</id><published>2010-09-16T22:21:00.002+03:00</published><updated>2010-09-16T23:38:35.039+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='audit'/><title type='text'>extended audit_trail</title><content type='html'>Want to audit issued sql_text and binds in 11g database? &lt;br /&gt;&lt;br /&gt;Documentation says that audit_trail parameter may have values &lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;Parameter type String&lt;br /&gt;Syntax AUDIT_TRAIL = { none | os | db [, extended] | xml [, extended] }&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Trying&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; alter system set audit_trail='db, extended' scope=spfile;&lt;br /&gt;alter system set audit_trail='db, extended' scope=spfile&lt;br /&gt;*&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-00096: invalid value db, extended for parameter audit_trail, must be from&lt;br /&gt;among extended, xml, db_extended, false, true, none, os, db&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Uups, the documented one did not work. I will try out the first suggested one.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; alter system set audit_trail='extended' scope=spfile;&lt;br /&gt;alter system set audit_trail='extended' scope=spfile&lt;br /&gt;*&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-32017: failure in updating SPFILE&lt;br /&gt;ORA-00096: invalid value EXTENDED for parameter audit_trail, must be from among&lt;br /&gt;NONE | OS | DB | DB,EXTENDED | XML | XML,EXTENDED&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Uups, Oracle did it again. DB,EXTENDED seems a bit closer to the one documented.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; alter system set audit_trail='DB,EXTENDED' scope=spfile;&lt;br /&gt;alter system set audit_trail='DB,EXTENDED' scope=spfile&lt;br /&gt;*&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-00096: invalid value DB,EXTENDED for parameter audit_trail, must be from&lt;br /&gt;among extended, xml, db_extended, false, true, none, os, db&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Back to the original error message. Yet another quess...&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; alter system set audit_trail='db_extended' scope=spfile;&lt;br /&gt;&lt;br /&gt;System altered.&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Yes I found it. After reboot sql_text and binds are collected.&lt;br /&gt;&lt;br /&gt;Should the documentation say&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;Parameter type String&lt;br /&gt;Syntax AUDIT_TRAIL = { none | true | false | os | db | db_extended | xml }&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;No. The problem is that issuing a String parameter as a quoted 'string'.&lt;br /&gt;&lt;br /&gt;The correct way to do documented way&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; alter system set audit_trail=db, extended scope=spfile;&lt;br /&gt;&lt;br /&gt;System altered.&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;This way also the new xml, extended is accepted, if someone likes it that way. Also some old (10.1) and alternative ways are also accepted. Although we should use only the documented ones. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; alter system set audit_trail=true scope=spfile;&lt;br /&gt;SQL&gt; alter system set audit_trail=false scope=spfile;&lt;br /&gt;SQL&gt; alter system set audit_trail=db_extended scope=spfile;&lt;br /&gt;SQL&gt; alter system set audit_trail=db,extended scope=spfile;&lt;br /&gt;SQL&gt; alter system set audit_trail=db,  extended scope=spfile;&lt;br /&gt;...&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;So minor issue, but should the ORA-00096 error messages be updated? Maybe. Compared to other product error messages the information Oracle gives in those are mostly understandable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-4221414647197509189?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/4221414647197509189/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/09/extended-audittrail.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/4221414647197509189'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/4221414647197509189'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/09/extended-audittrail.html' title='extended audit_trail'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-7559543078584090239</id><published>2010-09-14T01:14:00.006+03:00</published><updated>2010-09-14T01:26:39.681+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Developer'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>Anoying SQL Developer</title><content type='html'>Yet another new installation of SQL Developer. I am writing SQL. The query includes ANALYTIC functions not AGGREGATE ones. SQL Developer hits and adds some group by clause somewhere in between my clause. Getting rid of that.&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Tools&lt;/div&gt;&lt;div&gt;Preferences...&lt;/div&gt;&lt;div&gt;Code editor&lt;/div&gt;&lt;div&gt;Completion Insight&lt;/div&gt;&lt;div&gt;unselect Autogenerate GROUP BY clause.&lt;/div&gt;&lt;div&gt;&lt;div&gt;OK&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I so wish this would be the default.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-7559543078584090239?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/7559543078584090239/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/09/anoying-sql-developer.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7559543078584090239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7559543078584090239'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/09/anoying-sql-developer.html' title='Anoying SQL Developer'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-7021772280504101909</id><published>2010-09-06T23:47:00.005+03:00</published><updated>2010-09-07T00:28:41.043+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><title type='text'>Lean</title><content type='html'>&lt;div&gt;Just had a pleasure to participate a session with &lt;a href="http://users.rcn.com/jcoplien/"&gt;Jim Coplien&lt;/a&gt;. His earlier presentation about the main issues seems to be found also &lt;a href="http://vimeo.com/8235574"&gt;online&lt;/a&gt;. Need to listen that again later. MVC and DCI. Model and data in both the part closest to the storage seems to be the first words to name software architectures. Maybe also the &lt;a href="http://www.leansoftwarearchitecture.com/"&gt;Lean Architecture&lt;/a&gt; book to be read.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-7021772280504101909?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/7021772280504101909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/09/lean.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7021772280504101909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7021772280504101909'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/09/lean.html' title='Lean'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-2795700891258948656</id><published>2010-08-24T09:32:00.003+03:00</published><updated>2010-08-24T10:06:05.634+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OUGF'/><title type='text'>Baag</title><content type='html'>I have been involved in many situations that all come to the issue of knowing not quessing. The ideas behind &lt;a href="http://www.battleagainstanyguess.com/"&gt;BAAG&lt;/a&gt; should be considered in many problem solving situations. Avoid guessworking, RTFM (Read that fine manual), ...&lt;br /&gt;&lt;br /&gt;To avoid guesworking recommended attendance &lt;a href="http://www.ougf.fi/"&gt;Oracle User Group Finland&lt;/a&gt; Autumn Seminar 2010 4. November 2010 in Pörssitalo, Helsinki, Finland&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-2795700891258948656?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/2795700891258948656/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/08/baag.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2795700891258948656'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2795700891258948656'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/08/baag.html' title='Baag'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-3441121722439408332</id><published>2010-06-24T00:37:00.004+03:00</published><updated>2010-06-24T12:17:34.390+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='indexing'/><title type='text'>locator index size</title><content type='html'>Just dealing a situation with 10.2.0.4 locator index. Size of a index had grown to 1.3G. After rebuilding it had size less than 50M.&lt;br /&gt;Maybe there is going on something similar than Richard Foote is talking about &lt;a href="http://richardfoote.wordpress.com/2010/06/01/BITMAP-INDEX-degradation-since-10g-fix-you/"&gt;bitmap indexes behaving in 9.2 and 10.2&lt;/a&gt;. &lt;br /&gt;Trying a similar test with a locator index.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;CREATE TABLE foo AS &lt;br /&gt; SELECT mod(ROWNUM,1000)+1 ID&lt;br /&gt;     , SYSDATE+mod(ROWNUM,1000)+1 fro&lt;br /&gt;     , SYSDATE+mod(ROWNUM,1000)+2 til&lt;br /&gt;     , 'FOO' NAME &lt;br /&gt;  FROM (SELECT NULL A FROM&lt;br /&gt;(SELECT NULL A FROM dual CONNECT BY LEVEL &lt;= 1000),&lt;br /&gt;(SELECT NULL A FROM dual CONNECT BY LEVEL &lt;= 1000));&lt;br /&gt;&lt;br /&gt;CREATE OR REPLACE FUNCTION TF(FRO DATE, TIL DATE) RETURN SDO_GEOMETRY deterministic as &lt;br /&gt;BEGIN&lt;br /&gt;RETURN MDSYS.SDO_GEOMETRY(2002,NULL, NULL, SDO_ELEM_INFO_ARRAY (1,2,1),&lt;br /&gt;    SDO_ORDINATE_ARRAY(to_number(to_char(FRO,'j')),0,to_number(to_char(TIL,'j')),0));&lt;br /&gt;END;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;select min(to_number(to_char(FRO,'j'))),max(to_number(to_char(TIL,'j'))) from foo;&lt;br /&gt;&lt;br /&gt;2455373 2456373&lt;br /&gt;&lt;br /&gt;INSERT INTO USER_SDO_GEOM_METADATA(TABLE_NAME,COLUMN_NAME,DIMINFO)&lt;br /&gt;  VALUES (&lt;br /&gt;  'FOO',&lt;br /&gt;  'RAFU.TF(FRO,TIL)',&lt;br /&gt;  SDO_DIM_ARRAY(&lt;br /&gt;    SDO_DIM_ELEMENT('X', 2455373, 2456373, 0.5),&lt;br /&gt;    SDO_DIM_ELEMENT('Y', 0, 0, 0.5)&lt;br /&gt;     )&lt;br /&gt;  )&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;br /&gt;CREATE INDEX FOO_LOCATOR_IDX ON FOO(TF(FRO,TIL))&lt;br /&gt;  INDEXTYPE IS mdsys.spatial_index&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;analyze index FOO_LOCATOR_IDX compute statistics;&lt;br /&gt;&lt;br /&gt;SELECT index_name, blevel, leaf_blocks, num_rows FROM user_indexes WHERE index_name = 'FOO_LOCATOR_IDX';&lt;br /&gt;&lt;br /&gt;"INDEX_NAME" "BLEVEL" "LEAF_BLOCKS" "NUM_ROWS"&lt;br /&gt;"FOO_LOCATOR_IDX" "" "" ""&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Nothing there. It is a domain index and storing its structures in a table.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;select segment_name,bytes,blocks from user_segments where segment_name like 'MDRT_%';&lt;br /&gt;&lt;br /&gt;MDRT_11976$ 92274688 11264&lt;br /&gt;&lt;br /&gt;SELECT count(*) FROM MDRT_11976$;&lt;br /&gt;&lt;br /&gt;33342&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;And now populating in a loop as Richard did with bitmap index.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE bar AS &lt;br /&gt; SELECT * FROM foo &lt;br /&gt;  WHERE 0=1&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;INSERT INTO USER_SDO_GEOM_METADATA(TABLE_NAME,COLUMN_NAME,DIMINFO)&lt;br /&gt;  VALUES (&lt;br /&gt;  'BAR',&lt;br /&gt;  'RAFU.TF(FRO,TIL)',&lt;br /&gt;  SDO_DIM_ARRAY(&lt;br /&gt;    SDO_DIM_ELEMENT('X', 2455373, 2456373, 0.5),&lt;br /&gt;    SDO_DIM_ELEMENT('Y', 0, 0, 0.5)&lt;br /&gt;     )&lt;br /&gt;  )&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;br /&gt;CREATE INDEX BAR_LOCATOR_IDX ON BAR(TF(FRO,TIL))&lt;br /&gt;  INDEXTYPE IS mdsys.spatial_index&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;begin&lt;br /&gt; FOR i IN 1..1000 loop&lt;br /&gt;  FOR j IN 1..1000 loop&lt;br /&gt;   INSERT INTO bar VALUES (j, SYSDATE+j, SYSDATE+j, 'FOO');&lt;br /&gt;   COMMIT;&lt;br /&gt;  END loop;&lt;br /&gt; end loop;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select segment_name,bytes,blocks from user_segments where segment_name like 'MDRT_%';&lt;br /&gt;&lt;br /&gt;MDRT_11976$  92274688      11264&lt;br /&gt;MDRT_119DF$ 125829120      15360&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT count(*) FROM MDRT_11976$;&lt;br /&gt;&lt;br /&gt;33342&lt;br /&gt;&lt;br /&gt;select count(*) from MDRT_119DF$;&lt;br /&gt;&lt;br /&gt;58084&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Well that does not explain the 1.3G size. Similar result with 11.2.0.1, 11.1.0.7 and 10.2.0.4.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-3441121722439408332?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/3441121722439408332/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/06/locator-index-size.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3441121722439408332'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3441121722439408332'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/06/locator-index-size.html' title='locator index size'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-7342845873374602170</id><published>2010-06-16T00:08:00.004+03:00</published><updated>2010-06-16T00:14:36.233+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Performance tuning'/><title type='text'>Visual tuning</title><content type='html'>It was a nice opportunity to attend &lt;a href="http://db-optimizer.blogspot.com/2010/04/i-now-have-opportunity-to-offer-6-week.html"&gt;beta testing a tool&lt;/a&gt; that does something that I do with pen and paper quite often when trying to figure out query relations.&lt;br /&gt;&lt;br /&gt;Could not attend a &lt;a href="http://www.embarcadero.com/master-sql-tuners-oracle-lewis-hailey"&gt;webinar&lt;/a&gt; last Thursday. Just waiting for the opportunity to see &lt;a href="http://db-optimizer.blogspot.com/2010/06/jonathan-lewis-webinar-replay.html"&gt;the replay&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-7342845873374602170?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/7342845873374602170/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/06/visual-tuning.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7342845873374602170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7342845873374602170'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/06/visual-tuning.html' title='Visual tuning'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-1054014624245849132</id><published>2010-05-19T00:03:00.004+03:00</published><updated>2010-05-19T00:22:21.818+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='constraints'/><title type='text'>Exclusion Constraints</title><content type='html'>In future Postgresql versions they are talking about exclusion constraints. Hitting just the thing I have been writing about in several posts about not overlapping and how to dirty hack implement it somehow with Oracle. Nice video presentation about the issue from &lt;a href="http://media.postgresql.org/sfpug/sfpug-exclusion-20091208.mov"&gt;San Francisco PostgreSQL User Group&lt;/a&gt;. And some &lt;a href="http://www.hagander.net/talks/Beyond%20UNIQUE.pdf"&gt;pdf&lt;/a&gt; about the same issue.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-1054014624245849132?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/1054014624245849132/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/05/exclusion-constraints.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/1054014624245849132'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/1054014624245849132'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/05/exclusion-constraints.html' title='Exclusion Constraints'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-7845246305014748739</id><published>2010-05-18T20:13:00.003+03:00</published><updated>2010-05-18T21:51:29.738+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='modeling'/><title type='text'>Types of columns</title><content type='html'>Just participated C.J.Date two day seminar in 10 hours today. Thanks to the ash from Iceland. Monday was delayed.&lt;br /&gt;&lt;br /&gt;Just a small thing picked up from the massive amount of information. To avoid type conversions behind the scenas while doing natural joins avoid using different types for columns named similarily. Just checking that&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;select * from (&lt;br /&gt;select count(distinct data_type&lt;br /&gt;                      ||'|'||cast(data_length as varchar2(30))&lt;br /&gt;                      ||'|'||cast(data_precision as varchar2(30))&lt;br /&gt;                      ||'|'||cast(data_scale as varchar2(30))&lt;br /&gt;            ) over (partition by column_name) as dis&lt;br /&gt;     , table_name&lt;br /&gt;     , column_name&lt;br /&gt;     , data_type&lt;br /&gt;     , data_length&lt;br /&gt;     , data_precision&lt;br /&gt;     , data_scale &lt;br /&gt;  from user_tab_columns&lt;br /&gt;) &lt;br /&gt;where dis &gt; 1&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Well on the other hand do not use select *. As an analogy I would suggess not to use natural joins. Mr Date suggested to use views on to of base tables. That makes sense. And a good thing here user_tab_columns has also the columns in views included.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-7845246305014748739?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/7845246305014748739/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/05/types-of-columns.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7845246305014748739'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7845246305014748739'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/05/types-of-columns.html' title='Types of columns'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-5115199010923329593</id><published>2010-04-30T12:39:00.006+03:00</published><updated>2010-05-01T09:06:26.911+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ETL'/><category scheme='http://www.blogger.com/atom/ns#' term='append'/><title type='text'>How long will it take?</title><content type='html'>Reloading a table.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;truncate table sometable;&lt;br /&gt;&lt;br /&gt;insert /*+append*/ into sometable select ...&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;How long will it take?&lt;br /&gt;&lt;br /&gt;Table is populated earlier and the space consumed will be about the same after reload.&lt;br /&gt;&lt;br /&gt;With following technique I was able to get such an estimate after starting the insert.&lt;br /&gt;&lt;br /&gt;Before truncate see how much space there is to be consumed. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;select sum(bytes) from user_segments where segment_name = 'SOMETABLE';&lt;br /&gt;&lt;br /&gt;4445110272&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Check the execution plan of the insert statement. Ensure it will start consuming space at the beginning of execute.&lt;br /&gt;&lt;br /&gt;Start the load. Identify the session doing the insert statement and estimate.&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;select ((targetb-currb)/currb)*interv+currt estimatedfinnish &lt;br /&gt;  from (&lt;br /&gt; select currt&lt;br /&gt;       -(select sql_exec_start from v$session where sid = :sid)  interv&lt;br /&gt;     , currb, currt&lt;br /&gt;     , :b4445110272 targetb&lt;br /&gt;   from (&lt;br /&gt;  select systimestamp currt&lt;br /&gt;       , sum(bytes) currb &lt;br /&gt;    from user_segments &lt;br /&gt;   where segment_name like 'SOMETABLE' &lt;br /&gt;));&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;That is giving some time in the future. &lt;br /&gt;&lt;br /&gt;Reasons why the estimate is not correct.&lt;br /&gt;&lt;br /&gt;1. The execution plan does not start consuming space at the beginning.&lt;br /&gt;2. The space used before truncate was not the same that it will be at the end of load.&lt;br /&gt;3. Indexes in the table to be populated.&lt;br /&gt;&lt;br /&gt;If there are indexes they are builded after insert phase. Estimate was given for the table to be populated. Index building phase may be monitored by looking at V$SESSION_LONGOPS.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-5115199010923329593?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/5115199010923329593/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/04/how-long-will-it-take.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5115199010923329593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5115199010923329593'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/04/how-long-will-it-take.html' title='How long will it take?'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6525415257072463539</id><published>2010-04-27T21:17:00.004+03:00</published><updated>2010-04-27T21:51:33.766+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='data integrity'/><category scheme='http://www.blogger.com/atom/ns#' term='constraints'/><category scheme='http://www.blogger.com/atom/ns#' term='modeling'/><category scheme='http://www.blogger.com/atom/ns#' term='temporal sql'/><title type='text'>Not overlapping (MV approach)</title><content type='html'>Presented earlier a &lt;a href="http://rafudb.blogspot.com/2009/09/not-overlapping.html"&gt;not overlapping&lt;/a&gt; function based unique indexes approach. In this post I am using a materialized view and a unique constraining that. Several commits seen in here because MV approach makes constraints kind of deferrable. The MV is refreshed at commit phase. As the dirty hack function based unique indexes on the table itself are violated straight at the insert. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;DROP TABLE Z CASCADE CONSTRAINTS PURGE;&lt;br /&gt;&lt;br /&gt;DROP TABLE YEARS CASCADE CONSTRAINTS PURGE;&lt;br /&gt;&lt;br /&gt;DROP MATERIALIZED VIEW Z_MV;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Z(Z NUMBER(16) NOT NULL&lt;br /&gt;             , VALIDFROM NUMBER(4) NOT NULL&lt;br /&gt;             , VALIDTILL NUMBER(4) NOT NULL&lt;br /&gt;             , CONSTRAINT FRO2000 CHECK (2000 &lt; VALIDFROM)&lt;br /&gt;             , CONSTRAINT TIL2050 CHECK (VALIDTILL &lt;= 2050)&lt;br /&gt;             , CONSTRAINT FROTIL CHECK (VALIDFROM &lt;= VALIDTILL)&lt;br /&gt;             );&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE YEARS AS &lt;br /&gt;SELECT 2000+LEVEL TIM FROM DUAL CONNECT BY LEVEL &lt; (2051-2000)&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;CREATE MATERIALIZED VIEW LOG ON Z WITH ROWID&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;CREATE MATERIALIZED VIEW LOG ON YEARS WITH ROWID&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;CREATE MATERIALIZED VIEW Z_MV REFRESH FAST ON COMMIT AS&lt;br /&gt;SELECT Z.ROWID ZRID,T.ROWID TRID,Z.Z,T.TIM &lt;br /&gt;  FROM Z INNER JOIN YEARS T ON VALIDFROM &lt; T.TIM AND T.TIM &lt;= VALIDTILL &lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;With Oracle 11.1.0.7 and 11.2.0.1 getting&lt;br /&gt;ORA-12054: cannot set the ON COMMIT refresh attribute for the materialized view&lt;br /&gt;&lt;br /&gt;No worries. It is about inner join syntax not so widely supported with MVs.&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;CREATE MATERIALIZED VIEW Z_MV REFRESH FAST ON COMMIT AS&lt;br /&gt;SELECT Z.ROWID ZRID,T.ROWID TRID,Z.Z,T.TIM &lt;br /&gt;  FROM Z,YEARS T &lt;br /&gt; WHERE VALIDFROM &lt; T.TIM AND T.TIM &lt;= VALIDTILL &lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;ALTER TABLE Z_MV ADD CONSTRAINT Z_MV_U UNIQUE (Z,TIM);&lt;br /&gt;&lt;br /&gt;CREATE INDEX Z_MV_ZRID_IDX ON Z_MV(ZRID);&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;ZRID indexed to give the optimizer at least a possibility to do small updates "fast". More about the issue may be read from  &lt;a href="http://www.adellera.it/blog/2010/03/11/fast-refresh-of-join-only-mvs-_mv_refresh_use_stats-and-locking-log-stats/"&gt;Alberto Dell'Era's Oracle blog&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO Z VALUES(1,2001,2011);&lt;br /&gt;&lt;br /&gt;INSERT INTO Z VALUES(1,2011,2011);&lt;br /&gt;&lt;br /&gt;COMMIT;&lt;br /&gt;&lt;br /&gt;INSERT INTO Z VALUES(1,2010,2012);&lt;br /&gt;&lt;br /&gt;COMMIT;&lt;br /&gt;&lt;br /&gt;SQL ERROR: ORA-12008: ERROR IN MATERIALIZED VIEW REFRESH PATH&lt;br /&gt;ORA-00001: UNIQUE CONSTRAINT (RAFU.Z_MV_U) VIOLATED&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO Z VALUES(2,2049,2050);&lt;br /&gt;&lt;br /&gt;COMMIT;&lt;br /&gt;&lt;br /&gt;INSERT INTO Z VALUES(2,2049,2050);&lt;br /&gt;&lt;br /&gt;COMMIT;&lt;br /&gt;&lt;br /&gt;SQL ERROR: ORA-12008: ERROR IN MATERIALIZED VIEW REFRESH PATH&lt;br /&gt;ORA-00001: UNIQUE CONSTRAINT (RAFU.Z_MV_U) VIOLATED&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO Z VALUES(2,2010,2012);&lt;br /&gt;&lt;br /&gt;COMMIT;&lt;br /&gt;&lt;br /&gt;INSERT INTO Z VALUES(2,2001,2049);&lt;br /&gt;&lt;br /&gt;COMMIT;&lt;br /&gt;&lt;br /&gt;SQL ERROR: ORA-12008: ERROR IN MATERIALIZED VIEW REFRESH PATH&lt;br /&gt;ORA-00001: UNIQUE CONSTRAINT (RAFU.Z_MV_U) VIOLATED&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO Z VALUES(2,2014,2017);&lt;br /&gt;&lt;br /&gt;COMMIT;&lt;br /&gt;&lt;br /&gt;SELECT * FROM Z ORDER BY Z, VALIDFROM;&lt;br /&gt;&lt;br /&gt;1 2001 2011&lt;br /&gt;1 2011 2011&lt;br /&gt;2 2010 2012&lt;br /&gt;2 2014 2017&lt;br /&gt;2 2049 2050&lt;br /&gt;&lt;br /&gt;SELECT COUNT(*) FROM Z_MV;&lt;br /&gt;&lt;br /&gt;16&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6525415257072463539?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6525415257072463539/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/04/not-overlapping-mv-approach.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6525415257072463539'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6525415257072463539'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/04/not-overlapping-mv-approach.html' title='Not overlapping (MV approach)'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-559295632071486474</id><published>2010-04-27T09:28:00.003+03:00</published><updated>2010-04-27T10:11:42.032+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pl/sql'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance tuning'/><title type='text'>Pipelining</title><content type='html'>In &lt;a href="http://rafudb.blogspot.com/2010/04/reducing-number-of-function-calls.html"&gt;reducing number of function calls&lt;/a&gt; I wrote about how to rewrite a query that is calling a function. Another approach to the issue is to alter the function. The function includes only a SQL clause. The whole result of the clause is bulk collected first and then returned. The usage of the function is in IN clause. IN predicate is satisfied if there is one equality coming out of the select. So in the best cases it is not needed to populate the whole bulk collect inside the function. Using pipelining as an alternative here. &lt;br /&gt;&lt;br /&gt;Original bulk collect version.&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; create or replace type ns_typ is table of number;&lt;br /&gt;  2  /&lt;br /&gt;&lt;br /&gt;Type created.&lt;br /&gt;&lt;br /&gt;SQL&gt; create or replace function rn(n number) return ns_typ is&lt;br /&gt;  2    ret ns_typ;&lt;br /&gt;  3    begin&lt;br /&gt;  4     dbms_lock.sleep(1);&lt;br /&gt;  5     select level bulk collect into ret from dual connect by level &lt;= n;&lt;br /&gt;  6    return ret;&lt;br /&gt;  7  end;&lt;br /&gt;  8  /&lt;br /&gt;&lt;br /&gt;Function created.&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;And the pipelined version of the function.&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; create or replace function rnpiped(n number) return ns_typ pipelined is&lt;br /&gt;  2  begin&lt;br /&gt;  3    for ret in&lt;br /&gt;  4     (select level l from dual connect by level &lt;= n)&lt;br /&gt;  5    loop&lt;br /&gt;  6     dbms_lock.sleep(1/n);&lt;br /&gt;  7     pipe row (ret.l);&lt;br /&gt;  8    end loop;&lt;br /&gt;  9  end;&lt;br /&gt; 10  /&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;If the whole result returned from the function is needed there is no great difference in the execution times. Actually it seems to be increasing a bit.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; select * from table(rn(10));&lt;br /&gt;&lt;br /&gt;COLUMN_VALUE&lt;br /&gt;------------&lt;br /&gt;           1&lt;br /&gt;           2&lt;br /&gt;           3&lt;br /&gt;           4&lt;br /&gt;           5&lt;br /&gt;           6&lt;br /&gt;           7&lt;br /&gt;           8&lt;br /&gt;           9&lt;br /&gt;          10&lt;br /&gt;&lt;br /&gt;10 rows selected.&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:01.00&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select * from table(rnpiped(10));&lt;br /&gt;&lt;br /&gt;COLUMN_VALUE&lt;br /&gt;------------&lt;br /&gt;           1&lt;br /&gt;           2&lt;br /&gt;           3&lt;br /&gt;           4&lt;br /&gt;           5&lt;br /&gt;           6&lt;br /&gt;           7&lt;br /&gt;           8&lt;br /&gt;           9&lt;br /&gt;          10&lt;br /&gt;&lt;br /&gt;10 rows selected.&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:01.07&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;But when used in IN predicate the results with this data are even better than &lt;a href="http://rafudb.blogspot.com/2010/04/reducing-number-of-function-calls.html"&gt;in the previous post&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; select * from ta a where a.n in (select * from table(rn(a.m)));&lt;br /&gt;&lt;br /&gt;         N          M&lt;br /&gt;---------- ----------&lt;br /&gt;         1          2&lt;br /&gt;         2          3&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:&lt;B&gt;10.00&lt;/B&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select * from ta a where a.n in (select * from table(rnpiped(a.m)));&lt;br /&gt;&lt;br /&gt;         N          M&lt;br /&gt;---------- ----------&lt;br /&gt;         1          2&lt;br /&gt;         2          3&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:&lt;B&gt;01.95&lt;/B&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;And putting both together. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; with aa as (&lt;br /&gt;  2    select *&lt;br /&gt;  3      from ta a&lt;br /&gt;  4    ), bb as (&lt;br /&gt;  5    select distinct m&lt;br /&gt;  6      from aa&lt;br /&gt;  7    ), cc as (&lt;br /&gt;  8    select /*+materialize*/ b.m, dd.column_value n&lt;br /&gt;  9      from bb b, table(rn(b.m)) dd)&lt;br /&gt; 10    select *&lt;br /&gt; 11      from aa&lt;br /&gt; 12     where (n,m) in (select n,m from cc)&lt;br /&gt; 13  ;&lt;br /&gt;&lt;br /&gt;         N          M&lt;br /&gt;---------- ----------&lt;br /&gt;         1          2&lt;br /&gt;         2          3&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:&lt;B&gt;03.09&lt;/B&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; with aa as (&lt;br /&gt;  2    select *&lt;br /&gt;  3      from ta a&lt;br /&gt;  4    ), bb as (&lt;br /&gt;  5    select distinct m&lt;br /&gt;  6      from aa&lt;br /&gt;  7    ), cc as (&lt;br /&gt;  8    select /*+materialize*/ b.m, dd.column_value n&lt;br /&gt;  9      from bb b, table(rnpiped(b.m)) dd)&lt;br /&gt; 10    select *&lt;br /&gt; 11      from aa&lt;br /&gt; 12     where (n,m) in (select n,m from cc)&lt;br /&gt; 13  ;&lt;br /&gt;&lt;br /&gt;         N          M&lt;br /&gt;---------- ----------&lt;br /&gt;         1          2&lt;br /&gt;         2          3&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:&lt;B&gt;00.68&lt;/B&gt;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-559295632071486474?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/559295632071486474/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/04/pipelining.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/559295632071486474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/559295632071486474'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/04/pipelining.html' title='Pipelining'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6741158940992356463</id><published>2010-04-23T13:36:00.004+03:00</published><updated>2010-04-23T16:23:23.229+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL tuning'/><title type='text'>Paging before join and aggregation</title><content type='html'>First test data.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;drop table chi purge;&lt;br /&gt;&lt;br /&gt;drop table par purge;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;create table par &lt;br /&gt;( o varchar2(30)&lt;br /&gt;, t varchar2(30)&lt;br /&gt;, n varchar2(30)&lt;br /&gt;, constraint par_pk primary key(o,t,n)) &lt;br /&gt;organization index ;&lt;br /&gt;&lt;br /&gt;create table chi &lt;br /&gt;( o varchar2(30)&lt;br /&gt;, t varchar2(30)&lt;br /&gt;, n varchar2(30)&lt;br /&gt;, c varchar2(30)&lt;br /&gt;, constraint chi_pk primary key(o,t,n,c)&lt;br /&gt;, constraint chi_par_fk foreign key(o,t,n) references par(o,t,n)) &lt;br /&gt;organization index ;&lt;br /&gt;&lt;br /&gt;insert into par select distinct owner, object_type, object_name from dba_objects;&lt;br /&gt;&lt;br /&gt;insert into chi(o,t,n,c) &lt;br /&gt;select distinct ta.owner, ob.object_type, ta.table_name, ta.column_name &lt;br /&gt;from all_tab_columns ta &lt;br /&gt;inner join all_objects ob &lt;br /&gt;   on ta.owner=ob.owner and TA.TABLE_NAME = ob. object_name&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;br /&gt;exec dbms_stats.gather_table_stats(user,'PAR');&lt;br /&gt;&lt;br /&gt;exec dbms_stats.gather_table_stats(user,'CHI');&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Query to start with and the info about execution.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; SELECT n,t,o,cou&lt;br /&gt;  2    FROM (  SELECT pa.o, pa.t, pa.n, COUNT ( * ) cou&lt;br /&gt;  3              FROM par pa LEFT OUTER JOIN chi ch&lt;br /&gt;  4                      ON pa.o = ch.o and pa.t = ch.t and pa.n = ch.n&lt;br /&gt;  5          GROUP BY pa.o, pa.t, pa.n&lt;br /&gt;  6          ORDER BY pa.t, pa.o, pa.n)&lt;br /&gt;  7   WHERE ROWNUM &lt; 3;&lt;br /&gt;&lt;br /&gt;N                              T                              O                                     COU&lt;br /&gt;------------------------------ ------------------------------ ------------------------------ ----------&lt;br /&gt;C_COBJ#                        CLUSTER                        SYS                                     1&lt;br /&gt;C_FILE#_BLOCK#                 CLUSTER                        SYS                                     3&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:02.26&lt;br /&gt;&lt;br /&gt;----------------------------------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation                       | Name   | Starts | E-Rows | A-Rows |   A-Time   | Buffers |&lt;br /&gt;----------------------------------------------------------------------------------------------------&lt;br /&gt;|*  1 |  COUNT STOPKEY                  |        |      1 |        |      2 |00:00:02.19 |    2014 |&lt;br /&gt;|   2 |   VIEW                          |        |      1 |    112K|      2 |00:00:02.19 |    2014 |&lt;br /&gt;|*  3 |    SORT GROUP BY STOPKEY        |        |      1 |    112K|      2 |00:00:02.19 |    2014 |&lt;br /&gt;|   4 |     MERGE JOIN OUTER            |        |      1 |    112K|    166K|00:00:01.93 |    2014 |&lt;br /&gt;|   5 |      SORT JOIN                  |        |      1 |  64558 |  64558 |00:00:00.52 |     666 |&lt;br /&gt;|   6 |       INDEX FULL SCAN DESCENDING| PAR_PK |      1 |  64558 |  64558 |00:00:00.06 |     666 |&lt;br /&gt;|*  7 |      SORT JOIN                  |        |  64558 |    112K|    112K|00:00:00.87 |    1348 |&lt;br /&gt;|   8 |       INDEX FULL SCAN           | CHI_PK |      1 |    112K|    112K|00:00:00.11 |    1348 |&lt;br /&gt;----------------------------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;The alternative to do paging first and aggregate only the rows to be retrieved. &lt;br /&gt;&lt;br /&gt;Paging done in par inline view line 9, order by need to be done on both line 8 for paging and 14 to get the results back in order after joining and aggregating.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt;   SELECT pap.n,&lt;br /&gt;  2           pap.t,&lt;br /&gt;  3           pap.o,&lt;br /&gt;  4           COUNT ( * ) cou&lt;br /&gt;  5      FROM (SELECT *&lt;br /&gt;  6              FROM (  SELECT pa.o, pa.t, pa.n&lt;br /&gt;  7                        FROM par pa&lt;br /&gt;  8                    ORDER BY pa.t, pa.o, pa.n)&lt;br /&gt;  9             WHERE ROWNUM &lt; 3&lt;br /&gt; 10            ) pap&lt;br /&gt; 11       LEFT OUTER JOIN chi ch&lt;br /&gt; 12         ON pap.o = ch.o AND pap.t = ch.t AND pap.n = ch.n&lt;br /&gt; 13  GROUP BY pap.o, pap.t, pap.n&lt;br /&gt; 14  ORDER BY pap.t, pap.o, pap.n;&lt;br /&gt;&lt;br /&gt;N                              T                              O                                     COU&lt;br /&gt;------------------------------ ------------------------------ ------------------------------ ----------&lt;br /&gt;C_COBJ#                        CLUSTER                        SYS                                     1&lt;br /&gt;C_FILE#_BLOCK#                 CLUSTER                        SYS                                     3&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:00.20&lt;br /&gt;&lt;br /&gt;-----------------------------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation                  | Name   | Starts | E-Rows | A-Rows |   A-Time   | Buffers |&lt;br /&gt;-----------------------------------------------------------------------------------------------&lt;br /&gt;|   1 |  SORT GROUP BY NOSORT      |        |      1 |      2 |      2 |00:00:00.20 |     673 |&lt;br /&gt;|   2 |   NESTED LOOPS OUTER       |        |      1 |      2 |      4 |00:00:00.20 |     673 |&lt;br /&gt;|   3 |    VIEW                    |        |      1 |      2 |      2 |00:00:00.20 |     666 |&lt;br /&gt;|*  4 |     COUNT STOPKEY          |        |      1 |        |      2 |00:00:00.20 |     666 |&lt;br /&gt;|   5 |      VIEW                  |        |      1 |  64558 |      2 |00:00:00.20 |     666 |&lt;br /&gt;|*  6 |       SORT ORDER BY STOPKEY|        |      1 |  64558 |      2 |00:00:00.20 |     666 |&lt;br /&gt;|   7 |        INDEX FULL SCAN     | PAR_PK |      1 |  64558 |  64558 |00:00:00.06 |     666 |&lt;br /&gt;|*  8 |    INDEX RANGE SCAN        | CHI_PK |      2 |      1 |      4 |00:00:00.01 |       7 |&lt;br /&gt;-----------------------------------------------------------------------------------------------&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Notice cou column cannot be in order by condition.&lt;br /&gt;Join needs to be outer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6741158940992356463?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6741158940992356463/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/04/paging-before-join-and-aggregation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6741158940992356463'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6741158940992356463'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/04/paging-before-join-and-aggregation.html' title='Paging before join and aggregation'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-5694401317439413062</id><published>2010-04-21T16:13:00.003+03:00</published><updated>2010-04-21T16:34:41.460+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='pl/sql'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance tuning'/><title type='text'>Reducing the number of function calls</title><content type='html'>Using a slow function call in your query? Maybe you are calling it unnecessarily. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; create or replace type ns_typ is table of number;&lt;br /&gt;  2  /&lt;br /&gt;&lt;br /&gt;Type created.&lt;br /&gt;&lt;br /&gt;SQL&gt; create or replace function rn(n number) return ns_typ is&lt;br /&gt;  2  ret ns_typ;&lt;br /&gt;  3  begin&lt;br /&gt;  4   dbms_lock.sleep(1);&lt;br /&gt;  5   select level bulk collect into ret from dual connect by level &lt;= n;&lt;br /&gt;  6  return ret;&lt;br /&gt;  7  end;&lt;br /&gt;  8  /&lt;br /&gt;&lt;br /&gt;Function created.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; create table ta as select level n, mod(level,3)+1 m from dual connect by level &lt;= 10;&lt;br /&gt;&lt;br /&gt;Table created.&lt;br /&gt;&lt;br /&gt;SQL&gt; select * from ta;&lt;br /&gt;&lt;br /&gt;         N          M&lt;br /&gt;---------- ----------&lt;br /&gt;         1          2&lt;br /&gt;         2          3&lt;br /&gt;         3          1&lt;br /&gt;         4          2&lt;br /&gt;         5          3&lt;br /&gt;         6          1&lt;br /&gt;         7          2&lt;br /&gt;         8          3&lt;br /&gt;         9          1&lt;br /&gt;        10          2&lt;br /&gt;&lt;br /&gt;10 rows selected.&lt;br /&gt;&lt;br /&gt;SQL&gt; set timi on&lt;br /&gt;&lt;br /&gt;SQL&gt; select * from ta a where a.n in (select * from table(rn(a.m)));&lt;br /&gt;&lt;br /&gt;         N          M&lt;br /&gt;---------- ----------&lt;br /&gt;         1          2&lt;br /&gt;         2          3&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:&lt;B&gt;10&lt;/B&gt;.01&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;The query is calling rn function for each ten rows of ta table. Each call takes one second as the function is using dbms_lock. There are only three distinct values that the function is needed to be called.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; with aa as (&lt;br /&gt;  2  select *&lt;br /&gt;  3    from ta a&lt;br /&gt;  4  ), bb as (&lt;br /&gt;  5  select distinct m&lt;br /&gt;  6    from aa&lt;br /&gt;  7  ), cc as (&lt;br /&gt;  8  select /*+materialize*/ b.m, dd.column_value n&lt;br /&gt;  9    from bb b, table(rn(b.m)) dd)&lt;br /&gt; 10  select *&lt;br /&gt; 11    from aa&lt;br /&gt; 12   where (n,m) in (select n,m from cc)&lt;br /&gt; 13  ;&lt;br /&gt;&lt;br /&gt;         N          M&lt;br /&gt;---------- ----------&lt;br /&gt;         1          2&lt;br /&gt;         2          3&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:&lt;B&gt;03&lt;/B&gt;.03&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Alternatively you might consider using result cache for the function.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; create or replace function rn(n number) return ns_typ result_cache is&lt;br /&gt;  2  ret ns_typ;&lt;br /&gt;  3  begin&lt;br /&gt;  4   dbms_lock.sleep(1);&lt;br /&gt;  5   select level bulk collect into ret from dual connect by level &lt;= n;&lt;br /&gt;  6  return ret;&lt;br /&gt;  7  end;&lt;br /&gt;  8  /&lt;br /&gt;&lt;br /&gt;Function created.&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:00.04&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select * from ta a where a.n in (select * from table(rn(a.m)));&lt;br /&gt;&lt;br /&gt;         N          M&lt;br /&gt;---------- ----------&lt;br /&gt;         1          2&lt;br /&gt;         2          3&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:03.01&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select * from ta a where a.n in (select * from table(rn(a.m)));&lt;br /&gt;&lt;br /&gt;         N          M&lt;br /&gt;---------- ----------&lt;br /&gt;         1          2&lt;br /&gt;         2          3&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:00.00&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Cleanup&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; drop table ta purge;&lt;br /&gt;SQL&gt; drop function rn;&lt;br /&gt;SQL&gt; drop type ns_typ;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-5694401317439413062?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/5694401317439413062/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/04/reducing-number-of-function-calls.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5694401317439413062'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5694401317439413062'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/04/reducing-number-of-function-calls.html' title='Reducing the number of function calls'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6303118769275016065</id><published>2010-04-16T20:14:00.004+03:00</published><updated>2010-04-16T21:46:26.264+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='temporal sql'/><title type='text'>Packing rows</title><content type='html'>So worth tasting. Having a &lt;a href="http://www.alko.fi/tuotteet/fi/700614"&gt;Keisari Strong&lt;/a&gt; Munchener 5,7% brewed by &lt;a href="http://www.nokianpanimo.fi/"&gt;Nokian panimo&lt;/a&gt;. Figuring out a thing done today. &lt;br /&gt;&lt;br /&gt;The case was that we have a relation that has the &lt;a href="http://rafudb.blogspot.com/2009/09/not-overlapping.html"&gt;only one over time&lt;/a&gt; feature present. There is the possibility that the same attribute is the same in several continuous rows. And we want to put those rows together in a query result. So the question here was how to implement &lt;a href="http://books.google.com/books?id=grTubz0fjSEC&amp;printsec=frontcover&amp;dq=C.J.+Date&amp;lr=&amp;cd=11#v=onepage&amp;q=PACK&amp;f=false"&gt;pack operator&lt;/a&gt; presented in C.J. Date book Temporal data and the relational model. Some good alternatives are presented in Joe Celko's thinking in sets: auxiliary, temporal, and virtual tables in SQL. He presents a &lt;a href="http://books.google.com/books?id=W2Yi4TQaAjwC&amp;printsec=frontcover&amp;dq=Joe+Celko&amp;lr=&amp;cd=5#v=snippet&amp;q=OLAP%20Function%20Solution&amp;f=false"&gt;OLAP Function Solution&lt;/a&gt;. Here we have the not overlapping present so the question is a bit simpler. And to a example...&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;CREATE TABLE Z(Z NUMBER(16) NOT NULL&lt;br /&gt;             , VALIDFROM NUMBER(4) NOT NULL&lt;br /&gt;             , VALIDTILL NUMBER(4) NOT NULL&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;INSERT INTO Z VALUES (1,2000,2003);&lt;br /&gt;&lt;br /&gt;INSERT INTO Z VALUES (1,2003,2004);&lt;br /&gt;&lt;br /&gt;INSERT INTO Z VALUES (2,2004,2005);&lt;br /&gt;&lt;br /&gt;INSERT INTO Z VALUES (2,2005,2008);&lt;br /&gt;&lt;br /&gt;INSERT INTO Z VALUES (1,2008,2010);&lt;br /&gt;&lt;br /&gt;SELECT Z, MINVALIDFROM, MAX(VALIDTILL) MAXVALIDTILL&lt;br /&gt;  FROM (&lt;br /&gt;  SELECT Z, VALIDFROM,VALIDTILL,PREVTILL&lt;br /&gt;       , MAX(CASE WHEN VALIDFROM &lt;= PREVTILL&lt;br /&gt;                  THEN NULL&lt;br /&gt;                  ELSE VALIDFROM&lt;br /&gt;              END) &lt;br /&gt;         OVER ( PARTITION BY Z ORDER BY VALIDFROM, VALIDTILL&lt;br /&gt;                ROWS UNBOUNDED PRECEDING) MINVALIDFROM&lt;br /&gt;    FROM (&lt;br /&gt;    SELECT Z&lt;br /&gt;         , VALIDFROM,VALIDTILL&lt;br /&gt;         , LAG(VALIDTILL) &lt;br /&gt;           OVER (PARTITION BY Z ORDER BY VALIDTILL) PREVTILL&lt;br /&gt;      FROM Z&lt;br /&gt;   ) &lt;br /&gt;)&lt;br /&gt;GROUP BY Z, MINVALIDFROM&lt;br /&gt;ORDER BY MINVALIDFROM, Z&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;1 2000 2004&lt;br /&gt;2 2004 2008&lt;br /&gt;1 2008 2010&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;The simpler part is to use LAG.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6303118769275016065?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6303118769275016065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/04/packing-rows.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6303118769275016065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6303118769275016065'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/04/packing-rows.html' title='Packing rows'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-546150536921739703</id><published>2010-04-09T08:50:00.005+03:00</published><updated>2010-04-09T15:49:03.304+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maintenence'/><title type='text'>Datafile HWM</title><content type='html'>Cleaning up "joins gone wild" application bug. First cleaned up a mess that consumed a lot of space in tablespaces. After that had to move objects with high block_id values so the datafile size may be redused. To avoid hitting the error ORA-03297: file contains used data beyond requested RESIZE value. Alter table move may be used only the objects are not used. If you need to do this as an online operation use &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10577/d_redefi.htm#CBBJJAIF"&gt;DBMS_REDEFINITION&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Generators I used for tablespaces containing only tables.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SELECT file_id,'alter table '||owner||'.'||segment_name||' move'||&lt;br /&gt;   case when segment_type='TABLE PARTITION' then ' PARTITION '||partition_name&lt;br /&gt;        when segment_type='TABLE SUBPARTITION' then ' SUBPARTITION '||partition_name &lt;br /&gt;    end ||';' sq, &lt;br /&gt;MAX(BLOCK_ID) max_block_id,&lt;br /&gt;SEGMENT_NAME, partition_name, SEGMENT_TYPE&lt;br /&gt;  FROM DBA_EXTENTS&lt;br /&gt; WHERE FILE_ID in (4,5,6,7,8)&lt;br /&gt; group by file_id,owner,SEGMENT_NAME, partition_name, SEGMENT_TYPE&lt;br /&gt; having MAX(BLOCK_ID) &gt; 100000&lt;br /&gt; order by file_id,max_block_id desc&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;select 'alter database datafile '||file_id||' resize '||(ceil(max(block_id)*db_block_size/1024/1024/1024))||'G;'&lt;br /&gt;  from dba_extents, (&lt;br /&gt;    select value db_block_size &lt;br /&gt;      from v$parameter &lt;br /&gt;     where name='db_block_size' &lt;br /&gt;     )&lt;br /&gt; where FILE_ID in (4,5,6,7,8)&lt;br /&gt; group by db_block_size,file_id&lt;br /&gt; order by 1&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;Indexes went broken.&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;select 'alter index '||index_name||' rebuild;' from user_indexes where status = 'UNUSABLE' order by 1;&lt;br /&gt;&lt;br /&gt;select 'alter index '||index_name||' rebuild partition '||partition_name||';' from user_ind_partitions where status = 'UNUSABLE' order by 1;&lt;br /&gt;&lt;br /&gt;select 'alter index '||index_name||' rebuild subpartition '||partition_name||';' from user_ind_subpartitions where status = 'UNUSABLE' order by 1;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;Tablespaces including indexes.&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SELECT distinct 'alter index '||owner||'.'||segment_name||' rebuild'||&lt;br /&gt;   case when segment_type='INDEX PARTITION' then ' PARTITION '||partition_name&lt;br /&gt;        when segment_type='INDEX SUBPARTITION' then ' SUBPARTITION '||partition_name &lt;br /&gt;    end ||' online;' sq, &lt;br /&gt;MAX(BLOCK_ID) max_block_id&lt;br /&gt;  FROM DBA_EXTENTS&lt;br /&gt; WHERE FILE_ID in (9,10,11,12,13)&lt;br /&gt; group by file_id,owner,SEGMENT_NAME, partition_name, SEGMENT_TYPE&lt;br /&gt; having MAX(BLOCK_ID) &gt; 100000&lt;br /&gt; order by file_id,max_block_id desc&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;And after that datafile resize.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-546150536921739703?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/546150536921739703/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/04/datafile-hwm.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/546150536921739703'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/546150536921739703'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/04/datafile-hwm.html' title='Datafile HWM'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-7992836290657397792</id><published>2010-04-06T17:44:00.002+03:00</published><updated>2011-09-27T16:21:21.011+03:00</updated><title type='text'>Anoying Toad</title><content type='html'>Two anoying features of Toad. Use SQLPLUS or SQL Developer instead.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;create table pa(p number constraint pa_pk primary key) &lt;br /&gt;partition by hash(p) &lt;br /&gt;partitions 2;&lt;br /&gt;&lt;br /&gt;select partition_name from user_tab_partitions where table_name = 'PA';&lt;br /&gt;&lt;br /&gt;SYS_P61&lt;br /&gt;SYS_P62&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Truncating a partition with Toad gives an error.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;alter table pa truncate partition SYS_P61;&lt;br /&gt;&lt;br /&gt;ORA-14006: invalid partition name&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Modifying index visibility with Toad gives an error.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;alter index pa_pk invisible;&lt;br /&gt;&lt;br /&gt;ORA-14141: ALTER INDEX VISIBLE|INVISIBLE may not be combined with other operations&lt;br /&gt;&lt;br /&gt;alter index pa_pk visible;&lt;br /&gt;&lt;br /&gt;ORA-14141: ALTER INDEX VISIBLE|INVISIBLE may not be combined with other operations&lt;br /&gt;&lt;/pre&gt;Just get rid of the semi colon and you are able to use these commands with Toad.&lt;PRE&gt;&lt;br /&gt;alter index pa_pk visible&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-7992836290657397792?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/7992836290657397792/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/04/anoying-toad.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7992836290657397792'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7992836290657397792'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/04/anoying-toad.html' title='Anoying Toad'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6166546440357442801</id><published>2010-04-04T00:01:00.003+03:00</published><updated>2011-10-23T09:52:25.577+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL tuning'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance tuning'/><title type='text'>A dark side of Easter</title><content type='html'>It was an Easter a while ago. I had a bottle of Finnish porter beer. It was made by &lt;a href="http://www.laitilan.com/"&gt;Laitilan&lt;/a&gt; breweries. My mother in law got some of it and made it clear that it tasted like mämmi. She put some vanilla sauce in the class and the taste was, well similar like mämmi with vanilla sauce. This year Laitilan breweries has a bottle that has a yellow lable saying Mämmi on it. They have actually made beer out of mämmi. Well if you do not know what mämmi is take alook of something else from Finnish kitchen called &lt;a href="http://www.youtube.com/watch?v=cgE9G5QGs54"&gt;Kalakukko&lt;/a&gt;. They make that mainly in Kuopio. I had an exiting evening in Hakametsä. Ice hockey arena in Tampere. My favourite ice hockey team Tappara just won Kalpa - a team from Kuopio. &lt;br /&gt;&lt;br /&gt;Putting things together that do not actually have nothing to do with each other make sometimes wheels running. Ice hockey and mämmi have nothing in common like vanilla sauce and Kuopio. During last year I have had several occasions when the ideas from &lt;a href="http://www.spatialdbadvisor.com/"&gt;spatial advisor&lt;/a&gt; have came to the rescue. There have been several cases when I have been dealing with query performance problems with temporal data. Well spatial information is more close to temporal than Kalpa is to Laitila. These ideas have come to the rescue several times when the number count in tables have increased from a million to ten or hundred million. Changing a traditional b-tree index to a function based locator index and a query where predicate to use that has helped the response time to be usable. Joining similar table with greater than or between comparison has also been a troublesome to deal with. Using those function based locator indexes and &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e11830/sdo_operat.htm#SPATL1030"&gt;sdo_join&lt;/a&gt; have helped a lot. &lt;br /&gt;&lt;br /&gt;Lets have a simple example not from those real life experiences like I did not reveal &lt;a href="http://rafudb.blogspot.com/2010/03/parallel-query-distribution-methods.html"&gt;earlier&lt;/a&gt;. Lets copy the base situation from &lt;a href="http://rafudb.blogspot.com/2009/04/sum-over-time.html"&gt;sum over time&lt;/a&gt; writing. Notable here is that the locator indexing is available also in free XE version and also SE and EE. The basic idea for function based locator index may be expressed like &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;DROP TABLE T CASCADE CONSTRAINTS PURGE;&lt;br /&gt;&lt;br /&gt;DROP FUNCTION TF;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE T (FRO DATE, TIL DATE, N NUMBER);&lt;br /&gt;&lt;br /&gt;INSERT INTO T VALUES (TO_DATE('09.04.2009','dd.mm.yyyy'), TO_DATE('10.04.2009','dd.mm.yyyy'), 1);&lt;br /&gt;&lt;br /&gt;INSERT INTO T VALUES (TO_DATE('10.04.2009','dd.mm.yyyy'), TO_DATE('12.04.2009','dd.mm.yyyy'), 2);&lt;br /&gt;&lt;br /&gt;INSERT INTO T VALUES (TO_DATE('11.04.2009','dd.mm.yyyy'), TO_DATE('14.04.2009','dd.mm.yyyy'), 3);&lt;br /&gt;&lt;br /&gt;COMMIT;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Query performing not with satisfactory response time. &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SELECT * &lt;br /&gt;  FROM T &lt;br /&gt; WHERE TIL &amp;gt;= TO_DATE('11.04.2009','dd.mm.yyyy') &lt;br /&gt;   AND FRO &amp;lt;= TO_DATE('14.04.2009','dd.mm.yyyy')&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;10.04.2009 12.04.2009 2&lt;br /&gt;11.04.2009 14.04.2009 3&lt;br /&gt;&lt;br /&gt;CREATE OR REPLACE FUNCTION TF(FRO DATE, TIL DATE) RETURN SDO_GEOMETRY deterministic as &lt;br /&gt;BEGIN&lt;br /&gt;RETURN MDSYS.SDO_GEOMETRY(2002,NULL, NULL, SDO_ELEM_INFO_ARRAY (1,2,1),&lt;br /&gt;    SDO_ORDINATE_ARRAY(to_number(to_char(FRO,'j')),0,to_number(to_char(TIL,'j')),0));&lt;br /&gt;END;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;SELECT TO_CHAR(to_date('19000101','yyyymmdd'),'J'),TO_CHAR(to_date('22000101','yyyymmdd'),'J') FROM dual;&lt;br /&gt;&lt;br /&gt;--2415021 2524594&lt;br /&gt;&lt;br /&gt;DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = 'T';&lt;br /&gt;&lt;br /&gt;INSERT INTO USER_SDO_GEOM_METADATA(TABLE_NAME,COLUMN_NAME,DIMINFO)&lt;br /&gt;  VALUES (&lt;br /&gt;  'T',&lt;br /&gt;  'RAFU.TF(FRO,TIL)',&lt;br /&gt;  SDO_DIM_ARRAY(&lt;br /&gt;    SDO_DIM_ELEMENT('X', 2415021, 2524594, 0.5),&lt;br /&gt;    SDO_DIM_ELEMENT('Y', 0, 0, 0.5)&lt;br /&gt;     )&lt;br /&gt;  )&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;COMMIT;&lt;br /&gt;&lt;br /&gt;CREATE INDEX T_LOCATOR_IDX ON T(TF(FRO,TIL))&lt;br /&gt;  INDEXTYPE IS mdsys.spatial_index;&lt;br /&gt;&lt;br /&gt;SELECT * &lt;br /&gt;  FROM T &lt;br /&gt; WHERE SDO_FILTER(TF(FRO,TIL),&lt;br /&gt;                  TF(TO_DATE('11.04.2009','dd.mm.yyyy')&lt;br /&gt;                    ,TO_DATE('14.04.2009','dd.mm.yyyy'))&lt;br /&gt;                 ) = 'TRUE'&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;10.04.2009 12.04.2009 2&lt;br /&gt;11.04.2009 14.04.2009 3&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Just try with your own temporal data and &lt;a href="http://rafudb.blogspot.com/2010/01/visualizing-plans.html"&gt;PlanViz&lt;/a&gt; and compare the a-rows inside your query. &lt;br /&gt;&lt;br /&gt;An another thing that I sayed in &lt;a href="http://rafudb.blogspot.com/2009/04/sum-over-time.html"&gt;sum over time&lt;/a&gt; writing was "I like to see continous pair stored as open ended". It is just one thing to deal with this approach. SQL standard by the way says that the end in time interval should not be included in the interval. But if the end is the same than the start moment then the interval is presenting the one spot in the timeline. So in that case the end is not excluding.&lt;br /&gt;&lt;br /&gt;Yet another thing about timelines and my earlier postings. Last year I wrote about some ideas about &lt;a href="http://rafudb.blogspot.com/2009/10/not-overlapping-daily.html"&gt;not overlapping daily&lt;/a&gt;. The idea presented in this post might near to the answer missing in that post. But it is not possible to create a domain index as a unique.&lt;br /&gt;&lt;br /&gt;By the way Mämmi beer with vanilla sauce got called today white russian by my mother in law. Wonder what might &lt;a href="http://www.imdb.com/title/tt0118715/"&gt;Dude in Big Lebowski&lt;/a&gt; say about that.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6166546440357442801?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6166546440357442801/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/04/dark-side-of-easter.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6166546440357442801'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6166546440357442801'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/04/dark-side-of-easter.html' title='A dark side of Easter'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-918209901886760741</id><published>2010-03-28T18:58:00.004+03:00</published><updated>2010-03-28T19:54:29.658+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL tuning'/><title type='text'>Visualizing plans grants</title><content type='html'>A while ago I &lt;a href="http://rafudb.blogspot.com/2010/01/visualizing-plans.html"&gt;post about to use plan visualization&lt;/a&gt; by Tanel Poder. That has been a tool worth using. Thou that should be a tool also to other developers than DBAs. A-Rows and A-Time are such valuable information about the execution bottlenecs inside SQL execution.&lt;br /&gt;&lt;br /&gt;How to get it working without dba rights.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));&lt;br /&gt;&lt;br /&gt;PLAN_TABLE_OUTPUT&lt;br /&gt;-------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;User has no SELECT privilege on V$SESSION&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;It is not possible to grant select rights straight to v$ views &lt;a href="http://coskan.wordpress.com/2007/03/07/how-to-grant-to-v-views/"&gt;as Coscan has writen&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;grant select on v_$session to rafu;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;And a try&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));&lt;br /&gt;&lt;br /&gt;PLAN_TABLE_OUTPUT&lt;br /&gt;-------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;User has no SELECT privilege on V$SQL_PLAN_STATISTICS_ALL&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Giving a grant&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;grant select on v_$sql_plan_statistics_all to rafu;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;And after that no success. The same output.&lt;br /&gt;11.2 documentation says that to use DBMS_XPLAN.DISPLAY_CURSOR the calling user must have SELECT privilege on the fixed views V$SQL_PLAN_STATISTICS_ALL, V$SQL and V$SQL_PLAN views.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;grant select on v_$sql_plan to rafu;&lt;br /&gt;&lt;br /&gt;grant select on v_$sql to rafu;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;And we are there. User rafu may use DBMS_XPLAN.DISPLAY_CURSOR with sql_id=&gt;null parameter. Also grant alter session to avoid the need to use gather_plan_statistics hint might be recommended. That is how you enable ALTER SESSION SET statistics_level = ALL;&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;grant alter session to rafu;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Also giving these grants through a role to developer users is worth considering.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-918209901886760741?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/918209901886760741/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/03/visualizing-plans-grants.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/918209901886760741'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/918209901886760741'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/03/visualizing-plans-grants.html' title='Visualizing plans grants'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-8903193166518815764</id><published>2010-03-26T04:13:00.006+02:00</published><updated>2010-03-26T04:48:06.338+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='modeling'/><title type='text'>Pivoting EAV</title><content type='html'>If you are responsible for designing a data model and just consider to invent again and create this fine generic entity attribute value structure, maybe you should consider attending some teaching about the issue. For example some available soon by C.J. Date &lt;a href="http://kantamestarit.fi/Files/Chris_Date_Seminar_Helsinki_2010.pdf"&gt;in&lt;/a&gt; and &lt;a href="http://ougf.fi/"&gt;near&lt;/a&gt; Finland.&lt;br /&gt;&lt;br /&gt;Well maybe you have a EAV model that you have to deal with. Example&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; create table eav as&lt;br /&gt;  2  select 1 e, 'first' a, 'Timo' v from dual union all&lt;br /&gt;  3  select 1 e, 'last' a, 'Raitalaakso' v  from dual union all&lt;br /&gt;  4  select 1 e, 'nic' a, 'Rafu' v  from dual union all&lt;br /&gt;  5  select 2 e, 'first' a, 'John' v  from dual union all&lt;br /&gt;  6  select 2 e, 'last' a, 'Doe' v from dual&lt;br /&gt;  7  ;&lt;br /&gt;&lt;br /&gt;Table created.&lt;br /&gt;&lt;br /&gt;SQL&gt; select * from eav;&lt;br /&gt;&lt;br /&gt;         E A     V&lt;br /&gt;---------- ----- -----------&lt;br /&gt;         1 first Timo&lt;br /&gt;         1 last  Raitalaakso&lt;br /&gt;         1 nic   Rafu&lt;br /&gt;         2 first John&lt;br /&gt;         2 last  Doe&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;You should not query it in a basic case using joins. Most possibly you have tens of joins to the same table.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; select la.e, fi.v firs, la.v las&lt;br /&gt;  2    from eav la, eav fi&lt;br /&gt;  3   where la.e=fi.e&lt;br /&gt;  4     and fi.a='first'&lt;br /&gt;  5     and la.a='last'&lt;br /&gt;  6  ;&lt;br /&gt;&lt;br /&gt;         E FIRS        LAS&lt;br /&gt;---------- ----------- -----------&lt;br /&gt;         1 Timo        Raitalaakso&lt;br /&gt;         2 John        Doe&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;It is a pivot you want to do. &lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; select e, firs, las&lt;br /&gt;  2    from eav&lt;br /&gt;  3    pivot (max(v) for a in ('first' as firs, 'last' as las))&lt;br /&gt;  4  ;&lt;br /&gt;&lt;br /&gt;         E FIRS        LAS&lt;br /&gt;---------- ----------- -----------&lt;br /&gt;         1 Timo        Raitalaakso&lt;br /&gt;         2 John        Doe&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;With the pivot you get the nullable columns also easier without filtering out the whole entity&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; select e, firs, las, ni&lt;br /&gt;  2    from eav&lt;br /&gt;  3    pivot (max(v) for a in ('first' as firs, 'last' as las, 'nic' as ni))&lt;br /&gt;  4  ;&lt;br /&gt;&lt;br /&gt;         E FIRS        LAS         NI&lt;br /&gt;---------- ----------- ----------- -----------&lt;br /&gt;         1 Timo        Raitalaakso Rafu&lt;br /&gt;         2 John        Doe&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;Maybe you do not have 11g features available.&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; select e&lt;br /&gt;  2       , max(case when a = 'first' then v end) firs&lt;br /&gt;  3       , max(case when a = 'last' then v end) las&lt;br /&gt;  4    from eav&lt;br /&gt;  5   group by e&lt;br /&gt;  6  ;&lt;br /&gt;&lt;br /&gt;         E FIRS        LAS&lt;br /&gt;---------- ----------- -----------&lt;br /&gt;         1 Timo        Raitalaakso&lt;br /&gt;         2 John        Doe&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;And the best thing to do with it might be.&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; drop table eav purge;&lt;br /&gt;&lt;br /&gt;Table dropped.&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-8903193166518815764?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/8903193166518815764/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/03/pivoting-eav.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8903193166518815764'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8903193166518815764'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/03/pivoting-eav.html' title='Pivoting EAV'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6919022431093729440</id><published>2010-03-11T21:03:00.003+02:00</published><updated>2010-03-11T21:13:50.220+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='parallel SQL'/><title type='text'>Parallel query distribution methods</title><content type='html'>Figuring out should I recommend parallelizing materialized view refresh for several mvs or use parallel partition wise joins. Found valuable help for the issue just yesterday by &lt;a href="http://tonyhasler.wordpress.com/2010/03/10/parallel-query-distribution-methods/"&gt;Tony Hasler&lt;/a&gt;. Will be using both. Unfortunately no blog writing coming up about the issue.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6919022431093729440?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6919022431093729440/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/03/parallel-query-distribution-methods.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6919022431093729440'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6919022431093729440'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/03/parallel-query-distribution-methods.html' title='Parallel query distribution methods'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-4527970958970460156</id><published>2010-03-05T23:41:00.004+02:00</published><updated>2010-03-08T12:51:27.680+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>not in null countdown</title><content type='html'>Just a reminder about not in and nulls. Maybe consider using not exists or anti join if any of the columns in not in list may be null. Or maybe one of the following might be the result you want.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; create table nm as&lt;br /&gt;  2  with le as (select level ev from dual connect by level&lt;4)&lt;br /&gt;  3  select l.ev e,e.ev v from le l, le e;&lt;br /&gt;&lt;br /&gt;Table created.&lt;br /&gt;&lt;br /&gt;SQL&gt; select count(*) from nm;&lt;br /&gt;&lt;br /&gt;  COUNT(*)&lt;br /&gt;----------&lt;br /&gt;         9&lt;br /&gt;&lt;br /&gt;SQL&gt; select count(*) from nm where (e,v) not in ((1,1));&lt;br /&gt;&lt;br /&gt;  COUNT(*)&lt;br /&gt;----------&lt;br /&gt;         8&lt;br /&gt;&lt;br /&gt;SQL&gt; select count(*) from nm where (e,v) not in ((1,1),(2,2));&lt;br /&gt;&lt;br /&gt;  COUNT(*)&lt;br /&gt;----------&lt;br /&gt;         7&lt;br /&gt;&lt;br /&gt;SQL&gt; select count(*) from nm where (e,v) not in ((1,null));&lt;br /&gt;&lt;br /&gt;  COUNT(*)&lt;br /&gt;----------&lt;br /&gt;         6&lt;br /&gt;&lt;br /&gt;SQL&gt; select count(*) from nm where (e,v) not in ((1,1),(2,null));&lt;br /&gt;&lt;br /&gt;  COUNT(*)&lt;br /&gt;----------&lt;br /&gt;         5&lt;br /&gt;&lt;br /&gt;SQL&gt; select count(*) from nm where (e,v) not in ((null,1),(2,null));&lt;br /&gt;&lt;br /&gt;  COUNT(*)&lt;br /&gt;----------&lt;br /&gt;         4&lt;br /&gt;&lt;br /&gt;SQL&gt; select count(*) from nm where (e,v) not in ((1,null),(2,null));&lt;br /&gt;&lt;br /&gt;  COUNT(*)&lt;br /&gt;----------&lt;br /&gt;         3&lt;br /&gt;&lt;br /&gt;SQL&gt; select count(*) from nm where (e,v) not in ((1,null),(2,null),(3,3));&lt;br /&gt;&lt;br /&gt;  COUNT(*)&lt;br /&gt;----------&lt;br /&gt;         2&lt;br /&gt;&lt;br /&gt;SQL&gt; select count(*) from nm where (e,v) not in ((null,1),(null,2),(1,3),(2,3));&lt;br /&gt;&lt;br /&gt;  COUNT(*)&lt;br /&gt;----------&lt;br /&gt;         1&lt;br /&gt;&lt;br /&gt;SQL&gt; select count(*) from nm where (e,v) not in ((null,null),(1,1));&lt;br /&gt;&lt;br /&gt;  COUNT(*)&lt;br /&gt;----------&lt;br /&gt;         0&lt;br /&gt;&lt;br /&gt;SQL&gt; select count(*)&lt;br /&gt;  2    from nm m&lt;br /&gt;  3   where not exists (select n&lt;br /&gt;  4                       from (select null n from dual) d&lt;br /&gt;  5                      where m.v = d.n&lt;br /&gt;  6                        and m.e = d.n);&lt;br /&gt;&lt;br /&gt;  COUNT(*)&lt;br /&gt;----------&lt;br /&gt;         9&lt;br /&gt;&lt;br /&gt;SQL&gt; select count(*)&lt;br /&gt;  2    from nm m&lt;br /&gt;  3     left outer join (select 10 e, null n from dual) d&lt;br /&gt;  4       on m.e=d.e&lt;br /&gt;  5  where d.n is null;&lt;br /&gt;&lt;br /&gt;  COUNT(*)&lt;br /&gt;----------&lt;br /&gt;         9&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-4527970958970460156?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/4527970958970460156/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/03/not-in-null-countdown.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/4527970958970460156'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/4527970958970460156'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/03/not-in-null-countdown.html' title='not in null countdown'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-8111574084614201552</id><published>2010-02-14T17:35:00.004+02:00</published><updated>2010-02-14T17:44:39.687+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>Data types in a view</title><content type='html'>Is there actually a TIME data type in Oracle? What is the data type of null? Boolean is a number or is it? &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; create view v as&lt;br /&gt;  2  select null nul&lt;br /&gt;  3       , time '12:00:00' tim&lt;br /&gt;  4       , dbms_session.is_role_enabled('CREATE SESSION') boo&lt;br /&gt;  5   from dual&lt;br /&gt;  6  ;&lt;br /&gt;&lt;br /&gt;View created.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select column_name,data_type,data_length&lt;br /&gt;  2    from user_tab_columns&lt;br /&gt;  3   where table_name = 'V'&lt;br /&gt;  4   order by 1&lt;br /&gt;  5  ;&lt;br /&gt;&lt;br /&gt;COLUMN_NAME  DATA_TYPE    DATA_LENGTH&lt;br /&gt;------------ ------------ -----------&lt;br /&gt;BOO          NUMBER                22&lt;br /&gt;NUL          VARCHAR2               &lt;B&gt;0&lt;/B&gt;&lt;br /&gt;TIM          &lt;B&gt;TIME(9)&lt;/B&gt;               20&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select nul from v;&lt;br /&gt;&lt;br /&gt;N&lt;br /&gt;-&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select tim from v;&lt;br /&gt;&lt;br /&gt;TIM&lt;br /&gt;--------------------------------------------------------------&lt;br /&gt;12:00:00,000000000&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select boo from v;&lt;br /&gt;select boo from v&lt;br /&gt;                *&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-06552: PL/SQL: Statement ignored&lt;br /&gt;ORA-06553: PLS-382: expression is of wrong type&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;null and time types from &lt;a href="http://laurentschneider.com/wordpress/2010/02/what-is-the-type-of-null.html"&gt;Laurent Schneider&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-8111574084614201552?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/8111574084614201552/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/02/data-types-in-view.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8111574084614201552'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8111574084614201552'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/02/data-types-in-view.html' title='Data types in a view'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-8857529002312267289</id><published>2010-02-12T23:46:00.002+02:00</published><updated>2010-02-12T23:52:49.569+02:00</updated><title type='text'>Open position</title><content type='html'>It has been a while since Pirjo Salo wrote about &lt;a href="http://www.tietoviikko.fi/blogit/kolumni/article154848.ece"&gt;job opportunities&lt;/a&gt; for database specialist in Finland. Be aware something to be &lt;a href="http://www.solita.fi/career"&gt;available soon&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-8857529002312267289?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/8857529002312267289/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/02/open-position.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8857529002312267289'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8857529002312267289'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/02/open-position.html' title='Open position'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-2804029597888536908</id><published>2010-02-08T10:02:00.004+02:00</published><updated>2011-03-11T10:44:56.672+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>Equality -comparing text</title><content type='html'>Should we use case clause or still use decode? Yet again someting to be aware. Seems like case clause is trimming before comparing. And the same with DB2 minus. Postgres does not trim.&lt;br /&gt;&lt;br /&gt;&lt;B&gt;Oracle&lt;/B&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; select case when 'a' = 'a ' then 'same' else 'different' end as test from dual;&lt;br /&gt; &lt;br /&gt;TEST&lt;br /&gt;---------&lt;br /&gt;same&lt;br /&gt; &lt;br /&gt;SQL&gt; select 'a' from dual minus select 'a ' from dual;&lt;br /&gt; &lt;br /&gt;'A&lt;br /&gt;--&lt;br /&gt;a&lt;br /&gt;&lt;br /&gt;SQL&gt; select decode('a','a ','same','different') testdecode from dual;&lt;br /&gt;&lt;br /&gt;TESTDECOD&lt;br /&gt;---------&lt;br /&gt;different&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt; &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;B&gt;DB2&lt;/B&gt;&lt;br /&gt; &lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;db2 =&gt; select case when 'a' = 'a ' then 'same' else 'different' end as test from sysibm.sysdummy1&lt;br /&gt; &lt;br /&gt;TEST&lt;br /&gt;---------&lt;br /&gt;same&lt;br /&gt; &lt;br /&gt; 1 record(s) selected.&lt;br /&gt; &lt;br /&gt;db2 =&gt; select 'a' from sysibm.sysdummy1 minus select 'a ' from sysibm.sysdummy1&lt;br /&gt; &lt;br /&gt;1&lt;br /&gt;--&lt;br /&gt; &lt;br /&gt; 0 record(s) selected.&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;&lt;B&gt;Postgres&lt;/B&gt;&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;postgres=# select case when 'a' = 'a ' then 'same' else 'different' end as test ;&lt;br /&gt;   test&lt;br /&gt;-----------&lt;br /&gt; different&lt;br /&gt;(1 row)&lt;br /&gt;&lt;br /&gt;postgres=# select 'a' as a except select 'a ' as a;&lt;br /&gt; a&lt;br /&gt;---&lt;br /&gt; a&lt;br /&gt;(1 row)&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;&lt;B&gt;SQL Server&lt;br /&gt;&lt;/B&gt;&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;1&gt; select case when 'a' = 'a ' then 'same' else 'different' end as test ;&lt;br /&gt;2&gt; go&lt;br /&gt;test&lt;br /&gt;----&lt;br /&gt;same&lt;br /&gt;&lt;br /&gt;(1 rows affected)&lt;br /&gt;1&gt;&lt;br /&gt;2&gt; select 'a'&lt;br /&gt;3&gt; except&lt;br /&gt;4&gt; select 'a '&lt;br /&gt;5&gt; go&lt;br /&gt;&lt;br /&gt;--&lt;br /&gt;&lt;br /&gt;(0 rows affected)&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-2804029597888536908?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/2804029597888536908/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/02/equality-comparing-text.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2804029597888536908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2804029597888536908'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/02/equality-comparing-text.html' title='Equality -comparing text'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-4546311750830903232</id><published>2010-01-25T12:53:00.004+02:00</published><updated>2010-11-04T08:25:19.586+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pl/sql'/><title type='text'>select into</title><content type='html'>How come lines 9 and 10 do not execute in the following is_active function? Documentation says that use into_clause only when there is one row in the result. Should the remaining code be ignored when there are no rows. Be sure to have exactly that one row available when using select into structure. Count(*) is a way here to be sure there is the one row.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; CREATE OR REPLACE function is_active(i_is_active number)&lt;br /&gt; 2      return number as&lt;br /&gt; 3      ret number := 0;&lt;br /&gt; 4  begin&lt;br /&gt; 5      dbms_output.put_line('-'||ret||'-before-'||i_is_active||'-');&lt;br /&gt; 6      select 1 into ret&lt;br /&gt; 7        from dual&lt;br /&gt; 8       where i_is_active = 1;&lt;br /&gt; 9      dbms_output.put_line('-'||ret||'-after -'||i_is_active||'-');&lt;br /&gt;10      if ret is null then ret := 0;&lt;br /&gt;11      end if;&lt;br /&gt;12      return ret;&lt;br /&gt;13  end;&lt;br /&gt;14  /&lt;br /&gt;&lt;br /&gt;Function created.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select is_active(1),is_active(0) from dual&lt;br /&gt; 2  ;&lt;br /&gt;&lt;br /&gt;IS_ACTIVE(1) IS_ACTIVE(0)&lt;br /&gt;------------ ------------&lt;br /&gt;          1&lt;br /&gt;&lt;br /&gt;-0-before-1-&lt;br /&gt;-1-after -1-&lt;br /&gt;-0-before-0-&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; CREATE OR REPLACE function is_active_usingcount(i_is_active number)&lt;br /&gt; 2      return number as&lt;br /&gt; 3      ret number := 0;&lt;br /&gt; 4  begin&lt;br /&gt; 5      dbms_output.put_line('-'||ret||'-before-'||i_is_active||'-');&lt;br /&gt; 6      select count(*) into ret&lt;br /&gt; 7        from dual&lt;br /&gt; 8       where i_is_active = 1;&lt;br /&gt; 9      dbms_output.put_line('-'||ret||'-after -'||i_is_active||'-');&lt;br /&gt;10      return ret;&lt;br /&gt;11  end;&lt;br /&gt;12  /&lt;br /&gt;&lt;br /&gt;Function created.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select is_active_usingcount(1),is_active_usingcount(0) from dual&lt;br /&gt; 2  ;&lt;br /&gt;&lt;br /&gt;IS_ACTIVE_USINGCOUNT(1) IS_ACTIVE_USINGCOUNT(0)&lt;br /&gt;----------------------- -----------------------&lt;br /&gt;                     1                       0&lt;br /&gt;&lt;br /&gt;-0-before-1-&lt;br /&gt;-1-after -1-&lt;br /&gt;-0-before-0-&lt;br /&gt;-0-after -0-&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You get "ORA-01422: exact fetch returns more than requested number of rows" if there are more than one row. Should there be an exception also to the case when there are no rows?&lt;br /&gt;&lt;br /&gt;Update 4.11.2010:&lt;br /&gt;Well there is a exception thrown. Just not catching it anywhere.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;CREATE OR REPLACE function is_active(i_is_active number)&lt;br /&gt;       return number as&lt;br /&gt;       ret number := 0;&lt;br /&gt;  begin&lt;br /&gt;       dbms_output.put_line('-'||ret||'-before-'||i_is_active||'-');&lt;br /&gt;       select 1 into ret&lt;br /&gt;       from dual&lt;br /&gt;      where i_is_active = 1;&lt;br /&gt;     dbms_output.put_line('-'||ret||'-after -'||i_is_active||'-');&lt;br /&gt;     if ret is null then ret := 0;&lt;br /&gt;     end if;&lt;br /&gt;     return ret;&lt;br /&gt;&lt;b&gt;      EXCEPTION&lt;br /&gt;        WHEN NO_DATA_FOUND THEN return -1;&lt;br /&gt;&lt;/b&gt;    end;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;select is_active(1),is_active(0) from dual;&lt;br /&gt;&lt;br /&gt;IS_ACTIVE(1) IS_ACTIVE(0)&lt;br /&gt;------------ ------------&lt;br /&gt;1            -1&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-4546311750830903232?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/4546311750830903232/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/01/select-into.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/4546311750830903232'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/4546311750830903232'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/01/select-into.html' title='select into'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-5592083703247559680</id><published>2010-01-22T21:27:00.004+02:00</published><updated>2010-01-22T22:54:59.476+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='dba work'/><category scheme='http://www.blogger.com/atom/ns#' term='constraints'/><title type='text'>Only one (yet again)</title><content type='html'>Is that not a normal DBA work week. &lt;br /&gt;Installing Oracle on HP-UX cluster&lt;br /&gt;Trying to resolve problematic CPU usage -Solaris  &lt;br /&gt;Rewriting loooong query more readable&lt;br /&gt;Fiquring out 9.2 RAC&lt;br /&gt;Talking about a PL/SQL function having comments from the 90's&lt;br /&gt;Talking about modeling tools&lt;br /&gt;Partitioning postgresql&lt;br /&gt;A very good chinese dinner at Dong Bei Hu&lt;br /&gt;Some dark beer&lt;br /&gt;Night in a hotel&lt;br /&gt;Reading awr reports and creating some of my own &lt;br /&gt;Making ssh connections to a 10.2 RAC environment&lt;br /&gt;Installing 11.2&lt;br /&gt;Dumping a datafile block, boy that wait information in v$session mislead me. Should have used &lt;a href="http://blog.tanelpoder.com/2007/12/06/oracle-session-snapper-v106-released/"&gt;snapper&lt;/a&gt;. Well the blocks were the same both in primary and standby&lt;br /&gt;Rewriting that loooong query so that it will perform when there will be 10M rows in the future&lt;br /&gt;Sitting in a company meeting and hearing that Solita is recruiting new people&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Luckily some actual modeling work also. How to constrain a model where there is a variation of &lt;a href="http://rafudb.blogspot.com/2009/09/only-one-alternative-2.html"&gt;the only one&lt;/a&gt; problem. The difference here was that a country does not have to have a default currency. But if it has any currencies there has to be one as a default. And also a restriction that no virtual columns. Oracle version 10.2. In the following example currencies goes to A table and countries to D.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;drop  materialized view da_atleast_one_mv;&lt;br /&gt;&lt;br /&gt;drop table a cascade constraints purge;&lt;br /&gt;&lt;br /&gt;drop table d cascade constraints purge;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;create table d(d_id number primary key, current_a_id number)&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;create table a(a_id number primary key&lt;br /&gt;             , d_id references d not null&lt;br /&gt;             , constraint a_u unique(d_id,a_id))&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;alter table d add constraint d_curr_fk foreign key (d_id,current_a_id) references a(d_id,a_id) deferrable initially deferred;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;create materialized view log on d with rowid;&lt;br /&gt;&lt;br /&gt;create materialized view log on a with rowid;&lt;br /&gt;&lt;br /&gt;create materialized view da_atleast_one_mv &lt;br /&gt;refresh on commit as &lt;br /&gt;select d.rowid drid, a.rowid arid, d.d_id, a.a_id&lt;br /&gt;  from d, a&lt;br /&gt; where d.current_a_id(+)=a.a_id&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;alter table da_atleast_one_mv modify d_id constraint da_atleast_one_nn not null;&lt;br /&gt;&lt;br /&gt;insert into d values (0,null);&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;br /&gt;--now we have a country without any currencies&lt;br /&gt;&lt;br /&gt;insert into d values (1,null);&lt;br /&gt;&lt;br /&gt;insert into a values (1,1);&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;ORA-12008: error in materialized view refresh path&lt;br /&gt;ORA-01400: cannot insert NULL into ("RAFU"."DA_ATLEAST_ONE_MV"."D_ID")&lt;br /&gt;&lt;br /&gt;insert into d values (2,2);&lt;br /&gt;&lt;br /&gt;insert into a values (2,2);&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;br /&gt;select * from da_atleast_one_mv;&lt;br /&gt;&lt;br /&gt;update d set current_a_id=null where d_id = 2;&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;ORA-12008: error in materialized view refresh path&lt;br /&gt;ORA-01400: cannot insert NULL into ("RAFU"."DA_ATLEAST_ONE_MV"."D_ID")&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-5592083703247559680?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/5592083703247559680/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/01/only-one-yet-again.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5592083703247559680'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5592083703247559680'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/01/only-one-yet-again.html' title='Only one (yet again)'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-7000680645534761524</id><published>2010-01-21T01:06:00.003+02:00</published><updated>2010-01-21T09:27:08.205+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='constraints'/><title type='text'>Potential not nulls</title><content type='html'>Something to send to a development team of the model or just run the clauses from these generators. Here are ways to figure out potential missing not null constraints.&lt;br /&gt;&lt;br /&gt;First a test table&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;create table nnc(n number, m number);&lt;br /&gt;&lt;br /&gt;insert into nnc values (1,2);&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;By counting the actual rows&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;select 'select ''--alter table '||table_name||' modify '||column_name||' not null;'' c from ( select count(*) from '||table_name||' having count(*)&gt;0 and count(*) = sum(case when '||column_name||' is not null then 1 end));' &lt;br /&gt;  from user_tab_columns &lt;br /&gt; where nullable='Y'&lt;br /&gt; order by table_name,column_name&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;select '--alter table NNC modify M not null;' c from ( select count(*) from NNC having count(*)&gt;0 and count(*) = sum(case when M is not null then 1 end));&lt;br /&gt;&lt;br /&gt;select '--alter table NNC modify N not null;' c from ( select count(*) from NNC having count(*)&gt;0 and count(*) = sum(case when N is not null then 1 end));&lt;br /&gt;&lt;br /&gt;--alter table NNC modify M not null;&lt;br /&gt;&lt;br /&gt;--alter table NNC modify N not null;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Or another way by using stats&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;exec dbms_stats.gather_table_stats(user,'NNC');&lt;br /&gt;&lt;br /&gt;select t.table_name, c.column_name, t.num_rows &lt;br /&gt;  from user_tab_cols c &lt;br /&gt; inner join user_tables t &lt;br /&gt;    on t.table_name=c.table_name&lt;br /&gt; where c.nullable='Y'&lt;br /&gt;   and t.temporary='N'&lt;br /&gt;   and num_rows &gt; 0&lt;br /&gt;   and num_nulls = 0&lt;br /&gt; order by t.table_name,c.column_name&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select '--alter table '||t.table_name||' modify '||c.column_name||' not null;'&lt;br /&gt;  from user_tab_cols c &lt;br /&gt; inner join user_tables t &lt;br /&gt;    on t.table_name=c.table_name&lt;br /&gt; where c.nullable='Y'&lt;br /&gt;   and t.temporary='N'&lt;br /&gt;   and num_rows &gt; 0&lt;br /&gt;   and num_nulls = 0&lt;br /&gt; order by t.table_name,c.column_name&lt;br /&gt;;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;And the thirdth option putting those together. Candidates from stats and after that checking the actual data. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;select 'select ''--alter table '||table_name||' modify '||column_name||' not null;'' c from ( select count(*) from '||table_name||' having count(*)&gt;0 and count(*) = sum(case when '||column_name||' is not null then 1 end));' &lt;br /&gt;  from user_tab_columns &lt;br /&gt; where nullable='Y'&lt;br /&gt;   and table_name in (&lt;br /&gt;    select t.table_name&lt;br /&gt;      from user_tab_cols c &lt;br /&gt;     inner join user_tables t &lt;br /&gt;        on t.table_name=c.table_name&lt;br /&gt;     where c.nullable='Y'&lt;br /&gt;       and t.temporary='N'&lt;br /&gt;       and num_rows &gt; 0&lt;br /&gt;       and num_nulls = 0&lt;br /&gt;   )&lt;br /&gt; order by table_name,column_name&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;select '--alter table NNC modify M not null;' c from ( select count(*) from NNC having count(*)&gt;0 and count(*) = sum(case when M is not null then 1 end));&lt;br /&gt;&lt;br /&gt;select '--alter table NNC modify N not null;' c from ( select count(*) from NNC having count(*)&gt;0 and count(*) = sum(case when N is not null then 1 end));&lt;br /&gt;&lt;br /&gt;--alter table NNC modify M not null;&lt;br /&gt;&lt;br /&gt;--alter table NNC modify N not null;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Well maybe the stats version is the one to use. &lt;br /&gt;&lt;br /&gt;I prefer having names also to the not null constraints. So after dealing with the developer&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;alter table NNC modify M constraint nnc_m_nn not null;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-7000680645534761524?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/7000680645534761524/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/01/potential-not-nulls.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7000680645534761524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7000680645534761524'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/01/potential-not-nulls.html' title='Potential not nulls'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-331710672292921652</id><published>2010-01-19T00:21:00.002+02:00</published><updated>2010-01-19T00:25:04.158+02:00</updated><title type='text'>Visualizing plans</title><content type='html'>&lt;a href="http://tech.e2sn.com/apps/planviz"&gt;http://tech.e2sn.com/apps/planviz&lt;/a&gt; seems something that will help me tomorrow.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-331710672292921652?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/331710672292921652/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/01/visualizing-plans.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/331710672292921652'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/331710672292921652'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/01/visualizing-plans.html' title='Visualizing plans'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-8741803494433574096</id><published>2010-01-13T18:02:00.002+02:00</published><updated>2010-01-13T18:16:51.815+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='data integrity'/><title type='text'>Rely constraint validated mess</title><content type='html'>Not so happy with the html support pages. Could not create a SR. Had to go back to flash pages. &lt;br /&gt;&lt;br /&gt;Today's issue is about a constraint that is in validated state. Oracle documentation says that if you use rely constraints, you should know what you are doing. Maybe you did not know and want to go back to norely mode. Here is an example what you should not do.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; create table pa (pa_id number constraint pa_pk primary key);&lt;br /&gt;&lt;br /&gt;Table created.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; insert into pa&lt;br /&gt;  2  select level pa_id from dual connect by level &lt; 3;&lt;br /&gt;&lt;br /&gt;2 rows created.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; create table ch(ch_id number constraint ch_pk primary key&lt;br /&gt;  2                , pa_id not null constraint ch_pa_fk references pa&lt;br /&gt;  3                )&lt;br /&gt;  4  ;&lt;br /&gt;&lt;br /&gt;Table created.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; insert into ch select level ch_id, level pa_id from dual connect by level &lt; 3;&lt;br /&gt;&lt;br /&gt;2 rows created.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; alter table ch modify constraint ch_pa_fk disable novalidate;&lt;br /&gt;&lt;br /&gt;Table altered.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; alter table ch modify constraint ch_pa_fk rely;&lt;br /&gt;&lt;br /&gt;Table altered.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select status,validated,rely from user_constraints where constraint_name = 'CH_PA_FK';&lt;br /&gt;&lt;br /&gt;STATUS   VALIDATED     RELY&lt;br /&gt;-------- ------------- ----&lt;br /&gt;DISABLED NOT VALIDATED RELY&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; insert into ch select level+10 ch_id, level+10 pa_id from dual connect by level &lt; 3;&lt;br /&gt;&lt;br /&gt;2 rows created.&lt;br /&gt;&lt;br /&gt;SQL&gt; select * from pa;&lt;br /&gt;&lt;br /&gt;     PA_ID&lt;br /&gt;----------&lt;br /&gt;         1&lt;br /&gt;         2&lt;br /&gt;&lt;br /&gt;SQL&gt; select * from ch;&lt;br /&gt;&lt;br /&gt;     CH_ID      PA_ID&lt;br /&gt;---------- ----------&lt;br /&gt;         1          1&lt;br /&gt;         2          2&lt;br /&gt;        11         11&lt;br /&gt;        12         12&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; alter table ch modify constraint ch_pa_fk enable;&lt;br /&gt;&lt;br /&gt;Table altered.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; --Why was that possible?&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; alter table ch modify constraint ch_pa_fk validate;&lt;br /&gt;&lt;br /&gt;Table altered.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; --Why was that possible?&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; alter table ch modify constraint ch_pa_fk norely;&lt;br /&gt;&lt;br /&gt;Table altered.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; alter table ch modify constraint ch_pa_fk enable validate;&lt;br /&gt;&lt;br /&gt;Table altered.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select status,validated,rely from user_constraints where constraint_name = 'CH_PA_FK';&lt;br /&gt;&lt;br /&gt;STATUS   VALIDATED     RELY&lt;br /&gt;-------- ------------- ----&lt;br /&gt;ENABLED  VALIDATED&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select *&lt;br /&gt;  2    from ch c&lt;br /&gt;  3    where not exists (select null from pa p where p.pa_id = c.pa_id)&lt;br /&gt;  4  ;&lt;br /&gt;&lt;br /&gt;no rows selected&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; alter table ch modify constraint ch_pa_fk disable novalidate;&lt;br /&gt;&lt;br /&gt;Table altered.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select *&lt;br /&gt;  2    from ch c&lt;br /&gt;  3    where not exists (select null from pa p where p.pa_id = c.pa_id)&lt;br /&gt;  4  ;&lt;br /&gt;&lt;br /&gt;     CH_ID      PA_ID&lt;br /&gt;---------- ----------&lt;br /&gt;        11         11&lt;br /&gt;        12         12&lt;br /&gt;&lt;br /&gt;SQL&gt; alter table ch modify constraint ch_pa_fk enable validate;&lt;br /&gt;alter table ch modify constraint ch_pa_fk enable validate&lt;br /&gt;                                 *&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-02298: cannot validate (SYSTEM.CH_PA_FK) - parent keys not found&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Going back from rely mode to norely. Go first to norely and validate after.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-8741803494433574096?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/8741803494433574096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/01/rely-constraint-validated-mess.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8741803494433574096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8741803494433574096'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/01/rely-constraint-validated-mess.html' title='Rely constraint validated mess'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-7142546499386995490</id><published>2010-01-12T00:09:00.004+02:00</published><updated>2010-01-12T00:24:30.693+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='11.2'/><category scheme='http://www.blogger.com/atom/ns#' term='support'/><title type='text'>New year even happier</title><content type='html'>After migrating to 11.2 flash really has been driving me nuts. Mainly the migration from 11.1 gave us improved performance. But being a SR generator has made me feel not so warm thoughts for flash interface. Not yet faced a problem that we have not been able to overcome. Hopefully &lt;a href="https://supporthtml.oracle.com"&gt;supporthtml.oracle.com&lt;/a&gt; makes my life happier. Thank you &lt;A HREF="http://laurentschneider.com/wordpress/2010/01/happy-new-year-2010.html"&gt;Laurent Schneider&lt;/A&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-7142546499386995490?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/7142546499386995490/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2010/01/new-year-even-happier.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7142546499386995490'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7142546499386995490'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2010/01/new-year-even-happier.html' title='New year even happier'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-7220562799407463506</id><published>2009-12-07T23:46:00.007+02:00</published><updated>2009-12-08T00:47:54.911+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='11.2'/><category scheme='http://www.blogger.com/atom/ns#' term='temp usage'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL tuning'/><title type='text'>SQL Tuning reading plans and temp usage</title><content type='html'>What the heck is using so much temp space? Luckily we have an environment with &lt;br /&gt;&lt;BR&gt; 1. Diagnostic pack purchased&lt;br /&gt;&lt;BR&gt; 2. 11.2.0.1 version - TEMP_SPACE_ALLOCATED in v$active_session_history&lt;br /&gt;&lt;BR&gt; 3. software using dbms_application info - action and module populated&lt;br /&gt;&lt;br /&gt;And following queries will help. First to get overview and the last queries give pointers inside execution of the queries. Now we will have something where to start fixing our temp wasters.&lt;br /&gt;&lt;br /&gt;Trying to figure out stuff from execution plans? Here are some presentations worth reading from &lt;A HREF="http://www.tanelpoder.com/files/Oracle_SQL_Plan_Execution.pdf"&gt;Tanel Poder&lt;/A&gt;, &lt;A HREF="http://antognini.ch/papers/InterpretingExecutionPlans_20091017.pdf"&gt;Christian Antognini&lt;/A&gt; and &lt;A HREF="http://www.perfvision.com/ftp/Nocoug_Nov_2009_sqltuning_nointro.ppt"&gt;Kyle Hailey&lt;/A&gt;.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;select sql_id,action,module&lt;br /&gt;      ,min(sql_exec_start),max(sql_exec_start),max(sample_time)&lt;br /&gt;      ,min(TEMP_SPACE_ALLOCATED) mi&lt;br /&gt;      ,trunc(avg(TEMP_SPACE_ALLOCATED)) av&lt;br /&gt;      ,max(TEMP_SPACE_ALLOCATED) mx &lt;br /&gt;  from v$active_session_history h&lt;br /&gt; group by sql_id,action,module&lt;br /&gt; having max(TEMP_SPACE_ALLOCATED) &gt; 0&lt;br /&gt; order by mx desc;&lt;br /&gt;&lt;br /&gt;select * &lt;br /&gt;  from v$active_session_history h&lt;br /&gt; order by TEMP_SPACE_ALLOCATED desc nulls last;&lt;br /&gt;&lt;br /&gt;select sql_id,action,module&lt;br /&gt;      ,o.object_type,o.object_name,h.sql_plan_operation,h.sql_plan_options&lt;br /&gt;      ,min(sample_time),max(sample_time)&lt;br /&gt;      ,min(TEMP_SPACE_ALLOCATED) mi&lt;br /&gt;      ,trunc(avg(TEMP_SPACE_ALLOCATED)) av&lt;br /&gt;      ,max(TEMP_SPACE_ALLOCATED) mx &lt;br /&gt;  from v$active_session_history h &lt;br /&gt;   left outer join dba_objects o on o.object_id = h.current_obj#&lt;br /&gt; group by sql_id,action,module,o.object_type,o.object_name&lt;br /&gt;         ,SQL_PLAN_OPERATION,SQL_PLAN_OPTIONS&lt;br /&gt; having max(TEMP_SPACE_ALLOCATED) &gt; 0&lt;br /&gt; order by mx desc;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;DBA_HIST_ACTIVE_SESS_HISTORY for searching temp users from a longer period.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;select sql_opname,sql_id,module,action&lt;br /&gt;      ,count(distinct sql_exec_start),max(temp_space_allocated) mx &lt;br /&gt;  from DBA_HIST_ACTIVE_SESS_HISTORY&lt;br /&gt;  where temp_space_allocated &gt; 0&lt;br /&gt;  group by sql_opname,sql_id,module,action&lt;br /&gt;  order by mx desc&lt;br /&gt;;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-7220562799407463506?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/7220562799407463506/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/12/sql-tuning-reading-plans-and-temp-usage.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7220562799407463506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7220562799407463506'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/12/sql-tuning-reading-plans-and-temp-usage.html' title='SQL Tuning reading plans and temp usage'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-2384608489473798378</id><published>2009-12-01T12:27:00.002+02:00</published><updated>2009-12-01T12:32:50.564+02:00</updated><title type='text'>25 hour day</title><content type='html'>&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;alter session set TIME_ZONE = 'Europe/Helsinki';&lt;br /&gt;&lt;br /&gt;select to_timestamp_tz('28032010','ddmmyyyy') &lt;br /&gt;     + interval '&lt;B&gt;3&lt;/B&gt;' hour &lt;br /&gt;     + interval '30' minute as a&lt;br /&gt;from dual;&lt;br /&gt;&lt;br /&gt;28.3.2010 &lt;B&gt;4&lt;/B&gt;:30:00.000000000 +03:00 &lt;br /&gt;&lt;br /&gt;select to_timestamp_tz('31102010','ddmmyyyy')&lt;br /&gt;     + interval '3' hour &lt;br /&gt;     + interval '30' minute as b&lt;br /&gt;from dual;&lt;br /&gt;&lt;br /&gt;31.10.2010 3:30:00.000000000 +03:00 &lt;br /&gt;&lt;br /&gt;select to_timestamp_tz('31102010','ddmmyyyy') &lt;br /&gt;     + interval '&lt;B&gt;4&lt;/B&gt;' hour &lt;br /&gt;     + interval '30' minute as c&lt;br /&gt;from dual;&lt;br /&gt;&lt;br /&gt;31.10.2010 &lt;B&gt;3&lt;/B&gt;:30:00.000000000 +0&lt;B&gt;2&lt;/B&gt;:00 &lt;br /&gt;&lt;br /&gt;select to_timestamp_tz('31102010','ddmmyyyy') &lt;br /&gt;     + interval '&lt;B&gt;24&lt;/B&gt;' hour &lt;br /&gt;     + interval '30' minute as d&lt;br /&gt;from dual;&lt;br /&gt;&lt;br /&gt;31.10.2010 &lt;B&gt;23&lt;/B&gt;:30:00.000000000 +02:00&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-2384608489473798378?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/2384608489473798378/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/12/25-hour-day.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2384608489473798378'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2384608489473798378'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/12/25-hour-day.html' title='25 hour day'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-9097279890540375060</id><published>2009-11-21T00:15:00.002+02:00</published><updated>2009-11-21T00:20:22.481+02:00</updated><title type='text'>Invalid procedure</title><content type='html'>Wonder what is in there. Self invalidating procedure. Executable although invalid.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; drop table i purge;&lt;br /&gt;&lt;br /&gt;Table dropped.&lt;br /&gt;&lt;br /&gt;SQL&gt; create table i(n number);&lt;br /&gt;&lt;br /&gt;Table created.&lt;br /&gt;&lt;br /&gt;SQL&gt; create or replace procedure INVALID_EXECUTABLE wrapped&lt;br /&gt;  2  a000000&lt;br /&gt;  3  b2&lt;br /&gt;  4  abcd&lt;br /&gt;  5  abcd&lt;br /&gt;  6  abcd&lt;br /&gt;  7  abcd&lt;br /&gt;  8  abcd&lt;br /&gt;  9  abcd&lt;br /&gt; 10  abcd&lt;br /&gt; 11  abcd&lt;br /&gt; 12  abcd&lt;br /&gt; 13  abcd&lt;br /&gt; 14  abcd&lt;br /&gt; 15  abcd&lt;br /&gt; 16  abcd&lt;br /&gt; 17  abcd&lt;br /&gt; 18  abcd&lt;br /&gt; 19  7&lt;br /&gt; 20  133 148&lt;br /&gt; 21  /GKO5fy/wMAULSQ3EONeuteOeyYwgzLINa5qfHQCrcHqNAWjUjjq5aQl2wunqxfypGG6DTUC&lt;br /&gt; 22  yHBZPTO1oTh2rTHCnRckEhNR70+2N0Mxn4pbg7fZJwVKX9dFOCicXmazqP6JcBIEQF1QCSdZ&lt;br /&gt; 23  DK5WOcSpQXvAnj5qIawt3H+JSwVpk8gG4oVLFcJ/Du2MO8CJvj7IVzAKn1TGVhx7nATQ1Xoh&lt;br /&gt; 24  FtjOUd1kLeAhNpt+DGEwkLz/U3ZKLO8ZUrzcIIYGLJsBqyicCNA73FdMJNCGw7WlVkNl7Vji&lt;br /&gt; 25  GmA6ougclJqWHoi4fzY81Efcubz7O35pxg==&lt;br /&gt; 26  /&lt;br /&gt;&lt;br /&gt;Procedure created.&lt;br /&gt;&lt;br /&gt;SQL&gt; select * from i;&lt;br /&gt;&lt;br /&gt;no rows selected&lt;br /&gt;&lt;br /&gt;SQL&gt; select status from user_objects where object_name='INVALID_EXECUTABLE';&lt;br /&gt;&lt;br /&gt;STATUS&lt;br /&gt;-------&lt;br /&gt;VALID&lt;br /&gt;&lt;br /&gt;SQL&gt; exec INVALID_EXECUTABLE&lt;br /&gt;&lt;br /&gt;PL/SQL procedure successfully completed.&lt;br /&gt;&lt;br /&gt;SQL&gt; select * from i;&lt;br /&gt;&lt;br /&gt;         N&lt;br /&gt;----------&lt;br /&gt;         1&lt;br /&gt;&lt;br /&gt;SQL&gt; select status from user_objects where object_name='INVALID_EXECUTABLE';&lt;br /&gt;&lt;br /&gt;STATUS&lt;br /&gt;-------&lt;br /&gt;INVALID&lt;br /&gt;&lt;br /&gt;SQL&gt; alter procedure INVALID_EXECUTABLE compile;&lt;br /&gt;&lt;br /&gt;Procedure altered.&lt;br /&gt;&lt;br /&gt;SQL&gt; select status from user_objects where object_name='INVALID_EXECUTABLE';&lt;br /&gt;&lt;br /&gt;STATUS&lt;br /&gt;-------&lt;br /&gt;VALID&lt;br /&gt;&lt;br /&gt;SQL&gt; exec INVALID_EXECUTABLE&lt;br /&gt;&lt;br /&gt;PL/SQL procedure successfully completed.&lt;br /&gt;&lt;br /&gt;SQL&gt; select * from i;&lt;br /&gt;&lt;br /&gt;         N&lt;br /&gt;----------&lt;br /&gt;         2&lt;br /&gt;&lt;br /&gt;SQL&gt; select status from user_objects where object_name='INVALID_EXECUTABLE';&lt;br /&gt;&lt;br /&gt;STATUS&lt;br /&gt;-------&lt;br /&gt;INVALID&lt;br /&gt;&lt;br /&gt;SQL&gt; exec INVALID_EXECUTABLE&lt;br /&gt;&lt;br /&gt;PL/SQL procedure successfully completed.&lt;br /&gt;&lt;br /&gt;SQL&gt; select * from i;&lt;br /&gt;&lt;br /&gt;         N&lt;br /&gt;----------&lt;br /&gt;         3&lt;br /&gt;&lt;br /&gt;SQL&gt; select status from user_objects where object_name='INVALID_EXECUTABLE';&lt;br /&gt;&lt;br /&gt;STATUS&lt;br /&gt;-------&lt;br /&gt;INVALID&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-9097279890540375060?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/9097279890540375060/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/11/invalid-procedure.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/9097279890540375060'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/9097279890540375060'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/11/invalid-procedure.html' title='Invalid procedure'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6655562578968282069</id><published>2009-11-20T10:23:00.003+02:00</published><updated>2009-11-20T10:47:48.216+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pl/sql'/><title type='text'>PLSQL_WARNINGS</title><content type='html'>Struggling with pl/sql code having EXCEPTION WHEN OTHERS THEN NULL; lines. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;alter session set plsql_warnings = 'ENABLE:6009';&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;and compile your code. You get a nice report of your buggy code. There are quite a few other warnings available since 10.1. Here is a sqlplus script to be run on your development/test environment to get a information about your possible problematic code. The &lt;a href="http://www.iki.fi/rafu/rafuondb/compilewarnings.sql"&gt;compilewarnings.sql&lt;/a&gt; script generates a p.txt file containing the output.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; &lt;a href="http://www.iki.fi/rafu/rafuondb/compilewarnings.sql"&gt;compilewarnings.sql&lt;/a&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6655562578968282069?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6655562578968282069/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/11/plsqlwarnings.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6655562578968282069'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6655562578968282069'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/11/plsqlwarnings.html' title='PLSQL_WARNINGS'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-8682674095446861410</id><published>2009-11-08T17:10:00.003+02:00</published><updated>2009-11-08T17:16:47.811+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='data integrity'/><category scheme='http://www.blogger.com/atom/ns#' term='constraints'/><title type='text'>Check constraints and AND</title><content type='html'>&lt;a href="http://rwijk.blogspot.com/2009/09/check-constraints-and-and.html"&gt;Rob van Wijk&lt;/a&gt; has described nicely check constraints in inheritance conversion to a relation using single table implementation. The issue I planned to write about some day. Similar approach also to checks depending on state/status fields.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-8682674095446861410?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/8682674095446861410/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/11/check-constraints-and-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8682674095446861410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8682674095446861410'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/11/check-constraints-and-and.html' title='Check constraints and AND'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-3904425462624014364</id><published>2009-11-03T22:18:00.008+02:00</published><updated>2012-01-25T08:46:45.010+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='foreign key'/><category scheme='http://www.blogger.com/atom/ns#' term='11.2'/><category scheme='http://www.blogger.com/atom/ns#' term='indexing'/><category scheme='http://www.blogger.com/atom/ns#' term='unindex'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><title type='text'>unindex 11.2</title><content type='html'>Tom Kyte has updated his unindex documentation. It is good to review your work every now and then. I guessed he had a valid version of unindex somewhere. Just did not find it at the moment.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://jonathanlewis.wordpress.com/2009/11/03/foreign-keys-2/"&gt;Jonathan Lewis&lt;/a&gt; talking about the foreign key indexing issue in &lt;a href="http://forums.oracle.com/forums/thread.jspa?threadID=981572&amp;amp;tstart=0"&gt;OTN&lt;/a&gt;. It might be that not all foreign keys need an index in your schema.&lt;br /&gt;&lt;br /&gt;11.2 new function listagg is useful also in &lt;a href="http://rafudb.blogspot.com/2009/02/unindex.html"&gt;unindex&lt;/a&gt;. Here is a listagg version of unindex for the new Oracle version.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;select case when i.index_name is not null&lt;br /&gt;            then 'OK'&lt;br /&gt;            else '****'&lt;br /&gt;       end ok&lt;br /&gt;     , c.table_name&lt;br /&gt;     , c.constraint_name&lt;br /&gt;     , c.cols&lt;br /&gt;     , i.index_name&lt;br /&gt;from (&lt;br /&gt;  select a.table_name&lt;br /&gt;       , a.constraint_name&lt;br /&gt;       , listagg(b.column_name, ' ' ) &lt;br /&gt;          within group (order by column_name) cols&lt;br /&gt;      from user_constraints a, user_cons_columns b&lt;br /&gt;     where a.constraint_name = b.constraint_name&lt;br /&gt;       and a.constraint_type = 'R'&lt;br /&gt;  group by a.table_name, a.constraint_name&lt;br /&gt; ) c&lt;br /&gt; left outer join&lt;br /&gt; (&lt;br /&gt;  select table_name&lt;br /&gt;       , index_name&lt;br /&gt;       , cr&lt;br /&gt;       , listagg(column_name, ' ' ) &lt;br /&gt;          within group (order by column_name) cols&lt;br /&gt;    from (&lt;br /&gt;        select table_name&lt;br /&gt;             , index_name&lt;br /&gt;             , column_position&lt;br /&gt;             , column_name&lt;br /&gt;             , connect_by_root(column_name) cr&lt;br /&gt;          from user_ind_columns&lt;br /&gt;       connect by prior column_position-1 = column_position&lt;br /&gt;              and prior index_name = index_name&lt;br /&gt;         )&lt;br /&gt;    group by table_name, index_name, cr&lt;br /&gt;) i on c.cols = i.cols and c.table_name = i.table_name&lt;br /&gt;;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Even thou unindex query is not the kind of query that is run several times a day, I measured execution times from different versions. The test schema contains 1700 foreign keys. Performance comparison &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;"col_cnt &amp;gt; ALL" 13 sec&lt;br /&gt;"connect by"     3 sec &lt;br /&gt;"listagg"        1 sec&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-family: 'Times New Roman'; white-space: normal;"&gt;Foreign keys may point also to and from another schema.&amp;nbsp;&lt;/span&gt;&lt;a href="http://rafudb.blogspot.com/2011/12/unindex-112-cross-schema.html" style="font-family: 'Times New Roman'; white-space: normal;"&gt;Here you can find a version using ALL_CONSTRAINTS and ALL_CONS_COLUMNS views&lt;/a&gt;&lt;span style="font-family: 'Times New Roman'; white-space: normal;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-family: 'Times New Roman'; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-family: 'Times New Roman'; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-3904425462624014364?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/3904425462624014364/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/11/unindex-112.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3904425462624014364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/3904425462624014364'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/11/unindex-112.html' title='unindex 11.2'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-5307360780126276890</id><published>2009-11-02T23:19:00.003+02:00</published><updated>2009-11-02T23:36:37.785+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>TOra</title><content type='html'>Old news, but I just noticed, &lt;a href="http://torasql.com/"&gt;TOra&lt;/a&gt; project is alive. 2.0.0 version have been available for Windows almost a year already. I used the product before Quest purchased it from Underscore AB. Worth trying next to SQL Developer, Toad and/or other tools.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-5307360780126276890?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/5307360780126276890/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/11/tora.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5307360780126276890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5307360780126276890'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/11/tora.html' title='TOra'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-2967904454493735665</id><published>2009-10-29T00:14:00.002+02:00</published><updated>2009-10-29T00:19:07.066+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OUGF'/><title type='text'>OUGF Autumn Seminar</title><content type='html'>Today is the last day to register to &lt;a href="http://www.ougf.fi"&gt;OUGF&lt;/a&gt; Autumn Seminar 2009 at Vanha ylioppilastalo (The old student house), Helsinki 5.11.2009. Also time for me to put together a presentation about hierarchical storing structures and - queries. To be held there in finnish.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-2967904454493735665?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/2967904454493735665/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/10/ougf-autumn-seminar.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2967904454493735665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/2967904454493735665'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/10/ougf-autumn-seminar.html' title='OUGF Autumn Seminar'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-7283588474543002772</id><published>2009-10-28T23:32:00.003+02:00</published><updated>2009-10-28T23:58:34.606+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Coding Dojo'/><category scheme='http://www.blogger.com/atom/ns#' term='Map-Reduce'/><title type='text'>Coding Dojo</title><content type='html'>So, the day came to use &lt;a href="http://rafudb.blogspot.com/2009/10/mapreduce.html"&gt;PL/SQL MapReduce&lt;/a&gt;. Sooner than I thought two days ago. The purpose to use it was not parallel execution but the example itself. Today I participated &lt;a href="http://www.solita.fi"&gt;Solita Oy&lt;/a&gt; free time activity coding dojo. And the simplest task there was to put together &lt;a href="http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1407603857650"&gt;SpellNumbers&lt;/a&gt; and count used letters. I used the brute force method to spell all required numbers. I guess others used more sophisticated approaches. Mine is for sure the only SQL implementation today. Did not get to see other implementations and missed Sauna, because I left early to play with my kids. &lt;br /&gt;&lt;br /&gt;My implementation &lt;a href="http://www.iki.fi/rafu/rafuondb/euler17.sql"&gt;euler17.sql&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-7283588474543002772?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/7283588474543002772/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/10/coding-dojo.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7283588474543002772'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/7283588474543002772'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/10/coding-dojo.html' title='Coding Dojo'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-8923460004885882466</id><published>2009-10-27T08:49:00.004+02:00</published><updated>2009-10-27T08:58:38.425+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='data guard'/><category scheme='http://www.blogger.com/atom/ns#' term='direct path insert'/><category scheme='http://www.blogger.com/atom/ns#' term='append'/><title type='text'>Direct path insert and Data Guard</title><content type='html'>Christian Antognini describes nicely &lt;a href="http://antognini.ch/2009/10/hints-for-direct-path-insert-statements/"&gt;the direct path insert hints&lt;/a&gt; from version 10.2 to 11.2.&lt;br /&gt;&lt;br /&gt;Direct path insert works with Data Guard. No undo is generated for direct path insert and redo is generated. No redo is generated if nologgigin is set on the destination table. With Data Guard force logging should be set. Good explanation about this can be found in several discussions in &lt;a href="http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1951476814728#63965057665565"&gt;asktom&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-8923460004885882466?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/8923460004885882466/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/10/direct-path-insert-and-data-guard.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8923460004885882466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/8923460004885882466'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/10/direct-path-insert-and-data-guard.html' title='Direct path insert and Data Guard'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-1970342445338499455</id><published>2009-10-26T19:38:00.006+02:00</published><updated>2009-10-28T23:59:01.405+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='parallel SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Map-Reduce'/><title type='text'>MapReduce</title><content type='html'>There might come a day to use parallel SQL processing. &lt;a href="http://blogs.oracle.com/datawarehousing/2009/10/in-database_map-reduce.html"&gt;A good description&lt;/a&gt; about Map-Reduce model using Parallel Pipelined Table Functions  and parallel operations.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-1970342445338499455?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/1970342445338499455/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/10/mapreduce.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/1970342445338499455'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/1970342445338499455'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/10/mapreduce.html' title='MapReduce'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6646623004285308038</id><published>2009-10-08T22:53:00.004+03:00</published><updated>2009-10-08T23:34:37.445+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='constraints'/><category scheme='http://www.blogger.com/atom/ns#' term='modeling'/><category scheme='http://www.blogger.com/atom/ns#' term='temporal sql'/><title type='text'>Not overlapping daily</title><content type='html'>&lt;a href="http://www.miracleoy.fi/tanel2009.html"&gt;Attending&lt;/a&gt;. First day gone. Looking forward for tommorow. &lt;a href="http://blog.tanelpoder.com/seminar/"&gt;Tanel&lt;/a&gt; should you call your seminar Basic Oracle Troubleshooting Seminar as you talk about how a certain c program is executing function by function? Recommended attendance to all who troubleshoot Oracle.&lt;br /&gt;&lt;br /&gt;Back to basics. Should it not be basics of a rdbms system to launch a trigger on an event that it is instructed to execute. With Oracle the issue is not so obvious. A certain kind of a compound trigger will not fire when called through jdbc. Metalink -soon to retire- bug no 6785707. &lt;br /&gt;&lt;br /&gt;Another reason for my &lt;a href="http://rafudb.blogspot.com/2009/09/not-overlapping.html"&gt;previous post&lt;/a&gt;. But was i thinking too complex. There is actually no need to track bitwise the used years. The problem is not O 2^n problem, but O n. As n is the number of distinct possible values in the validity interval. How about changing possible values from yearly to daily.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;drop table z cascade constraints purge;&lt;br /&gt;&lt;br /&gt;create table z(z number(16) not null&lt;br /&gt;              , validfrom date not null&lt;br /&gt;              , validtill date not null&lt;br /&gt;              , constraint tilld check (trunc(validfrom)=validfrom)&lt;br /&gt;              , constraint fromd check (trunc(validtill)=validtill)&lt;br /&gt;              , constraint fro2000 &lt;br /&gt;                     check (to_date('20000101','yyyymmdd') &lt; validfrom)&lt;br /&gt;              , constraint til2050 &lt;br /&gt;                     check (validtill &lt;= to_date('20500101','yyyymmdd'))&lt;br /&gt;              , constraint frotil check (validfrom &lt;= validtill)&lt;br /&gt;              );&lt;br /&gt;&lt;br /&gt;begin &lt;br /&gt; for i in (&lt;br /&gt;  select 'create unique index z'||d||' &lt;br /&gt;              on z (case when validfrom &lt;= to_date('''||d||''',''yyyymmdd'') &lt;br /&gt;                          and to_date('''||d||''',''yyyymmdd'') &lt; validtill &lt;br /&gt;                         then z &lt;br /&gt;                         else null &lt;br /&gt;                     end)' createindex&lt;br /&gt;   from&lt;br /&gt;  (select level l&lt;br /&gt;        , to_char(to_date('20000101','yyyymmdd')+level-1,'yyyymmdd') d &lt;br /&gt;     from dual &lt;br /&gt;  connect by level&lt;=to_date('20500101','yyyymmdd')-to_date('20000101','yyyymmdd')&lt;br /&gt;  )&lt;br /&gt;  order by l&lt;br /&gt;  )&lt;br /&gt; loop&lt;br /&gt;  execute immediate i.createindex;&lt;br /&gt; end loop;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;begin&lt;br /&gt;*&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-01792: maximum number of columns in a table or view is 1000&lt;br /&gt;ORA-06512: at line 18&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Not a production ready aproach. Howcome index creation states that no more columns for a table?&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;select count(*) &lt;br /&gt;  from user_indexes &lt;br /&gt; where table_name = 'Z';&lt;br /&gt;&lt;br /&gt;  COUNT(*)&lt;br /&gt;----------&lt;br /&gt;       997&lt;br /&gt;&lt;br /&gt;select count(*) &lt;br /&gt;  from user_tab_columns &lt;br /&gt; where table_name = 'Z';&lt;br /&gt;&lt;br /&gt;  COUNT(*)&lt;br /&gt;----------&lt;br /&gt;         3&lt;br /&gt;&lt;br /&gt;select count(*) &lt;br /&gt;  from user_tab_cols &lt;br /&gt; where table_name = 'Z';&lt;br /&gt;&lt;br /&gt;  COUNT(*)&lt;br /&gt;----------&lt;br /&gt;      1000&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;A function based index is creating a invisible virtual column to table. A table may have at least 1000 columns. &lt;br /&gt;&lt;br /&gt;Well we have 997 first days covered. How a small inserting test is performing with those 997 indexes?&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; insert into z&lt;br /&gt;  2  values(1,to_date('20010101','yyyymmdd'),to_date('20010102','yyyymmdd'));&lt;br /&gt;&lt;br /&gt;1 row created.&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:00.50&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; insert into z&lt;br /&gt;  2  values(1,to_date('20020101','yyyymmdd'),to_date('20020102','yyyymmdd'));&lt;br /&gt;&lt;br /&gt;1 row created.&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:00.40&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; insert into z&lt;br /&gt;  2  values(1,to_date('20020102','yyyymmdd'),to_date('20030101','yyyymmdd'));&lt;br /&gt;&lt;br /&gt;1 row created.&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:00.42&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; insert into z&lt;br /&gt;  2  values(1,to_date('20020201','yyyymmdd'),to_date('20020202','yyyymmdd'));&lt;br /&gt;insert into z&lt;br /&gt;*&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-00001: unique constraint (RAFU.Z20020201) violated&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:01.50&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select * from z;&lt;br /&gt;&lt;br /&gt;         Z VALIDFRO VALIDTIL&lt;br /&gt;---------- -------- --------&lt;br /&gt;         1 20010101 20010102&lt;br /&gt;         1 20020101 20020102&lt;br /&gt;         1 20020102 20030101&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:01.01&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; update z&lt;br /&gt;  2     set validfrom=to_date('20010101','yyyymmdd')&lt;br /&gt;  3   where z=1 and validfrom=to_date('20020101','yyyymmdd');&lt;br /&gt;update z&lt;br /&gt;*&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-00001: unique constraint (RAFU.Z20010101) violated&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:01.15&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6646623004285308038?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6646623004285308038/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/10/not-overlapping-daily.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6646623004285308038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6646623004285308038'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/10/not-overlapping-daily.html' title='Not overlapping daily'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6656447822625895643</id><published>2009-09-28T23:33:00.004+03:00</published><updated>2009-09-29T00:09:48.974+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='constraints'/><category scheme='http://www.blogger.com/atom/ns#' term='modeling'/><category scheme='http://www.blogger.com/atom/ns#' term='temporal sql'/><title type='text'>Not overlapping</title><content type='html'>Lets have a validity period in a table and a rule not to have overlapping periods. The correct solution is to have an another table having the concurrency lock and a combound trigger to handle the overlapping check. Or might there be an alternative way? A way that does not force us to rely that all code modifying the table remember to use the concurrency lock table before modifying the periods. Here it comes. A great abuse of the "bad hack" function based indexes. No need for the concurrency table or triggers. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;drop table z cascade constraints purge;&lt;br /&gt;&lt;br /&gt;create table z(z number(16) not null&lt;br /&gt;             , validfrom number(4) not null&lt;br /&gt;             , validtill number(4) not null&lt;br /&gt;             , constraint fro2000 check (2000 &lt; validfrom)&lt;br /&gt;             , constraint til2050 check (validtill &lt;= 2050)&lt;br /&gt;             , constraint frotil check (validfrom &lt;= validtill)&lt;br /&gt;             );&lt;br /&gt;&lt;br /&gt;create or replace function f(fro number,til number) &lt;br /&gt;return number &lt;br /&gt;deterministic&lt;br /&gt;as&lt;br /&gt;  n number(16);&lt;br /&gt;begin&lt;br /&gt;  n:=0;&lt;br /&gt;  for i in fro..(til-1) loop&lt;br /&gt;    n:= n + power(2,i-2001);&lt;br /&gt;  end loop;&lt;br /&gt;  return n;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;create unique index z1 on z (case when bitand(1,f(validfrom,validtill)) = 1 then z else null end); &lt;br /&gt;&lt;br /&gt;create unique index z2 on z (case when bitand(2,f(validfrom,validtill)) = 2 then z else null end); &lt;br /&gt;&lt;br /&gt;create unique index z3 on z (case when bitand(4,f(validfrom,validtill)) = 4 then z else null end); &lt;br /&gt;&lt;br /&gt;create unique index z4 on z (case when bitand(8,f(validfrom,validtill)) = 8 then z else null end); &lt;br /&gt;&lt;br /&gt;create unique index z5 on z (case when bitand(16,f(validfrom,validtill)) = 16 then z else null end); &lt;br /&gt;&lt;br /&gt;create unique index z6 on z (case when bitand(32,f(validfrom,validtill)) = 32 then z else null end); &lt;br /&gt;&lt;br /&gt;create unique index z7 on z (case when bitand(64,f(validfrom,validtill)) = 64 then z else null end); &lt;br /&gt;&lt;br /&gt;create unique index z8 on z (case when bitand(128,f(validfrom,validtill)) = 128 then z else null end); &lt;br /&gt;&lt;br /&gt;create unique index z9 on z (case when bitand(256,f(validfrom,validtill)) = 256 then z else null end); &lt;br /&gt;&lt;br /&gt;create unique index z10 on z (case when bitand(512,f(validfrom,validtill)) = 512 then z else null end); &lt;br /&gt;&lt;br /&gt;--You maybe got the idea. Left out indexes z11-z46 ... &lt;br /&gt;&lt;br /&gt;create unique index z47 on z (case when bitand(70368744177664,f(validfrom,validtill)) = 70368744177664 then z else null end); &lt;br /&gt;&lt;br /&gt;create unique index z48 on z (case when bitand(140737488355328,f(validfrom,validtill)) = 140737488355328 then z else null end); &lt;br /&gt;&lt;br /&gt;create unique index z49 on z (case when bitand(281474976710656,f(validfrom,validtill)) = 281474976710656 then z else null end); &lt;br /&gt;&lt;br /&gt;SQL&gt; insert into z values(1,2001,2011);&lt;br /&gt;&lt;br /&gt;1 row created.&lt;br /&gt;&lt;br /&gt;SQL&gt; insert into z values(1,2011,2011);&lt;br /&gt;&lt;br /&gt;1 row created.&lt;br /&gt;&lt;br /&gt;SQL&gt; insert into z values(1,2010,2012);&lt;br /&gt;insert into z values(1,2010,2012)&lt;br /&gt;*&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-00001: unique constraint (RAFU.Z10) violated&lt;br /&gt;&lt;br /&gt;SQL&gt; insert into z values(2,2049,2050);&lt;br /&gt;&lt;br /&gt;1 row created.&lt;br /&gt;&lt;br /&gt;SQL&gt; insert into z values(2,2049,2050);&lt;br /&gt;insert into z values(2,2049,2050)&lt;br /&gt;*&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-00001: unique constraint (RAFU.Z49) violated&lt;br /&gt;&lt;br /&gt;SQL&gt; insert into z values(2,2010,2012);&lt;br /&gt;&lt;br /&gt;1 row created.&lt;br /&gt;&lt;br /&gt;SQL&gt; insert into z values(2,2001,2049);&lt;br /&gt;insert into z values(2,2001,2049)&lt;br /&gt;*&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-00001: unique constraint (RAFU.Z10) violated&lt;br /&gt;&lt;br /&gt;SQL&gt; insert into z values(2,2014,2017);&lt;br /&gt;&lt;br /&gt;1 row created.&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6656447822625895643?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6656447822625895643/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/09/not-overlapping.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6656447822625895643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6656447822625895643'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/09/not-overlapping.html' title='Not overlapping'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-5094689821830212624</id><published>2009-09-21T22:18:00.003+03:00</published><updated>2009-09-21T22:38:44.805+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='data integrity'/><category scheme='http://www.blogger.com/atom/ns#' term='constraints'/><category scheme='http://www.blogger.com/atom/ns#' term='denormalization'/><title type='text'>Denormalize safely</title><content type='html'>For some reason there is a need to denormalize values from p table to c table. &lt;br /&gt;How to ensure that denormalized values are the same that original values in p?&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;drop table c cascade constraints purge;&lt;br /&gt;&lt;br /&gt;drop table p cascade constraints purge;&lt;br /&gt;&lt;br /&gt;create table p(p_id number(10) primary key&lt;br /&gt;             , p_name varchar2(200) not null);&lt;br /&gt;&lt;br /&gt;create table c(c_id number(10) primary key&lt;br /&gt;             , p_id constraint c_p_fk references p&lt;br /&gt;             , c_value varchar2(200) not null);&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;The denormalization.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;alter table c add (p_name varchar2(200));&lt;br /&gt;&lt;br /&gt;alter table p add unique (p_name,p_id);&lt;br /&gt;&lt;br /&gt;alter table c add constraint c_p_2fk foreign key(p_name,p_id) references p(p_name,p_id);&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Make the c_p_2fk deferrable if there is a need to update the denormalized values. To satisfy &lt;a href="http://rafudb.blogspot.com/2009/02/unindex.html"&gt;unindex&lt;/a&gt;:&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;create index c_p_2fk_idx on c(p_id,p_name);&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-5094689821830212624?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/5094689821830212624/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/09/denormalize-safely.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5094689821830212624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5094689821830212624'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/09/denormalize-safely.html' title='Denormalize safely'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6354516285197363395</id><published>2009-09-11T00:45:00.004+03:00</published><updated>2009-09-11T12:11:06.227+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='constraints'/><category scheme='http://www.blogger.com/atom/ns#' term='modeling'/><title type='text'>Only one (is_current)</title><content type='html'>Kimball writes in &lt;a href="http://books.google.fi/books?id=2OCbq8Azdm8C&amp;q=%22type%206%22&amp;f=false#v=snippet&amp;q=%22type%206%22&amp;f=false"&gt;The Date Warehouse Toolkit&lt;/a&gt; about slowly changing dimension type 6. Seen such structures with marked current values in a separate attribute. Like in &lt;a href="http://en.wikipedia.org/wiki/Slowly_changing_dimension#Type_6_.2F_Hybrid"&gt;wikipedia&lt;/a&gt;. If the dimension is storing transaction time as durations then the current indicator column might as well be a virtual column in 11g, evaluated to Y if the end day is set to end_date value. No need to update the current indicator column when populating new values for a dimension.&lt;br /&gt;&lt;br /&gt;There should be at most one current indicator = Y row for each supplier. To satisfy this requirement it is possible to create a unique constraint to a virtual column. Actually I would replace the Y value with the supplier_key if the end of days is set in the row. And put the unique key to that column as show &lt;a href="http://rafudb.blogspot.com/2009/08/only-one.html"&gt;earlier&lt;/a&gt;. Adding such a column to an existing model might be problematic because the ETL or mainetenance software might populate new rows before updating the old ones. Should there exist atomic multi table merge? With 11g and virtual columns this is quite easy to overcome by setting the newly created unique constraint deferrable initially deferred.&lt;br /&gt;&lt;br /&gt;But how about 10.2 without virtual columns. Lets dig into the only one, insert first and update then problem with an example without durations.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;drop table di purge;&lt;br /&gt;&lt;br /&gt;drop materialized view di_mv;&lt;br /&gt;&lt;br /&gt;create table di(di_id number(4) primary key&lt;br /&gt;               , sour number(4) not null&lt;br /&gt;               , val number(4) not null&lt;br /&gt;               , is_current number(1) not null);&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Each sour should have only one current. This can be acheaved by creating a bad hack function based index.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;create unique index d_only_one_u on di(case when is_current = 1 then sour end);&lt;br /&gt;&lt;br /&gt;insert into di (di_id,sour,val,is_current) values (1,1,0,0);&lt;br /&gt;&lt;br /&gt;insert into di (di_id,sour,val,is_current) values (2,1,1,1);&lt;br /&gt;&lt;br /&gt;insert into di (di_id,sour,val,is_current) values (3,2,2,1);&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Problematic ETL prosess might want to populate new values first and update the current status at the end of transaction. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;insert into di (di_id,sour,val,is_current) values (4,2,3,1);&lt;br /&gt;insert into di (di_id,sour,val,is_current) values (4,2,3,1)&lt;br /&gt;*&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-00001: unique constraint (RAFU.D_ONLY_ONE_U) violated&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Unique index is checked immediately and now row is allowed to be inserted.&lt;br /&gt;Glue on commit refreshable materialized view to the model. &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;drop index d_only_one_u;&lt;br /&gt;&lt;br /&gt;create materialized view log on di with rowid; &lt;br /&gt;&lt;br /&gt;create materialized view di_mv refresh on commit as&lt;br /&gt;select sour,is_current, rowid drid&lt;br /&gt;  from di&lt;br /&gt; where is_current = 1&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;alter table di_mv&lt;br /&gt;add constraint sour_u unique (sour);&lt;br /&gt;&lt;br /&gt;insert into di (di_id,sour,val,is_current) values (5,2,3,1);&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;commit&lt;br /&gt;*&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-12008: error in materialized view refresh path&lt;br /&gt;ORA-00001: unique constraint (RAFU.SOUR_U) violated&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;And it behaves like an deferrable initially deferred unique constraint. Uniquenes check is done at the end of a transaction.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;insert into di (di_id,sour,val,is_current) values (6,2,3,1);&lt;br /&gt;&lt;br /&gt;update di set is_current = 0 where di_id = 3;&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Ok. The downside is that di_mv is using space. May be worth using, if your data population is beeing coded by humans.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6354516285197363395?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6354516285197363395/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/09/only-one-iscurrent.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6354516285197363395'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6354516285197363395'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/09/only-one-iscurrent.html' title='Only one (is_current)'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-5589477178965976686</id><published>2009-09-01T00:32:00.002+03:00</published><updated>2009-09-01T01:12:32.628+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='constraints'/><category scheme='http://www.blogger.com/atom/ns#' term='modeling'/><title type='text'>Only one (alternative 2)</title><content type='html'>10g friendly approach to store primary currencies. No virtual column used. Structure seems a lot like Tom Kyte &lt;a href="http://www.oracle.com/technology/oramag/oracle/08-sep/o58asktom.html"&gt;suggested&lt;/a&gt;. Difference is that all country currencies are here populated in the same table and the materialized view replaced with a foreign key constraint.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;create table country(country varchar2(2) constraint country_pk primary key&lt;br /&gt;                   , primary_currency varchar(3) not null&lt;br /&gt;                    )&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;create table currency(country references country&lt;br /&gt;                    , currency varchar(3)&lt;br /&gt;                    , constraint currency_pk primary key (currency,country)&lt;br /&gt;                    )&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;alter table country&lt;br /&gt;  add constraint primary_curr_in_country_curr&lt;br /&gt;  foreign key(primary_currency,country)&lt;br /&gt;  references currency(currency,country)&lt;br /&gt;  deferrable initially deferred&lt;br /&gt;;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Populating &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;insert into country (country,primary_currency) values ('US','USS');&lt;br /&gt;&lt;br /&gt;insert into currency (country,currency) values ('US','USD');&lt;br /&gt;&lt;br /&gt;insert into currency (country,currency) values ('US','USN');&lt;br /&gt;&lt;br /&gt;insert into currency (country,currency) values ('US','USS');&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;br /&gt;insert into country (country,primary_currency) values ('FI','EUR');&lt;br /&gt;&lt;br /&gt;insert into currency (country,currency) values ('FI','EUR');&lt;br /&gt;&lt;br /&gt;insert into currency (country,currency) values ('FI','FIM');&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Changing the default. Easier than before. Less code&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;update country set primary_currency='USD' where country='US';&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;br /&gt;select * from country;&lt;br /&gt;country primary_currency&lt;br /&gt;US      USD&lt;br /&gt;FI      EUR&lt;br /&gt;&lt;br /&gt;select * from currency;&lt;br /&gt;country currency&lt;br /&gt;FI      EUR&lt;br /&gt;FI      FIM&lt;br /&gt;US      USD&lt;br /&gt;US      USN&lt;br /&gt;US      USS&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Testing the model:&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;&lt;br /&gt;update country set primary_currency='USD' where country='FI';&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;br /&gt;ORA-02091: transaction rolled back&lt;br /&gt;ORA-02291: integrity constraint (RAFU.PRIMARY_CURR_IN_COUNTRY_CURR) violated -&lt;br /&gt;parent key not found&lt;br /&gt;&lt;br /&gt;insert into country (country, primary_currency) values ('SW','SEK');&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;br /&gt;ORA-02091: transaction rolled back&lt;br /&gt;ORA-02291: integrity constraint (RAFU.PRIMARY_CURR_IN_COUNTRY_CURR) violated -&lt;br /&gt;parent key not found&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;There is only one default currency per country, should be obvious.&lt;br /&gt;&lt;br /&gt;Be sure to run &lt;a href="http://rafudb.blogspot.com/2009/02/unindex.html"&gt;unindex&lt;/a&gt; on your production model.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-5589477178965976686?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/5589477178965976686/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/09/only-one-alternative-2.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5589477178965976686'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/5589477178965976686'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/09/only-one-alternative-2.html' title='Only one (alternative 2)'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6520236549849799831</id><published>2009-08-31T11:04:00.006+03:00</published><updated>2009-08-31T12:46:08.756+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance tuning'/><category scheme='http://www.blogger.com/atom/ns#' term='insert'/><title type='text'>Load using Java</title><content type='html'>&lt;a href="http://carymillsap.blogspot.com/"&gt;Cary Millsap&lt;/a&gt; is writing good things about measuring when tuning performance. His paper &lt;a href="http://method-r.com/downloads/doc_download/10-for-developers-making-friends-with-the-oracle-database-cary-millsap"&gt;Making friends&lt;/a&gt; "Optimizing the insert program" is talking how to insert 10000 rows using Java. There are presented only possibilities to insert using Statement in a loop or using PreparedStatement in a loop. Should there be a alternative way also presented? Avoid looping statements in Java and populate all rows just in single call to the database.&lt;br /&gt;&lt;br /&gt;Timing results inserting 10000 rows:&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;Array&lt;br /&gt;Executed in 0 min 0 s 313 ms.&lt;br /&gt;Prepared&lt;br /&gt;Executed in 0 min 2 s 985 ms.&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;ARRAY:&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;create table si (s number(19),s2 number(19));&lt;br /&gt;create or replace type nums is object ( n1 number(19), n2 number(19));&lt;br /&gt;create type sit is table of nums;&lt;br /&gt;&lt;br /&gt;    private static void insertArray(Connection c, List&lt;Object[]&gt; elems) &lt;br /&gt;            throws SQLException {&lt;br /&gt;        ArrayDescriptor ad = ArrayDescriptor.createDescriptor("SIT", c);&lt;br /&gt;        ARRAY a = new ARRAY(ad, c, elems.toArray());&lt;br /&gt;        OraclePreparedStatement ops &lt;br /&gt;           = (OraclePreparedStatement)c.prepareStatement(&lt;br /&gt;                        "insert into si " +&lt;br /&gt;                        " select *" +&lt;br /&gt;                        "    from table(?)");&lt;br /&gt;        ops.setARRAY(1, a);&lt;br /&gt;&lt;br /&gt;        System.out.println(ops.executeUpdate());&lt;br /&gt;        ops.close();&lt;br /&gt;        c.commit();&lt;br /&gt;    }&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Prepared:&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;    private static void insertPrepared(Connection c, List&lt;Object[]&gt; elems) &lt;br /&gt;            throws SQLException {&lt;br /&gt;        PreparedStatement ps = c.prepareStatement("insert into si values(?,?)");&lt;br /&gt;        Iterator&lt;Object[]&gt; i = elems.iterator();&lt;br /&gt;        while ( i.hasNext()) &lt;br /&gt;        {&lt;br /&gt;            Object[] o = i.next();&lt;br /&gt;            ps.setInt(1, (Integer)o[0]);&lt;br /&gt;            ps.setInt(2, (Integer)o[1]);&lt;br /&gt;            ps.executeUpdate();&lt;br /&gt;        }&lt;br /&gt;        ps.close();&lt;br /&gt;        &lt;br /&gt;        c.commit();&lt;br /&gt;    }&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Here are some timings for other number of rows. It shows that if you are inserting 100-1000 rows this approach might be worth considering. Measure yourself. Be sure to have enough memory available for your Java.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;ms      localhost      remote db &lt;br /&gt;rows    prepared array prepared array&lt;br /&gt;10      94       140   93       141&lt;br /&gt;100     125      141   125      156&lt;br /&gt;1000    313      203   844      265&lt;br /&gt;10000   1500     344   16297    453&lt;br /&gt;100000  12063    1422  206210   2078&lt;br /&gt;1000000 182063   java.lang.OutOfMemoryError: Java heap space  &lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://iki.fi/rafu/rafuondb/insertintoselect.java"&gt;insertintoselect.java&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6520236549849799831?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6520236549849799831/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/08/load-using-java.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6520236549849799831'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6520236549849799831'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/08/load-using-java.html' title='Load using Java'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-6462250900656233222</id><published>2009-08-27T13:08:00.004+03:00</published><updated>2009-08-27T14:15:29.372+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='constraints'/><category scheme='http://www.blogger.com/atom/ns#' term='modeling'/><title type='text'>Only one</title><content type='html'>Last September Tom Kyte wrote a yet another good article in Oracle magazine &lt;a href="http://www.oracle.com/technology/oramag/oracle/08-sep/o58asktom.html"&gt;The Trouble with Triggers&lt;/a&gt;. The point about triggers is very good, but the example and the "Correct Answer" I do not like. He is suggesting to model currencies to two separate tables. In my opinion the data model is entirely wrong if the same thing is modeled in many places. "Less code equals fewer bugs. Look for ways to write less code." Here is my approach to the problem without a materialized view and materialized view logs.&lt;br /&gt;&lt;br /&gt;The problem itself is that &lt;br /&gt;-a country must have a default currency&lt;br /&gt;-there is only one default currency per country&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;create table country(country varchar2(2) constraint country_pk primary key);&lt;br /&gt;&lt;br /&gt;create table currency(country references country&lt;br /&gt;                    , currency varchar(3)&lt;br /&gt;                    , is_primary varchar2(1) not null &lt;br /&gt;                                             check (is_primary in ('Y','N'))&lt;br /&gt;                    , primary_country &lt;br /&gt;                            as (case when is_primary = 'Y' then country end) &lt;br /&gt;                               virtual &lt;br /&gt;                        constraint only_one_primary_u unique &lt;br /&gt;                    , constraint currency_pk primary key (currency,country)&lt;br /&gt;                    )&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;alter table country&lt;br /&gt;  add constraint must_have_at_least_one_primary&lt;br /&gt;  foreign key(country)&lt;br /&gt;  references currency(primary_country)&lt;br /&gt;  deferrable initially deferred;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;And that is it. One may see that there is used the "bad hack" behind only_one_primary_u. The unique constraint generates a function-based normal index.&lt;br /&gt;The good thing about this is that constraints are visible in constraint list, not implemented only in a index or a materialized view.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;select * &lt;br /&gt;  from user_constraints &lt;br /&gt; where constraint_name &lt;br /&gt;    in ('ONLY_ONE_PRIMARY_U','MUST_HAVE_AT_LEAST_ONE_PRIMARY');&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Populating &lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;insert into country (country) values ('US');&lt;br /&gt;&lt;br /&gt;insert into currency (country,currency,is_primary) values ('US','USD','N');&lt;br /&gt;&lt;br /&gt;insert into currency (country,currency,is_primary) values ('US','USN','N');&lt;br /&gt;&lt;br /&gt;insert into currency (country,currency,is_primary) values ('US','USS','Y');&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;br /&gt;insert into country (country) values ('FI');&lt;br /&gt;&lt;br /&gt;insert into currency (country,currency,is_primary) values ('FI','EUR','Y');&lt;br /&gt;&lt;br /&gt;insert into currency (country,currency,is_primary) values ('FI','FIM','N');&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Changing the default&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;update currency set is_primary = 'N' where country = 'US' and currency = 'USS';&lt;br /&gt;&lt;br /&gt;update currency set is_primary = 'Y' where country = 'US' and currency = 'USD';&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;br /&gt;select * from country;&lt;br /&gt;&lt;br /&gt;COUNTRY&lt;br /&gt;US&lt;br /&gt;FI&lt;br /&gt;&lt;br /&gt;select * from currency;&lt;br /&gt;&lt;br /&gt;COUNTRY	CURRENCY	IS_PRIMARY	PRIMARY_COUNTRY&lt;br /&gt;US	USD		Y		US&lt;br /&gt;US	USN		N	&lt;br /&gt;US	USS		N	&lt;br /&gt;FI	EUR		Y		FI&lt;br /&gt;FI	FIM		N	&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A country must have a default currency&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;insert into country (country) values ('NO');&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;br /&gt;ORA-02091: transaction rolled back&lt;br /&gt;ORA-02291: integrity constraint (RAFU.MUST_HAVE_AT_LEAST_ONE_PRIMARY) violated - parent key not found&lt;br /&gt;&lt;br /&gt;insert into country (country) values ('SW');&lt;br /&gt;&lt;br /&gt;insert into currency (country,currency,is_primary) values ('SW','EUR','N');&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;br /&gt;ORA-02091: transaction rolled back&lt;br /&gt;ORA-02291: integrity constraint (RAFU.MUST_HAVE_AT_LEAST_ONE_PRIMARY) violated - parent key not found&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;There is only one default currency per country&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;insert into currency (country,currency,is_primary) values ('FI','USD','Y');&lt;br /&gt;&lt;br /&gt;ORA-00001: unique constraint (RAFU.ONLY_ONE_PRIMARY_U) violated&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-6462250900656233222?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/6462250900656233222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/08/only-one.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6462250900656233222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/6462250900656233222'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/08/only-one.html' title='Only one'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1286598839924995997.post-1315526830506580524</id><published>2009-08-19T15:30:00.003+03:00</published><updated>2009-08-19T15:45:23.819+03:00</updated><title type='text'>Multi table insert atomic?</title><content type='html'>Reading &lt;a href="http://www.amazon.com/SQL-Relational-Theory-Write-Accurate/dp/0596523068"&gt;SQL and Relational Theory: How to Write Accurate SQL Code&lt;/a&gt;. Talking about constraints and data modifications. There should be able to update several tables in one atomic operation. Oracle multi table insert could be something to that direction, but &lt;a href="http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:6915127515933#30394438027431"&gt;no atomicy&lt;/a&gt;. Bug still open from version not any more supported.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;SQL&gt; create table a (a_id number(1) primary key&lt;br /&gt;  2                , b_id number(1) not null);&lt;br /&gt;&lt;br /&gt;Table created.&lt;br /&gt;&lt;br /&gt;SQL&gt; create table b (b_id number(1) primary key&lt;br /&gt;  2                , a_id not null constraint b_a_fk references a );&lt;br /&gt;&lt;br /&gt;Table created.&lt;br /&gt;&lt;br /&gt;SQL&gt; alter table a add&lt;br /&gt;  2    constraint a_b_fk foreign key (b_id) references b&lt;br /&gt;  3      deferrable initially deferred;&lt;br /&gt;&lt;br /&gt;Table altered.&lt;br /&gt;&lt;br /&gt;SQL&gt; insert all into b values (x,x)&lt;br /&gt;  2  into a values (x,x)&lt;br /&gt;  3  select 0 x&lt;br /&gt;  4    from dual;&lt;br /&gt;insert all into b values (x,x)&lt;br /&gt;*&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-02291: integrity constraint (RAFU.B_A_FK) violated - parent key not found&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; insert all into a values (x,x)&lt;br /&gt;  2  into b values (x,x)&lt;br /&gt;  3  select 1 x&lt;br /&gt;  4    from dual;&lt;br /&gt;&lt;br /&gt;2 rows created.&lt;br /&gt;&lt;br /&gt;SQL&gt; insert into a values (2,2);&lt;br /&gt;&lt;br /&gt;1 row created.&lt;br /&gt;&lt;br /&gt;SQL&gt; insert into b values (2,2);&lt;br /&gt;&lt;br /&gt;1 row created.&lt;br /&gt;&lt;br /&gt;SQL&gt; select * from a;&lt;br /&gt;&lt;br /&gt;      A_ID       B_ID&lt;br /&gt;---------- ----------&lt;br /&gt;         1          1&lt;br /&gt;         2          2&lt;br /&gt;&lt;br /&gt;SQL&gt; rollback;&lt;br /&gt;&lt;br /&gt;Rollback complete.&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1286598839924995997-1315526830506580524?l=rafudb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rafudb.blogspot.com/feeds/1315526830506580524/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rafudb.blogspot.com/2009/08/multi-table-insert-atomic.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/1315526830506580524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1286598839924995997/posts/default/1315526830506580524'/><link rel='alternate' type='text/html' href='http://rafudb.blogspot.com/2009/08/multi-table-insert-atomic.html' title='Multi table insert atomic?'/><author><name>Rafu</name><uri>http://www.blogger.com/profile/09149025430133739471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
