<?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-28333051</id><updated>2012-01-23T13:59:58.349-05:00</updated><title type='text'>Wenlai's Tech Notes</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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>21</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-28333051.post-4707439680418889708</id><published>2010-07-22T16:27:00.006-04:00</published><updated>2010-07-22T16:46:55.903-04:00</updated><title type='text'>Interval Partitions in Oracle 11g</title><content type='html'>Among many other enhancements in Oracle 11g, interval partition is definitely a good one for DBAs. There is a good article &lt;a href="http://www.oracle-base.com/articles/11g/PartitioningEnhancements_11gR1.php"&gt;here &lt;/a&gt;discussing it (and other partition enhancements).&lt;br /&gt;&lt;br /&gt;In one of our projects, we are looking for sub-partitions within an interval partition, and it's well able to handle. Here's an extended discussion of the &lt;a href="http://www.oracle-base.com/articles/11g/PartitioningEnhancements_11gR1.php"&gt;link&lt;/a&gt; above.&lt;br /&gt;&lt;br /&gt;This time we have a interval partition, and list subpartitions inside.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;CREATE TABLE interval_tab (&lt;br /&gt;  id           NUMBER,&lt;br /&gt;  code         VARCHAR2(10),&lt;br /&gt;  description  VARCHAR2(50),&lt;br /&gt;  created_date DATE&lt;br /&gt;)&lt;br /&gt;PARTITION BY RANGE (created_date)&lt;br /&gt;INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))&lt;br /&gt;SUBPARTITION BY LIST( code )&lt;br /&gt;SUBPARTITION TEMPLATE&lt;br /&gt;  ( SUBPARTITION CD_01 VALUES ('ONE'),&lt;br /&gt;    SUBPARTITION CD_02 VALUES ('TWO'),&lt;br /&gt;    SUBPARTITION CD_03 VALUES ('THREE')&lt;br /&gt;  )&lt;br /&gt;(&lt;br /&gt;   PARTITION part_01 values LESS THAN (TO_DATE('01-NOV-2007','DD-MON-YYYY'))&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;INSERT INTO interval_tab VALUES (1, 'ONE', 'One', TO_DATE('16-OCT-2007', 'DD-MON-YYYY'));&lt;br /&gt;INSERT INTO interval_tab VALUES (2, 'TWO', 'Two', TO_DATE('31-OCT-2007', 'DD-MON-YYYY'));&lt;br /&gt;COMMIT;&lt;br /&gt;EXEC DBMS_STATS.gather_table_stats(USER, 'INTERVAL_TAB');&lt;br /&gt;&lt;br /&gt;COLUMN partition_name FORMAT A20&lt;br /&gt;COLUMN subpartition_name FORMAT A20&lt;br /&gt;COLUMN high_value FORMAT A10&lt;br /&gt;&lt;br /&gt;SELECT partition_name, subpartition_name, high_value, num_rows&lt;br /&gt;FROM   user_tab_subpartitions&lt;br /&gt;where table_name = 'INTERVAL_TAB'&lt;br /&gt;ORDER BY table_name, partition_name, subpartition_name;&lt;br /&gt;&lt;br /&gt;PARTITION_NAME       SUBPARTITION_NAME    HIGH_VALUE   NUM_ROWS&lt;br /&gt;-------------------- -------------------- ---------- ----------&lt;br /&gt;PART_01              PART_01_CD_01        'ONE'               1&lt;br /&gt;PART_01              PART_01_CD_02        'TWO'               1&lt;br /&gt;PART_01              PART_01_CD_03        'THREE'             0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;By adding more data that expands the partitions, you'll see the subpartitions are generated as well.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;INSERT INTO interval_tab VALUES (3, 'THREE', 'Three', TO_DATE('01-NOV-2007', 'DD-MON-YYYY'));&lt;br /&gt;INSERT INTO interval_tab VALUES (4, 'TWO', 'TWO', TO_DATE('30-NOV-2007', 'DD-MON-YYYY'));&lt;br /&gt;COMMIT;&lt;br /&gt;EXEC DBMS_STATS.gather_table_stats(USER, 'INTERVAL_TAB');&lt;br /&gt;&lt;br /&gt;SELECT partition_name, subpartition_name, high_value, num_rows&lt;br /&gt;FROM   user_tab_subpartitions&lt;br /&gt;where table_name = 'INTERVAL_TAB'&lt;br /&gt;ORDER BY table_name, partition_name, subpartition_name;&lt;br /&gt;&lt;br /&gt;PARTITION_NAME       SUBPARTITION_NAME    HIGH_VALUE   NUM_ROWS&lt;br /&gt;-------------------- -------------------- ---------- ----------&lt;br /&gt;PART_01              PART_01_CD_01        'ONE'               1&lt;br /&gt;PART_01              PART_01_CD_02        'TWO'               1&lt;br /&gt;PART_01              PART_01_CD_03        'THREE'             0&lt;br /&gt;SYS_P40              SYS_SUBP37           'ONE'               0&lt;br /&gt;SYS_P40              SYS_SUBP38           'TWO'               1&lt;br /&gt;SYS_P40              SYS_SUBP39           'THREE'             1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Subpartition names are automatically with system name, which is not I'm expecting: it's better to named as partition + subpartition_template, ie, SYS_P40_CD_01.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-4707439680418889708?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/4707439680418889708/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=4707439680418889708' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/4707439680418889708'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/4707439680418889708'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2010/07/interval-partitions-in-oracle-11g.html' title='Interval Partitions in Oracle 11g'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-4066815349137591594</id><published>2009-04-10T16:56:00.004-04:00</published><updated>2010-03-26T16:15:55.241-04:00</updated><title type='text'>Encrypt in WebLogic</title><content type='html'>A colleague gave me a piece of code to plug into my WebLogic 10 JDBC configure file:&lt;br /&gt;&lt;blockquote&gt;&amp;lt;jdbc-data-source ...&lt;br /&gt;...&lt;br /&gt;&amp;lt;password-encrypted&amp;gt;{3DES}xxxxxxxxxxxxxxx&amp;lt;/password-encrypted&amp;gt;&lt;br /&gt;...&lt;br /&gt;&amp;lt;/jdbc-data-source&amp;gt;&lt;/blockquote&gt;&lt;br /&gt;When I copied over, and tried to start WebLogic, got an exception:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;weblogic.management.ManagementRuntimeException: com.rsa.jsafe.JSAFE_PaddingException: Could not perform unpadding: invalid pad byte.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It's really not telling what you'll have to do. After some research, I figured out I need to re-encrypt the password. Here's the utility to use:&lt;br /&gt;&lt;br /&gt;java -cp &amp;lt;weblogic_home&amp;gt;\server\lib\weblogic.jar -Dweblogic.RootDirectory=&amp;lt;your_domain_dir&amp;gt; weblogic.security.Encrypt &amp;lt;password&amp;gt;&lt;br /&gt;&lt;br /&gt;Pasted the result to replace old password, it worked fine.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/your&gt;&lt;/password&gt;&lt;/your_domain_dir&gt;&lt;/your&gt;&lt;/weblogic_dir&gt;&lt;/weblogic_home&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-4066815349137591594?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/4066815349137591594/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=4066815349137591594' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/4066815349137591594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/4066815349137591594'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2009/04/encrypt-in-weblogic.html' title='Encrypt in WebLogic'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-6173532475465396243</id><published>2008-05-01T14:32:00.003-04:00</published><updated>2008-05-01T14:58:12.353-04:00</updated><title type='text'>Slow When Bulk Inserting Records to Database Using Lotus Notes Agent</title><content type='html'>I don't do Lotus Notes program. But our Notes developers told me that it was extremely slow to insert records into Oracle (SQL Server as well) database. One example is that 1 million rows took 8 hours.&lt;br /&gt;&lt;br /&gt;After some investigation, I found that they were constructing full SQLs, instead of using parameters. Below is a piece of their code:&lt;br /&gt;&lt;pre&gt;    Dim con As ODBCConnection&lt;br /&gt;   Dim qry As ODBCQuery&lt;br /&gt;   Dim result As ODBCResultSet&lt;br /&gt;&lt;br /&gt;   Set qry = New ODBCQuery&lt;br /&gt;   Set result = New ODBCResultSet&lt;br /&gt;   con.ConnectTo("&lt;odbc_name&gt;")&lt;br /&gt;   Set qry.Connection = con&lt;br /&gt;&lt;br /&gt;   for each document loop&lt;br /&gt;       &lt;span style="color: rgb(255, 0, 0);"&gt;qry.SQL = "insert into person (fname,lname) values( '" &amp;amp; v_fname &amp;amp; &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;                  "','" &amp;amp; v_lname &amp;amp; "' )"&lt;/span&gt;&lt;br /&gt;       &lt;span style="color: rgb(255, 0, 0);"&gt;Set result.Query = qry&lt;/span&gt;&lt;br /&gt;   end loop&lt;br /&gt;   ...&lt;br /&gt;&lt;/odbc_name&gt;&lt;/pre&gt;The high-lite is the trouble. Whenever this was called, I noticed so many queries on Oracle data dictionary views. It seems to me that Notes was parsing the SQL, and the second statement sometimes took about 2 seconds.&lt;br /&gt;&lt;br /&gt;To solve it, I did some research and found the parameters was useful.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    qry.SQL = "insert into person (fname,lname) values( ?fname?, ?lname? )"&lt;br /&gt;    Set result.Query = qry&lt;br /&gt;    for each document loop&lt;br /&gt;        Call result.SetParameter( fname, "'" &amp; v_fname &amp; "'" )&lt;br /&gt;        Call result.SetParameter( lname, "'" &amp; v_lname &amp; "'" )&lt;br /&gt;    end loop&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The performance improved greatly, one example is 30K records reduced time from 4 hours to 10 minutes. Still high, but Notes spends most of the time preparing data.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-6173532475465396243?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/6173532475465396243/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=6173532475465396243' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/6173532475465396243'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/6173532475465396243'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2008/05/slow-when-bulk-inserting-records-to.html' title='Slow When Bulk Inserting Records to Database Using Lotus Notes Agent'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-6362305168289978866</id><published>2008-03-14T14:39:00.005-04:00</published><updated>2008-03-14T14:50:43.193-04:00</updated><title type='text'>Accessing Non-exsits Item in Oracle Associative Array</title><content type='html'>Look at this piece of code:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; set serveroutput on&lt;br /&gt; declare&lt;br /&gt;  type MONTH_TYPE is table of varchar(20) index by binary_integer;&lt;br /&gt;&lt;br /&gt;  month_table   MONTH_TYPE;&lt;br /&gt;begin&lt;br /&gt;  month_table(1) := 'Jan';&lt;br /&gt;  month_table(2) := 'Feb';&lt;br /&gt;&lt;br /&gt;  if month_table(3) is null then&lt;br /&gt;    dbms_output.put_line( 'March is not defined.' );&lt;br /&gt;  end if;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;/pre&gt;What you'll get? You may think the print line.&lt;br /&gt;&lt;br /&gt;However, you'll get an error:&lt;br /&gt;&lt;pre&gt;    ERROR at line 1:&lt;br /&gt;ORA-01403: no data found&lt;br /&gt;ORA-06512: at line 9&lt;br /&gt;&lt;/pre&gt;Well, associative array is working the same way as table (is that why it's defined as &lt;span style="font-weight: bold;"&gt;TABLE&lt;/span&gt; of ...), and month_table is similar to select value from month_table &lt;span style="font-weight: bold;"&gt;into &lt;/span&gt;v..., so need to have an exception handling.&lt;br /&gt;&lt;pre&gt;    set serveroutput on&lt;br /&gt; declare&lt;br /&gt;   type MONTH_TYPE is table of varchar(20) index by binary_integer;&lt;br /&gt;&lt;br /&gt;   month_table   MONTH_TYPE;&lt;br /&gt; begin&lt;br /&gt;   month_table(1) := 'Jan';&lt;br /&gt;   month_table(2) := 'Feb';&lt;br /&gt;&lt;br /&gt;   if month_table(3) is null then&lt;br /&gt;     dbms_output.put_line( 'March is not defined.' );&lt;br /&gt;   end if;&lt;br /&gt; exception&lt;br /&gt;   when NO_DATA_FOUND then&lt;br /&gt;     dbms_output.put_line( 'March is not found.' );&lt;br /&gt; end;&lt;br /&gt; /&lt;br /&gt;&lt;/pre&gt;Then, you'll get: March is not found.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-6362305168289978866?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/6362305168289978866/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=6362305168289978866' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/6362305168289978866'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/6362305168289978866'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2008/03/accessing-non-exsits-item-in-oracle.html' title='Accessing Non-exsits Item in Oracle Associative Array'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-1924952256182918503</id><published>2008-01-03T14:49:00.000-05:00</published><updated>2008-01-03T15:01:53.211-05:00</updated><title type='text'>Track Long Operations in Oracle</title><content type='html'>You may need to run a process on 1 million rows and the whole process takes a few hours to finish. In Oracle, there is a way that you can track the process.&lt;br /&gt;&lt;br /&gt;Here's a piece of example code in PL/SQL, it takes advantage of package DBMS_APPLICATION_INFO.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; declare&lt;br /&gt;   -- main variables&lt;br /&gt;   ...&lt;br /&gt;&lt;br /&gt;   -- long op info&lt;br /&gt;   v_rindex     PLS_INTEGER;&lt;br /&gt;   v_slno       PLS_INTEGER;&lt;br /&gt;   v_totalwork  NUMBER;&lt;br /&gt;   v_sofar      NUMBER;&lt;br /&gt;   v_obj        PLS_INTEGER;&lt;br /&gt;&lt;br /&gt;   v_op_name    varchar(100) := 'My work';&lt;br /&gt;   v_units      varchar(100) := 'rows processed';&lt;br /&gt; begin&lt;br /&gt;   -- Calculate total work (number of rows to be processed, etc.)&lt;br /&gt;   select count(*) into v_totalwork from ...;&lt;br /&gt;&lt;br /&gt;   v_sofar := 0;&lt;br /&gt;   v_rindex     := DBMS_APPLICATION_INFO.set_session_longops_nohint;&lt;br /&gt;&lt;br /&gt;   for ... -- A loop to process your work&lt;br /&gt;   loop&lt;br /&gt;     ...  -- do your work here.&lt;br /&gt;&lt;br /&gt;     -- log longops view.&lt;br /&gt;     v_sofar := v_sofar + 1;&lt;br /&gt;     if mod( v_sofar, 500 ) = 0 then   -- log your operation every 500 rounds&lt;br /&gt;        DBMS_APPLICATION_INFO.set_session_longops(rindex   =&gt; v_rindex,&lt;br /&gt;                                               slno        =&gt; v_slno,&lt;br /&gt;                                               op_name     =&gt; v_op_name,&lt;br /&gt;                                               target      =&gt; v_obj,&lt;br /&gt;                                               context     =&gt; 0,&lt;br /&gt;                                               sofar       =&gt; v_sofar,&lt;br /&gt;                                               totalwork   =&gt; v_totalwork,&lt;br /&gt;                                               target_desc =&gt; 'Some description here',&lt;br /&gt;                                               units       =&gt; v_units);&lt;br /&gt;     end if;&lt;br /&gt;&lt;br /&gt;   end loop;&lt;br /&gt;&lt;br /&gt;   -- mark the end&lt;br /&gt;   DBMS_APPLICATION_INFO.set_session_longops(rindex   =&gt; v_rindex,&lt;br /&gt;                                          slno        =&gt; v_slno,&lt;br /&gt;                                          op_name     =&gt; v_op_name,&lt;br /&gt;                                          target      =&gt; v_obj,&lt;br /&gt;                                          context     =&gt; 0,&lt;br /&gt;                                          sofar       =&gt; v_sofar,&lt;br /&gt;                                          totalwork   =&gt; v_totalwork,&lt;br /&gt;                                          target_desc =&gt; 'Some description here',&lt;br /&gt;                                          units       =&gt; v_units);&lt;br /&gt;&lt;br /&gt; end;&lt;br /&gt; /&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To view the status of the process, run query:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; select sid, serial#, opname, sofar, totalwork, start_time, last_update_time&lt;br /&gt; from v$session_longops where opname = 'My Work';&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Columns sofar and totalwork show you how much work has been done so far.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-1924952256182918503?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/1924952256182918503/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=1924952256182918503' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/1924952256182918503'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/1924952256182918503'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2008/01/tracke-long-operations-in-oracle.html' title='Track Long Operations in Oracle'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-7384635938269225363</id><published>2007-11-14T15:54:00.000-05:00</published><updated>2007-11-14T16:52:11.309-05:00</updated><title type='text'>Another Way to Reorgnize Table in Oracle</title><content type='html'>After inserting/deleting from a table for a long time, the table may contain much spared space that hurts the full table scan greatly. Instead of export and import, or recreate it. Move it from one tablespace to another is another way.&lt;br /&gt;&lt;br /&gt;Here's a case I did recently. I noticed a table is slow when running full table scan, however it contains only 30K rows, and each row is not that big.&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;select segment_name, sum(bytes)/1024/1024 MB_Bytes, sum(blocks) blocks, sum(extents) extents&lt;br /&gt;from user_segments&lt;br /&gt;where segment_name = 'BAD_TABLE'&lt;br /&gt;group by segment_name;&lt;br /&gt;&lt;br /&gt;SEGMENT_NAME        MB_BYTES   BLOCKS     EXTENTS&lt;br /&gt;------------------- ---------- ---------- ----------&lt;br /&gt;BAD_TABLE           220        28160      99&lt;br /&gt;&lt;br /&gt;&lt;/PRE&gt;OK, move it to another tablespace:&lt;br /&gt;&lt;PRE&gt;alter table BAD_TABLE move tablespace tb_another;&lt;/PRE&gt;Run that check again:&lt;br /&gt;&lt;PRE&gt;select segment_name, sum(bytes)/1024/1024 MB_Bytes, sum(blocks) blocks, sum(extents) extents&lt;br /&gt;from user_segments&lt;br /&gt;where segment_name = 'BAD_TABLE'&lt;br /&gt;group by segment_name;&lt;br /&gt;&lt;br /&gt;SEGMENT_NAME           MB_BYTES   BLOCKS     EXTENTS&lt;br /&gt;---------------------- ---------- ---------- ----------&lt;br /&gt;BAD_TABLE              32         4096       47&lt;br /&gt;&lt;/PRE&gt;It's much smaller. Well, you may want to move it back to its original tablespace.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-7384635938269225363?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/7384635938269225363/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=7384635938269225363' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/7384635938269225363'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/7384635938269225363'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2007/11/another-way-to-reorgnize-table.html' title='Another Way to Reorgnize Table in Oracle'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-5323740356461282002</id><published>2007-07-20T13:46:00.000-04:00</published><updated>2007-07-20T13:58:54.656-04:00</updated><title type='text'>Oracle Database Console Credential Failures on Windows</title><content type='html'>There is an error message in Oracle Database console:&lt;br /&gt;&lt;br /&gt;Connection to host as user USER failed: ERROR: Wrong password for user&lt;br /&gt;&lt;br /&gt;Usually you find this error when trying to connect to host, for example, you want to start/shutdown, or backup the database. It had confused me for a long time. Then I found an solution.&lt;br /&gt;&lt;br /&gt;1. &lt;span class="MsgBodyText"&gt;Provide the 'Log on as a batch job' &lt;/span&gt;&lt;span class="MsgBodyText"&gt;privilege.&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="MsgBodyText"&gt;  Go to control panel/administrative tools&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="MsgBodyText"&gt;  click on "local security policy"&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="MsgBodyText"&gt;  click on "local policies"&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="MsgBodyText"&gt;  click on "user rights assignments"&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="MsgBodyText"&gt;  double click on "log on as a batch job"&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="MsgBodyText"&gt;  click on "add" and add the user(s) that you're going to use in database console.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;2. Set credentials and test&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="MsgBodyText"&gt;  Go to the Preferences link in the database console page&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="MsgBodyText"&gt;  click on Preferred Credentials (link on the left menu)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="MsgBodyText"&gt;  under "Target Type: Host" click on "set credentials"&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="MsgBodyText"&gt;  enter the OS user(s) for whom you have set "logon as a batch job" privilege&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="MsgBodyText"&gt;   click on "Test"&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;Then you should see the backup is working.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-5323740356461282002?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/5323740356461282002/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=5323740356461282002' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/5323740356461282002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/5323740356461282002'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2007/07/oracle-database-console-credential.html' title='Oracle Database Console Credential Failures on Windows'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28333051.post-946310322796078885</id><published>2007-02-16T11:36:00.000-05:00</published><updated>2007-02-16T11:47:13.447-05:00</updated><title type='text'>Get Month End in SQL Server</title><content type='html'>SQL Server doesn't have a function to get the month end. Here shows one I wrote:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; ALTER  function dbo.sp_getmonthend ( @inputDate    DATETIME )&lt;br /&gt; /*&lt;br /&gt;   This function returns the month end of a specific date.&lt;br /&gt; */&lt;br /&gt; RETURNS DATETIME&lt;br /&gt; BEGIN&lt;br /&gt;     DECLARE @outputDate        DATETIME&lt;br /&gt;&lt;br /&gt;     select @outputDate = CAST(YEAR(@inputDate) AS VARCHAR(4)) + '-' +&lt;br /&gt;                        CAST(MONTH(@inputDate) AS VARCHAR(2)) + '-01'&lt;br /&gt;     select @outputDate = dateadd( day, -1, dateadd( month, 1, @outputDate ) )&lt;br /&gt;     return @outputDate&lt;br /&gt; END&lt;/pre&gt;Since there is 1st in every month, we forward 1 month from 1st of the month and backward a day.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-946310322796078885?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/946310322796078885/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=946310322796078885' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/946310322796078885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/946310322796078885'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2007/02/get-month-end-in-sql-server.html' title='Get Month End in SQL Server'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-5920421526934547023</id><published>2007-02-13T14:07:00.000-05:00</published><updated>2006-12-13T12:01:46.621-05:00</updated><title type='text'>Undrop table in Oracle</title><content type='html'>I don't "undrop" table a lot. So once when I tried to "undrop" a table, I got an error:&lt;br /&gt;&lt;br /&gt;  sql&gt; undrop table test1;&lt;br /&gt;  SP2-0734:unknown command beginning "undrop tab..." - rest of line ignored.&lt;br /&gt;&lt;br /&gt;Well, I soon found, it's not "undrop", instead:&lt;br /&gt;&lt;br /&gt;  SQL&gt; flashback table test1 to before drop rename to test2;&lt;br /&gt;  Flashback complete.&lt;br /&gt;&lt;br /&gt;You can rename it if the previous name has been used by others.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-5920421526934547023?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/5920421526934547023/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=5920421526934547023' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/5920421526934547023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/5920421526934547023'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2007/02/undrop-table-in-oracle.html' title='Undrop table in Oracle'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-8122995049956074252</id><published>2006-12-13T11:50:00.000-05:00</published><updated>2006-12-13T12:01:46.290-05:00</updated><title type='text'>Row Locks When Inserting - Oracle</title><content type='html'>My co-worker told me his application hanging while inserting a row into a table. By looking at the Oracle Enterprise Manager, I noticed it's caused by foreign key. Here I show an example.&lt;br /&gt;&lt;br /&gt;Open a SQL Plus, create the tables and foreign key.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    create table tmp_test &lt;br /&gt;    ( id         number(5) not null, &lt;br /&gt;      test_type  char(1), &lt;br /&gt;      comments varchar2(100),&lt;br /&gt;      constraint pk_tmp_test primary key (id) &lt;br /&gt;    );&lt;br /&gt;&lt;br /&gt;    create table tmp_test_type &lt;br /&gt;    ( test_type char(1), &lt;br /&gt;      description  varchar2(100),&lt;br /&gt;      constraint pk_tmp_test_type primary key (test_type) );&lt;br /&gt;&lt;br /&gt;    alter table tmp_test add constraint fk1_tmp_test foreign key ( test_type )&lt;br /&gt;      references tmp_test_type;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now try to insert a row without referring type. Expecting an error:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    insert into tmp_test values( 1, 'A', 'Just a test' );&lt;br /&gt;&lt;br /&gt;    ORA-02291: integrity constraint (EAS_DEMO.FK1_TMP_TEST) violated - parent key not found&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Open another session using SQL Plus, insert a row in test_test_type table but don't commit:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    insert into tmp_test_type values( 'A', 'Test type A' );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Run the insert again using the first SQL Plus, you'll find it hangs. In Oracle Enterprise Manager, you can see "enq: TX - row lock contention".&lt;br /&gt;&lt;br /&gt;Commit the changes and cleanup:&lt;pre&gt;&lt;br /&gt;    drop table tmp_test;&lt;br /&gt;    drop table tmp_test_type;&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/28333051-8122995049956074252?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/8122995049956074252/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=8122995049956074252' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/8122995049956074252'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/8122995049956074252'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2006/12/row-locks-when-inserting-oracle.html' title='Row Locks When Inserting - Oracle'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-116122088863937043</id><published>2006-10-18T21:20:00.002-04:00</published><updated>2010-10-07T11:48:47.838-04:00</updated><title type='text'>Delete Duplicate Rows</title><content type='html'>It's easy to delete duplicate rows in Oracle using cursor and rownum. Here shows an example.&lt;br /&gt;&lt;br /&gt;Create table and insert some duplicate rows.&lt;br /&gt;&lt;blockquote  style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;CREATE TABLE DUP_TEST&lt;br /&gt;(&lt;br /&gt;COMPANY_ID VARCHAR(8),&lt;br /&gt;COMPANY_NAME VARCHAR(80),&lt;br /&gt;ADDRESS VARCHAR(80)&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;-- Create test data, dup by company id&lt;br /&gt;INSERT INTO DUP_TEST VALUES ('1', 'Company One', 'Address1');&lt;br /&gt;INSERT INTO DUP_TEST VALUES ('1', 'Company One', 'Address1');&lt;br /&gt;INSERT INTO DUP_TEST VALUES ('2', 'Company Two', 'Address2');&lt;br /&gt;INSERT INTO DUP_TEST VALUES ('2', 'Company Two', 'Address');&lt;br /&gt;INSERT INTO DUP_TEST VALUES ('3', 'Company Three', 'Address3');&lt;/span&gt;&lt;/blockquote&gt;&lt;br /&gt;The duplicates are with company id 1 and 2. Let delete the duplicates.&lt;br /&gt;&lt;pre&gt;&lt;p&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;set serveroutput on&lt;br /&gt;declare&lt;br /&gt;  rows_deleted integer := 0;&lt;br /&gt;begin&lt;br /&gt;  for cur in ( select company_id, count(*) cnt from DUP_TEST&lt;br /&gt;               group by company_id having count(*) &gt; 1 )&lt;br /&gt;  loop&lt;br /&gt;    delete from DUP_TEST&lt;br /&gt;    where company_id = cur.company_id and rownum &lt; cur.cnt;&lt;br /&gt;    rows_deleted := rows_deleted + SQL%ROWCOUNT;&lt;br /&gt;  end loop;&lt;br /&gt;  dbms_output.put_line( 'records deleted: '  rows_deleted );&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;/p&gt;&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;&lt;/span&gt;&lt;/p&gt;Now show the result after deleting.&lt;br /&gt;&lt;pre&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;SQL&gt; select * from dup_test;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;COMPANY_ COMPANY_NAME ADDRESS&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;-------- -------------------- --------------------&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;1 Company One Address1&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;2 Company Two Address&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;3 Company Three Address3&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;It's a little bit diffcult to delete duplicate rows in SQL Server. I'll show one solution using a cursor. Consider the performance when you have large amount of data to search or delete.&lt;br /&gt;&lt;blockquote  style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;declare cur cursor for select COMPANY_ID from DUP_TEST&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;declare @CompanyId int&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;open cur&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;fetch cur into @CompanyId&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;while @@fetch_status = 0&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;begin&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;if ( select count(*) from DUP_TEST where COMPANY_ID = @CompanyId ) &gt; 1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;begin&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;delete from DUP_TEST where current of cur&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;fetch cur into @CompanyId&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;close cur&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;deallocate cur&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;go&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;It goes through the full table and search duplicates for each row, if found, delete the current of cursor.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-116122088863937043?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/116122088863937043/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=116122088863937043' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/116122088863937043'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/116122088863937043'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2006/10/delete-duplicate-rows.html' title='Delete Duplicate Rows'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-116103015111905828</id><published>2006-10-16T16:21:00.000-04:00</published><updated>2006-10-26T14:58:21.376-04:00</updated><title type='text'>Ref: moving from Sybase to SQL</title><content type='html'>This is a good &lt;a href="http://www.sql-server-performance.com/sg_from_sybase_to_sql_server.asp"&gt;article&lt;/a&gt; discussing the difference between Sybase and SQL Server.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-116103015111905828?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.sql-server-performance.com/sg_from_sybase_to_sql_server.asp' title='Ref: moving from Sybase to SQL'/><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/116103015111905828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=116103015111905828' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/116103015111905828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/116103015111905828'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2006/10/ref-moving-from-sybase-to-sql.html' title='Ref: moving from Sybase to SQL'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-116008031776919310</id><published>2006-10-05T16:12:00.000-04:00</published><updated>2006-10-26T14:58:21.306-04:00</updated><title type='text'>SQL Server - Append Query Result to .csv file</title><content type='html'>While searching on the web, I found a lot talking about appending SQL Server data to Excel files. But not many about appending data to .csv file. After some research, I got one.&lt;br /&gt;&lt;br /&gt;First, create the csv file and prepare the column header:&lt;br /&gt;&lt;blockquote&gt;  master..xp_cmdshell 'echo EmpID,LastName,FirstName &gt; C:\temp\Employees.csv'&lt;/blockquote&gt;It creates a file c:\temp\Employees.csv with 3 columns.&lt;br /&gt;&lt;br /&gt;Then, append the data using OPENROWSET:&lt;br /&gt;&lt;blockquote&gt;INSERT INTO OPENROWSET('Microsoft.Jet.OleDB.4.0',&lt;br /&gt;   'Text;Database=C:\temp',&lt;br /&gt;   [Employees#csv])&lt;br /&gt;select EmployeeID, LastName, FirstName from NOrthwind..Employees&lt;br /&gt;(9 row(s) affected)&lt;br /&gt;&lt;/blockquote&gt;Open the file c:\temp\Employees.csv, you'll see there are 9 rows appended.&lt;br /&gt;Some points here are: 1) Database=C:\temp (need to put the folder here only), and 2) [Employees#csv] (need to replace . with # as the table name.&lt;br /&gt;&lt;br /&gt;OK, it's similar to read the file back:&lt;br /&gt;&lt;blockquote&gt;select * from OPENROWSET('Microsoft.Jet.OleDB.4.0',&lt;br /&gt; 'Text;Database=C:\temp', [Employees#csv])&lt;br /&gt;&lt;br /&gt;1    Davolio    Nancy&lt;br /&gt;...&lt;br /&gt;9    Dodsworth    Anne&lt;br /&gt;&lt;/blockquote&gt;At the end, I'll show another way to read the data in csv file:&lt;br /&gt;&lt;blockquote&gt;select * from OpenRowset('MSDASQL',&lt;br /&gt; 'Driver={Microsoft Text Driver (*.txt; *.csv)};DefaultDir=C:\temp;',&lt;br /&gt; 'select top 3 * from "Employees.csv"')&lt;/blockquote&gt;It seems you cannot append to csv using MSDASQL.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-116008031776919310?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/116008031776919310/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=116008031776919310' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/116008031776919310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/116008031776919310'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2006/10/sql-server-append-query-result-to-csv.html' title='SQL Server - Append Query Result to .csv file'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-115595163415954310</id><published>2006-08-18T21:35:00.000-04:00</published><updated>2006-10-26T14:58:21.239-04:00</updated><title type='text'>Drop Linked Server in SQL Server</title><content type='html'>You have learned how to create linked server in SQL Server in &lt;a href="http://floretli.blogspot.com/2006/07/accessing-oracle-from-sql-server.html"&gt;Accessing Oracle From SQL Server&lt;/a&gt;. Sometimes you may want to drop it. I'll show you how.&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;First find and drop the logins associated with the linked server.&lt;br /&gt;user master&lt;br /&gt;go&lt;br /&gt;&lt;br /&gt;select s.srvid, s.srvname, l.name login_name_associated&lt;br /&gt;from dbo.sysxlogins x, dbo.syslogins l, dbo.sysservers s&lt;br /&gt;where l.sid = x.sid and s.srvid = x.srvid and s.srvname = 'ora_test'&lt;br /&gt;go&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;srvid   srvname         login_name_associated&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;-----   ---------       ------------------------&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;1       ora_test        sa&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;1       ora_test        analyst&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;Now sa and analyst need to be dropped from the linked server.&lt;br /&gt;&lt;blockquote&gt;sp_droplinkedsrvlogin @rmtsrvname = 'ora_test', @locallogin = 'analyst'&lt;br /&gt;go&lt;br /&gt;sp_droplinkedsrvlogin @rmtsrvname = 'ora_test', @locallogin = 'sa'&lt;br /&gt;go&lt;/blockquote&gt;Then the linked server is ready to be dropped.&lt;br /&gt;&lt;blockquote&gt;sp_dropserver @server = 'ora_test'&lt;br /&gt;go&lt;br /&gt;&lt;/blockquote&gt;The logins have to be dropped from linked server first, otherwise an error message will show:&lt;br /&gt;&lt;blockquote&gt;There are still remote logins for the server 'ora_test'.&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-115595163415954310?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/115595163415954310/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=115595163415954310' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/115595163415954310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/115595163415954310'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2006/08/drop-linked-server-in-sql-server.html' title='Drop Linked Server in SQL Server'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-115584670772908334</id><published>2006-08-17T16:28:00.000-04:00</published><updated>2006-10-26T14:58:21.168-04:00</updated><title type='text'>Oracle Flashback Query Using AS OF TIMESTAMP</title><content type='html'>Since Oracle 9i Release 2, you can use "AS OF SCN | TIMESTAMP" flashback query to query the "before" data of a changed table. It's useful to find the changes you made or recover errors.&lt;br /&gt;I used TIMESTAMP more often and found it simple but efficient. I'll show some examples below.&lt;br /&gt;&lt;blockquote&gt;  SQL&gt; select salary from employees where employee_id = 100;&lt;br /&gt;     SALARY&lt;br /&gt; ----------&lt;br /&gt;      24000&lt;br /&gt;&lt;br /&gt; SQL&gt; update employees set salary = salary * 1.05 where employee_id = 100;&lt;br /&gt; 1 row updated.&lt;br /&gt;&lt;br /&gt; SQL&gt; commit;&lt;br /&gt;&lt;br /&gt; SQL&gt; select salary from employees where employee_id = 100;&lt;br /&gt;     SALARY&lt;br /&gt; ----------&lt;br /&gt;      25200&lt;/blockquote&gt;Here shows the way to query the "before" data of yesterday:&lt;br /&gt;&lt;blockquote&gt;  SQL&gt; select salary from employees AS OF TIMESTAMP sysdate - 1 where employee_id = 100;&lt;br /&gt;     SALARY&lt;br /&gt; ----------&lt;br /&gt;      24000&lt;br /&gt;&lt;/blockquote&gt;To show ten (10) minutes ago:&lt;br /&gt;&lt;blockquote&gt;  select salary from employees AS OF TIMESTAMP sysdate - 10/60/24 where employee_id = 100;&lt;br /&gt;&lt;/blockquote&gt;Or you can use function SYSTIMESTAMP instead of sysdate.&lt;br /&gt;&lt;blockquote&gt;  select salary from employees AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '1' DAY) where employee_id = 100;&lt;br /&gt; select salary from employees AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '10' MINUTE) where employee_id = 100;&lt;br /&gt;&lt;/blockquote&gt;To recover the change:&lt;br /&gt;&lt;blockquote&gt;  SQL&gt;update employees e1 set salary =&lt;br /&gt;     ( select salary from employees AS OF TIMESTAMP sysdate - 1 e2&lt;br /&gt;       where e2.employee_id = e1.employee_id )&lt;br /&gt; where employee_id = 100;&lt;br /&gt; 1 row updated.&lt;br /&gt;&lt;/blockquote&gt;&lt;blockquote&gt;  SQL&gt; select salary from employees where employee_id = 100;&lt;br /&gt;     SALARY&lt;br /&gt; ----------&lt;br /&gt;      24000&lt;br /&gt;&lt;/blockquote&gt;You may sometimes want to save the before data to a temporary table, then compare and reccover.&lt;br /&gt;&lt;blockquote&gt;  create table tmp_employees nologging as select * from employees AS OF TIMESTAMP sysdate - 1;&lt;br /&gt;&lt;/blockquote&gt;The SELECT ... AS OF will not work after the table structure changes or  table truncation.&lt;br /&gt;&lt;blockquote&gt;  SQL&gt; truncate table tmp_objects;&lt;br /&gt; Table truncated.&lt;br /&gt;&lt;br /&gt; SQL&gt; select count(*) from tmp_objects as of timestamp sysdate - 1/24/60;&lt;br /&gt;&lt;br /&gt; ORA-01466: unable to read data - table definition has changed&lt;br /&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-115584670772908334?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/115584670772908334/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=115584670772908334' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/115584670772908334'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/115584670772908334'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2006/08/oracle-flashback-query-using-as-of.html' title='Oracle Flashback Query Using AS OF TIMESTAMP'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-115428303614313281</id><published>2006-07-30T13:55:00.000-04:00</published><updated>2006-10-26T14:58:21.099-04:00</updated><title type='text'>Accessing Oracle From SQL Server</title><content type='html'>SQL Server supports &lt;span style="font-weight: bold;"&gt;linked server&lt;/span&gt; to  execute SQL commands against another database or data file. With the help of Oracle SQL*Net, connection from SQL Server to Oracle is fairly easy (comparing to Oracle to SQL Server using &lt;span class="bodycopy"&gt;Oracle Generic Connectivity&lt;/span&gt; -- I'll discuss it later).&lt;br /&gt;&lt;br /&gt;Below shows the steps. The target Oracle database is named TEST and with sample schema HR, password HR.&lt;br /&gt;&lt;br /&gt;1. You need to install Oracle SQL*Net on the SQL Server box. The simple way is to install the Oracle client.&lt;br /&gt;&lt;br /&gt;2. Use Oracle Net Configuration Assistant to configure a SQL*Net local service name. Or you can simply add an entry into file $ORACLE_HOME/network/admin/tnsname.ora:&lt;br /&gt;&lt;blockquote&gt;TEST =&lt;br /&gt;(DESCRIPTION =&lt;br /&gt;(ADDRESS_LIST =&lt;br /&gt;(ADDRESS = (PROTOCOL = TCP)(HOST = &lt;span style="font-weight: bold;"&gt;ORACLE_HOST&lt;/span&gt;)(PORT = 1521))&lt;br /&gt;)&lt;br /&gt;(CONNECT_DATA =&lt;br /&gt;(SERVICE_NAME = &lt;span style="font-weight: bold;"&gt;ORACLE_SID&lt;/span&gt;)&lt;br /&gt;)&lt;br /&gt;)&lt;br /&gt;&lt;/blockquote&gt;Replace ORACLE_HOST and ORACLE_SID with your oracle server name and SID or service name.&lt;br /&gt;&lt;br /&gt;3. Add linked server in SQL Server. Login as sa:&lt;br /&gt;&lt;blockquote&gt;p_addlinkedserver @server = 'ora_test'&lt;br /&gt;,  @srvproduct =  'Oracle'&lt;br /&gt;,  @provider = 'MSDAORA'&lt;br /&gt;,  @datasrc = 'test'&lt;br /&gt;&lt;/blockquote&gt;Where ora_test is the linked server you're going to created (or you can name it whatever you want), test is the local service name of SQL*Net. Keep product and provider Oracle and MSDAORA respectively.&lt;br /&gt;&lt;br /&gt;4. Map login on SQL Server, this will give the login permission to access the linked Oracle server.&lt;br /&gt;&lt;blockquote&gt;sp_addlinkedsrvlogin @rmtsrvname = 'ora_test'&lt;br /&gt;, @useself = false&lt;br /&gt;,  @locallogin =  'analyst'&lt;br /&gt;,  @rmtuser =  'hr'&lt;br /&gt;,  @rmtpassword =  'hr'&lt;/blockquote&gt;The example above gives analyst (a SQL Server login) permission to access hr schema in Oracle.&lt;br /&gt;&lt;br /&gt;5. Test&lt;br /&gt;&lt;blockquote&gt;select * from ora_test..HR.EMPLOYEES&lt;/blockquote&gt;You'll see:&lt;br /&gt;&lt;blockquote&gt;100    Steven    King    SKING    515.123.4567    1987-06-17 00:00:00.000    AD_PRES    24000.00    NULL    NULL    90&lt;br /&gt;...&lt;br /&gt;&lt;/blockquote&gt;The object names in Oracle are in upper case. So you'll need to spell the schema and object names in upper case unless they're defined in lower or mixed case. In the example above, if you want select * from ora_test..HR.&lt;span style="font-weight: bold;"&gt;employees&lt;/span&gt;, you'll be informed that such table does not exist. Because SQL Server will translate the SQL to: select * from ora_test..HR.&lt;span style="font-weight: bold;"&gt;"employees"&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-115428303614313281?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/115428303614313281/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=115428303614313281' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/115428303614313281'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/115428303614313281'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2006/07/accessing-oracle-from-sql-server.html' title='Accessing Oracle From SQL Server'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-115230593301909355</id><published>2006-07-07T16:43:00.000-04:00</published><updated>2006-10-26T14:58:21.020-04:00</updated><title type='text'>Trailing spaces in VARCHAR</title><content type='html'>I just noticed that many people  are misunderstanding the trailing spaces in VARCHAR field. The truth is they're &lt;span style="font-weight: bold;"&gt;not&lt;/span&gt; trimmed automatically. At least in the databases I know, Oracle, Sybase, SQL Server, DB2, MySQL, etc.&lt;br /&gt;&lt;br /&gt;Many know that when you save "abc" into char(5), two trailing spaces will be padded. And when you save "abc" into varchar(5), no space will be added.&lt;br /&gt;&lt;br /&gt;How about save "abc " into varchar(5)? Well, the database will keep the trailing space. This sounds reasonable. Many make mistakes when copying data from char field to varchar field or changing the char type to varchar type. Remember, you'll need to trim, at least right trim them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-115230593301909355?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/115230593301909355/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=115230593301909355' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/115230593301909355'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/115230593301909355'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2006/07/trailing-spaces-in-varchar.html' title='Trailing spaces in VARCHAR'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-115161440351514432</id><published>2006-06-29T16:41:00.000-04:00</published><updated>2006-10-26T14:58:20.904-04:00</updated><title type='text'>Multiply records</title><content type='html'>In one of my task, I needed to multiply some records in a table, so that they can have more chances to be picked up in a random draw. I did it in SQL Server, so I'll show it in SQL. It's similar in Oracle.&lt;br /&gt;What I need to do is to Cartesian join the target records with a table with a certain number of records.&lt;br /&gt;&lt;br /&gt;Create a test table and insert some records.&lt;br /&gt;&lt;blockquote  style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;create table test_multiply( id  int, type varchar(10), comments  varchar(100) )&lt;br /&gt;go&lt;br /&gt;insert into test_multiply values ( 1, 'single', 'This row will show only once' )&lt;br /&gt;insert into test_multiply values ( 2, 'times 10', 'This row will repeat 10 times' )&lt;br /&gt;go&lt;/span&gt;&lt;/blockquote&gt;Now we're to multiply the second record 10 times, we join the records with a table contains 9 records.&lt;br /&gt;&lt;blockquote&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;insert into test_multiply&lt;br /&gt;select a.* from test_multiply a&lt;br /&gt;inner join ( select top 9 id from sysobjects ) x on 1=1&lt;br /&gt;where a.type = 'times 10'&lt;br /&gt;go&lt;br /&gt;(9 rows affected)&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;Check the result.&lt;br /&gt;&lt;blockquote  style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;select id, type, count(*) cnt from test_multiply group by id, type&lt;br /&gt;go&lt;br /&gt;id          type       cnt&lt;br /&gt;----------- ---------- -----------&lt;br /&gt;         1 single               1&lt;br /&gt;         2 times 10            10&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;Similar in Oracle.&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;&lt;blockquote&gt;insert into test_multiply&lt;br /&gt;select a.* from test_multiply a&lt;br /&gt;inner join ( select 1 from all_objects where rownum &lt; 1="1" type =" 'times"&gt;&lt;/blockquote&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-115161440351514432?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/115161440351514432/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=115161440351514432' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/115161440351514432'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/115161440351514432'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2006/06/multiply-records.html' title='Multiply records'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-115075072897381717</id><published>2006-06-19T16:40:00.000-04:00</published><updated>2006-10-26T14:58:20.817-04:00</updated><title type='text'>PowerMultiSet in Oracle 10g</title><content type='html'>In one of my task, I needed to find all the possible combinations of a few strings. By searching the functions in Oracle, I found an interesting and powerful function: PowerMultiSet.&lt;br /&gt;&lt;br /&gt;Oracle says the function returns a nested table of nested tables containing all nonempty subsets (called submultisets) of the input nested table.&lt;br /&gt;&lt;br /&gt;The submultisets are just the combinations of all elements (you're guaranteed :-) ) and will have 2&lt;sup&gt;n&lt;/sup&gt;-1 sets.&lt;br /&gt;&lt;br /&gt;Let see with an example:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-family:courier new;"&gt;create or replace type NUM_LIST_TYPE is table of number;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  /&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  create or replace type NUM_LIST_LIST_TYPE is table of NUM_LIST_TYPE;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  /&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;select NUM_LIST_TYPE( 1, 2, 3 ) base_set from dual;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  BASE_SET&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  -----------------------&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  NUM_LIST_TYPE(1, 2, 3)&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;It shows three elements in the set: 1, 2 and 3. The run PowerMultiSet.&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-family:courier new;"&gt;select cast( powermultiset( NUM_LIST_TYPE( 1, 2, 3 ) ) as NUM_LIST_LIST_TYPE ) power_set from dual;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  POWER_SET&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  --------------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  NUM_LIST_LIST_TYPE(NUM_LIST_TYPE(1), NUM_LIST_TYPE(2), NUM_LIST_TYPE(1, 2), NUM_&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  LIST_TYPE(3), NUM_LIST_TYPE(1, 3), NUM_LIST_TYPE(2, 3), NUM_LIST_TYPE(1, 2, 3))&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;Let's make it easy to read:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;1&lt;br /&gt;2&lt;br /&gt;1 2&lt;br /&gt;3&lt;br /&gt;1 3&lt;br /&gt;2 3&lt;br /&gt;1 2 3&lt;br /&gt;&lt;/blockquote&gt;However, you have to create the type that is &lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-weight: bold;"&gt;nested table of nested&lt;/span&gt; tables&lt;/span&gt; and cast the result into it. Otherwise, you'll get an error.&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;select powermultiset( NUM_LIST_TYPE( 1, 2, 3 ) ) power_set from dual;&lt;br /&gt;&lt;br /&gt;ORA-22833: Must cast a transient type to a persistent type&lt;br /&gt;&lt;/blockquote&gt;The number of elements in the input nested table cannot exceed 32. The number of submulties in such case would be 2&lt;sup&gt;32&lt;/sup&gt; -1, that's 4 gig.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-115075072897381717?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/115075072897381717/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=115075072897381717' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/115075072897381717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/115075072897381717'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2006/06/powermultiset-in-oracle-10g.html' title='PowerMultiSet in Oracle 10g'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-114988502092574098</id><published>2006-06-09T16:22:00.000-04:00</published><updated>2006-10-26T14:58:20.732-04:00</updated><title type='text'>String aggregate in Oracle</title><content type='html'>&lt;p&gt;You may have known aggregate functions well, for example, sum, count, max, min, etc. How about add up strings? After searching on the web for a while, I found a function (See the code at the bottom).&lt;/p&gt;The main function is &lt;b&gt;STRING_AGG&lt;/b&gt;, which you can use the same way as other aggregate functions. Example:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;    select employee_id, string_agg( job_id ) job_list from job_history group by employee_id;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;Here's the output in SQL Plus:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;      EMPLOYEE_ID JOB_LIST&lt;br /&gt;  ----------- ----------------------------------------&lt;br /&gt;          101 AC_ACCOUNT,AC_MGR&lt;br /&gt;          102 IT_PROG&lt;br /&gt;          114 ST_CLERK&lt;br /&gt;          122 ST_CLERK&lt;br /&gt;          176 SA_REP,SA_MAN&lt;br /&gt;          200 AD_ASST,AC_ACCOUNT&lt;br /&gt;          201 MK_REP&lt;br /&gt;&lt;br /&gt;  7 rows selected.&lt;br /&gt;&lt;/pre&gt;The delimiter by default is comma (,), and is controlled by a store package &lt;b&gt;STRING_AGG_CONTROL&lt;/b&gt;. To change it, you can use:&lt;br /&gt;&lt;pre&gt;     begin string_agg_control.g_delim := '|'; end;&lt;br /&gt;   /&lt;br /&gt;&lt;/pre&gt;Then run the sql again:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;    select employee_id, string_agg( job_id ) job_list from job_history group by employee_id;&lt;br /&gt;  EMPLOYEE_ID JOB_LIST&lt;br /&gt;  ----------- ----------------------------------------&lt;br /&gt;          101 AC_ACCOUNT|AC_MGR&lt;br /&gt;          102 IT_PROG&lt;br /&gt;          114 ST_CLERK&lt;br /&gt;          122 ST_CLERK&lt;br /&gt;          176 SA_REP|SA_MAN&lt;br /&gt;          200 AD_ASST|AC_ACCOUNT&lt;br /&gt;          201 MK_REP&lt;br /&gt;&lt;br /&gt;  7 rows selected.&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;The function is implemented using an Oracle user defined type with the help of User-Defined Aggregates Interface. You can find more information in &lt;a href="http://download-east.oracle.com/docs/cd/B19306_01/appdev.102/b14289/dciaggfns.htm#sthref542"&gt;this doc&lt;/a&gt;.&lt;br /&gt;Sounds perfect? Not that much -- you cannot order the strings. That means the source strings appear in the aggregate string randomly.&lt;br /&gt;&lt;p&gt;&lt;/p&gt;The script is attached:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;create or replace package string_agg_control IS&lt;br /&gt;  g_delim  varchar2(100) := ',';&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;CREATE OR REPLACE TYPE t_string_agg AS OBJECT&lt;br /&gt;(&lt;br /&gt;  g_string  VARCHAR2(32767),&lt;br /&gt;  g_delim   VARCHAR2(100),  -- Delimiter to seperate the strings&lt;br /&gt;&lt;br /&gt;  STATIC FUNCTION ODCIAggregateInitialize(sctx  IN OUT  t_string_agg)&lt;br /&gt;    RETURN NUMBER,&lt;br /&gt;&lt;br /&gt;  MEMBER FUNCTION ODCIAggregateIterate(self   IN OUT  t_string_agg,&lt;br /&gt;                                       value  IN      VARCHAR2 )&lt;br /&gt;     RETURN NUMBER,&lt;br /&gt;&lt;br /&gt;  MEMBER FUNCTION ODCIAggregateTerminate(self         IN   t_string_agg,&lt;br /&gt;                                         returnValue  OUT  VARCHAR2,&lt;br /&gt;                                         flags        IN   NUMBER)&lt;br /&gt;    RETURN NUMBER,&lt;br /&gt;&lt;br /&gt;  MEMBER FUNCTION ODCIAggregateMerge(self  IN OUT  t_string_agg,&lt;br /&gt;                                     ctx2  IN      t_string_agg)&lt;br /&gt;    RETURN NUMBER&lt;br /&gt;);&lt;br /&gt;/&lt;br /&gt;SHOW ERRORS&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE OR REPLACE TYPE BODY t_string_agg IS&lt;br /&gt;  STATIC FUNCTION ODCIAggregateInitialize(sctx  IN OUT  t_string_agg)&lt;br /&gt;    RETURN NUMBER IS&lt;br /&gt;  BEGIN&lt;br /&gt;    sctx := t_string_agg( NULL, string_agg_control.g_delim );&lt;br /&gt;    RETURN ODCIConst.Success;&lt;br /&gt;  END;&lt;br /&gt;&lt;br /&gt;  MEMBER FUNCTION ODCIAggregateIterate(self   IN OUT  t_string_agg,&lt;br /&gt;                                       value  IN      VARCHAR2 )&lt;br /&gt;    RETURN NUMBER IS&lt;br /&gt;  BEGIN&lt;br /&gt;    SELF.g_string := self.g_string || self.g_delim || value;&lt;br /&gt;    RETURN ODCIConst.Success;&lt;br /&gt;  END;&lt;br /&gt;&lt;br /&gt;  MEMBER FUNCTION ODCIAggregateTerminate(self         IN   t_string_agg,&lt;br /&gt;                                         returnValue  OUT  VARCHAR2,&lt;br /&gt;                                         flags        IN   NUMBER)&lt;br /&gt;    RETURN NUMBER IS&lt;br /&gt;  BEGIN&lt;br /&gt;    returnValue := RTRIM(LTRIM(SELF.g_string, self.g_delim ), self.g_delim );&lt;br /&gt;    RETURN ODCIConst.Success;&lt;br /&gt;  END;&lt;br /&gt;&lt;br /&gt;  MEMBER FUNCTION ODCIAggregateMerge(self  IN OUT  t_string_agg,&lt;br /&gt;                                     ctx2  IN      t_string_agg)&lt;br /&gt;    RETURN NUMBER IS&lt;br /&gt;  BEGIN&lt;br /&gt;    SELF.g_string := SELF.g_string || self.g_delim || ctx2.g_string;&lt;br /&gt;    RETURN ODCIConst.Success;&lt;br /&gt;  END;&lt;br /&gt;END;&lt;br /&gt;/&lt;br /&gt;SHOW ERRORS&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE OR REPLACE FUNCTION string_agg (p_input VARCHAR2)&lt;br /&gt;RETURN VARCHAR2&lt;br /&gt;PARALLEL_ENABLE AGGREGATE USING t_string_agg;&lt;br /&gt;/&lt;br /&gt;SHOW ERRORS&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/28333051-114988502092574098?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/114988502092574098/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=114988502092574098' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/114988502092574098'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/114988502092574098'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2006/06/string-aggregate-in-oracle.html' title='String aggregate in Oracle'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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-28333051.post-114834526143567816</id><published>2006-05-22T20:21:00.000-04:00</published><updated>2006-10-26T14:58:20.647-04:00</updated><title type='text'>Testing cursor variable in SQL Plus</title><content type='html'>In Oracle stored functions and procedures, you may often return or pass out a result set using cursor variable. Here're some ways I found you can test those cusor variables using SQL Plus. It uses the Oracle hr schema for the example.&lt;br /&gt;&lt;br /&gt;Now I created a package:&lt;br /&gt;&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;create or replace package test_refcursor as&lt;br /&gt; TYPE DynamicCursorType IS REF CURSOR;&lt;br /&gt; procedure test( id in number,&lt;br /&gt;         result out DynamicCursorType );&lt;br /&gt;end test_refcursor;&lt;br /&gt;/&lt;/blockquote&gt;Create test package body:&lt;br /&gt;&lt;blockquote&gt;create or replace package body test_refcursor as&lt;br /&gt;  procedure test (&lt;br /&gt;      id    in   number,&lt;br /&gt;      result out DynamicCursorType&lt;br /&gt;   )&lt;br /&gt; as&lt;br /&gt; begin&lt;br /&gt;  open result for select department_id,department_name&lt;br /&gt;         from departments where department_id &lt; id;  &lt;br /&gt;end;&lt;br /&gt;end test_refcursor;&lt;br /&gt;/ &lt;/blockquote&gt;The procedure test returns all the departments with department_id lower than passed in ID.&lt;br /&gt;&lt;br /&gt;Now the first way to test it in a PL/SQL block:&lt;br /&gt;&lt;blockquote&gt;set serveroutput on&lt;br /&gt;declare&lt;br /&gt; p  test_refcursor.DynamicCursorType;&lt;br /&gt; v_id   number(4);&lt;br /&gt; v_name varchar2(100);&lt;br /&gt;begin&lt;br /&gt; test_refcursor.test( 50, p );&lt;br /&gt; -- The cusor has already opened, no need to open again.&lt;br /&gt; loop&lt;br /&gt;   fetch p into v_id, v_name;&lt;br /&gt;   exit when p%NOTFOUND;&lt;br /&gt;   dbms_output.put_line( v_id || ', ' || v_name );&lt;br /&gt; end loop;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;/blockquote&gt;The result you can see:&lt;br /&gt;&lt;blockquote&gt;10, Administration&lt;br /&gt;20, Marketing&lt;br /&gt;30, Purchasing&lt;br /&gt;40, Human Resources&lt;/blockquote&gt;There's another way even easier in SQL Plus:&lt;br /&gt;&lt;blockquote&gt;var p refcursor&lt;br /&gt;exec test_refcursor.test( 50, :p );&lt;br /&gt;print p&lt;br /&gt;&lt;/blockquote&gt;It'll print as if you select the data from a table:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;DEPARTMENT_ID DEPARTMENT_NAME&lt;br /&gt;------------- ----------------------------------&lt;br /&gt;          10            Administration&lt;br /&gt;          20 Marketing&lt;br /&gt;          30 Purchasing&lt;br /&gt;          40 Human Resources&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28333051-114834526143567816?l=floretli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floretli.blogspot.com/feeds/114834526143567816/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28333051&amp;postID=114834526143567816' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/114834526143567816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28333051/posts/default/114834526143567816'/><link rel='alternate' type='text/html' href='http://floretli.blogspot.com/2006/05/testing-cursor-variable-in-sql-plus.html' title='Testing cursor variable in SQL Plus'/><author><name>floretli</name><uri>http://www.blogger.com/profile/06587975241596799819</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>
