﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-小菜毛毛技术分享-文章分类-数据库</title><link>http://www.blogjava.net/caizh2009/category/39398.html</link><description>与大家共同成长</description><language>zh-cn</language><lastBuildDate>Mon, 08 Mar 2010 15:42:39 GMT</lastBuildDate><pubDate>Mon, 08 Mar 2010 15:42:39 GMT</pubDate><ttl>60</ttl><item><title>查看oracle执行计划</title><link>http://www.blogjava.net/caizh2009/articles/312205.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Sat, 06 Feb 2010 09:30:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/312205.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/312205.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/312205.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/312205.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/312205.html</trackback:ping><description><![CDATA[<p>日常开发活动中，有时候需要对oracle执行计划进行监控，以此来调优程序和数据库方面的性能。</p>
<p>　　常用方法有以下几种：</p>
<p>　　一、通过PL/SQL Dev工具</p>
<p>　　1、直接File-&gt;New-&gt;Explain Plan Window，在窗口中执行sql可以查看计划结果。其中，Cost表示cpu的消耗，单位为n%，Cardinality表示执行的行数，等价Rows。</p>
<p>　　2、先执行 EXPLAIN PLAN FOR　　 select * from tableA　where paraA=1，再 select * from table(DBMS_XPLAN.DISPLAY)便可以看到oracle的执行计划了，看到的结果和1中的一样，所以使用工具的时候推荐使用1方法。</p>
<p>　　注意：PL/SQL Dev工具的Command window中不支持set autotrance on的命令。还有使用工具方法查看计划看到的信息不全，有些时候我们需要sqlplus的支持。</p>
<p>　　二、通过sqlplus</p>
<p>　　1、一般情况都是本机链接远程服务器，所以命令如下：</p>
<p>　　sqlplus user/pwd@serviceName</p>
<p>　　此处的serviceName为tnsnames.ora中定义的命名空间。</p>
<p>　　2、执行set autotrace on，然后执行sql语句，会列出以下信息：</p>
<p>　　。。。（省略一些信息）</p>
<p>　　统计信息</p>
<p>　　----------------------------------------------------------</p>
<p>　　　　　　　　　　1　　recursive　calls　（归调用次数）<br />
　　　　　　　　　　0　　db　block　gets　　<br />
　　　　　　　　　　2　　consistent　gets<br />
　　　　　　　　　　0　　physical　reads　（物理读——执行SQL的过程中，从硬盘上读取的数据块个数）<br />
　　　　　　　　　　0　　redo　size　(重做数——执行SQL的过程中，产生的重做日志的大小)<br />
　　　　　　　　358　　bytes　sent　via　SQL*Net　to　client<br />
　　　　　　　　366　　bytes　received　via　SQL*Net　from　client<br />
　　　　　　　　　　1　　SQL*Net　roundtrips　to/from　client<br />
　　　　　　　　　　0　　sorts　(memory)　　　　　在内存中发生的排序<br />
　　　　　　　　　　0　　sorts　(disk)　　　　　在硬盘中发生的排序<br />
　　　　　　　　　　1　　rows　processed</p>
<p>　　省略部分信息和通过PL/SQL Dev工具查看执行计划的信息一样，下面的统计信息是更详细的。 </p>
<p>　　判断SQL效率高低不关通过时间来衡量，还应该通过执行SQL执行状态里面的逻辑读的数量</p>
<p>　　逻辑读=（db block gets+ consistent gets） </p>
<p>FengFly.Com <br />
ＷWＷ.ＦENGＦLy.ＣOM FengFly.Com </p>
<p><br />
原文来自：雨枫技术教程网 http://www.fengfly.com<br />
原文网址：http://www.fengfly.com/plus/view-161902-1.html</p>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/312205.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-06 17:30 <a href="http://www.blogjava.net/caizh2009/articles/312205.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ORACLE执行计划的一些基本概念</title><link>http://www.blogjava.net/caizh2009/articles/312193.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Sat, 06 Feb 2010 08:24:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/312193.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/312193.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/312193.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/312193.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/312193.html</trackback:ping><description><![CDATA[<p><strong>一．相关的概念</strong></p>
<p>Rowid的概念：rowid是一个伪列，既然是伪列，那么这个列就不是用户定义，而是系统自己给加上的。对每个表都有一个rowid的伪列，但是表中并不物理存储ROWID列的值。不过你可以像使用其它列那样使用它，但是不能删除改列，也不能对该列的值进行修改、插入。一旦一行数据插入数据库，则rowid在该行的生命周期内是唯一的，即即使该行产生行迁移，行的rowid也不会改变。</p>
<p>Recursive SQL概念：有时为了执行用户发出的一个sql语句，Oracle必须执行一些额外的语句，我们将这些额外的语句称之为'recursive calls'或'recursive SQL statements'。如当一个DDL语句发出后，ORACLE总是隐含的发出一些recursive SQL语句，来修改数据字典信息，以便用户可以成功的执行该DDL语句。当需要的数据字典信息没有在共享内存中时，经常会发生Recursive calls，这些Recursive calls会将数据字典信息从硬盘读入内存中。用户不比关心这些recursive SQL语句的执行情况，在需要的时候，ORACLE会自动的在内部执行这些语句。当然DML语句与SELECT都可能引起recursive SQL。简单的说，我们可以将触发器视为recursive SQL。</p>
<p>Row Source(行源)：用在查询中，由上一操作返回的符合条件的行的集合，即可以是表的全部行数据的集合；也可以是表的部分行数据的集合；也可以为对上2个row source进行连接操作(如join连接)后得到的行数据集合。</p>
<p>Predicate(谓词)：一个查询中的WHERE限制条件</p>
<p>Driving Table(驱动表)：该表又称为外层表(OUTER TABLE)。这个概念用于嵌套与HASH连接中。如果该row source返回较多的行数据，则对所有的后续操作有负面影响。注意此处虽然翻译为驱动表，但实际上翻译为驱动行源(driving row source)更为确切。一般说来，是应用查询的限制条件后，返回较少行源的表作为驱动表，所以如果一个大表在WHERE条件有有限制条件(如等值限制)，则该大表作为驱动表也是合适的，所以并不是只有较小的表可以作为驱动表，正确说法应该为应用查询的限制条件后，返回较少行源的表作为驱动表。在执行计划中，应该为靠上的那个row source，后面会给出具体说明。在我们后面的描述中，一般将该表称为连接操作的row source 1。</p>
<p>Probed Table(被探查表)：该表又称为内层表(INNER TABLE)。在我们从驱动表中得到具体一行的数据后，在该表中寻找符合连接条件的行。所以该表应当为大表(实际上应该为返回较大row source的表)且相应的列上应该有索引。在我们后面的描述中，一般将该表称为连接操作的row source 2。</p>
<p>组合索引(concatenated index)：由多个列构成的索引，如create index idx_emp on emp(col1, col2, col3, &#8230;&#8230;)，则我们称idx_emp索引为组合索引。在组合索引中有一个重要的概念：引导列(leading column)，在上面的例子中，col1列为引导列。当我们进行查询时可以使用&#8221;where col1 = ? &#8221;，也可以使用&#8221;where col1 = ? and col2 = ?&#8221;，这样的限制条件都会使用索引，但是&#8221;where col2 = ? &#8221;查询就不会使用该索引。所以限制条件中包含先导列时，该限制条件才会使用该组合索引。</p>
<p>可选择性(selectivity)：比较一下列中唯一键的数量和表中的行数，就可以判断该列的可选择性。如果该列的&#8221;唯一键的数量/表中的行数&#8221;的比值越接近1，则该列的可选择性越高，该列就越适合创建索引，同样索引的可选择性也越高。在可选择性高的列上进行查询时，返回的数据就较少，比较适合使用索引查询。<br />
<strong>二．oracle访问数据的存取方法</strong></p>
<p>1) 全表扫描（Full Table Scans, FTS）</p>
<p>为实现全表扫描，Oracle读取表中所有的行，并检查每一行是否满足语句的WHERE限制条件一个多块读操作可以使一次I/O能读取多块数据块(db_block_multiblock_read_count参数设定)，而不是只读取一个数据块，这极大的减少了I/O总次数，提高了系统的吞吐量，所以利用多块读的方法可以十分高效地实现全表扫描，而且只有在全表扫描的情况下才能使用多块读操作。在这种访问模式下，每个数据块只被读一次。<br />
使用FTS的前提条件：在较大的表上不建议使用全表扫描，除非取出数据的比较多，超过总量的5% -- 10%，或你想使用并行查询功能时。<br />
使用全表扫描的例子：<br />
~~~~~~~~~~~~~~~~~~~~~~~~
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre>SQL&gt; explain plan for select * from dual;<br />
            Query Plan<br />
            -----------------------------------------<br />
            SELECT STATEMENT[CHOOSE] Cost=<br />
            TABLE ACCESS FULL DUAL
            <p>&nbsp;</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p>2) 通过ROWID的表存取（Table Access by ROWID或rowid lookup）</p>
<p>行的ROWID指出了该行所在的数据文件、数据块以及行在该块中的位置，所以通过ROWID来存取数据可以快速定位到目标数据上，是Oracle存取单行数据的最快方法。<br />
这种存取方法不会用到多块读操作，一次I/O只能读取一个数据块。我们会经常在执行计划中看到该存取方法，如通过索引查询数据。</p>
<p>使用ROWID存取的方法：
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre>SQL&gt; explain plan for select * from dept where rowid = 'AAAAyGAADAAAAATAAF';<br />
            Query Plan<br />
            ------------------------------------<br />
            SELECT STATEMENT [CHOOSE] Cost=1<br />
            TABLE ACCESS BY ROWID DEPT [ANALYZED]</pre>
            </td>
        </tr>
    </tbody>
</table>
<p>3）索引扫描（Index Scan或index lookup）</p>
<p>我们先通过index查找到数据对应的rowid值(对于非唯一索引可能返回多个rowid值)，然后根据rowid直接从表中得到具体的数据，这种查找方式称为索引扫描或索引查找(index lookup)。一个rowid唯一的表示一行数据，该行对应的数据块是通过一次i/o得到的，在此情况下该次i/o只会读取一个数据库块。</p>
<p>在索引中，除了存储每个索引的值外，索引还存储具有此值的行对应的ROWID值。索引扫描可以由2步组成：(1) 扫描索引得到对应的rowid值。 (2) 通过找到的rowid从表中读出具体的数据。每步都是单独的一次I/O，但是对于索引，由于经常使用，绝大多数都已经CACHE到内存中，所以第1步的I/O经常是逻辑I/O，即数据可以从内存中得到。但是对于第2步来说，如果表比较大，则其数据不可能全在内存中，所以其I/O很有可能是物理I/O，这是一个机械操作，相对逻辑I/O来说，是极其费时间的。所以如果多大表进行索引扫描，取出的数据如果大于总量的5% -- 10%，使用索引扫描会效率下降很多。如下列所示：</p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre>
            <p>SQL&gt; explain plan for select empno, ename from emp where empno=10;<br />
            Query Plan<br />
            ------------------------------------<br />
            SELECT STATEMENT [CHOOSE] Cost=1<br />
            TABLE ACCESS BY ROWID EMP [ANALYZED] <br />
            INDEX UNIQUE SCAN EMP_I1</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p>但是如果查询的数据能全在索引中找到，就可以避免进行第2步操作，避免了不必要的I/O，此时即使通过索引扫描取出的数据比较多，效率还是很高的
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><br />
            SQL&gt; explain plan for select empno from emp where empno=10;-- 只查询empno列值<br />
            Query Plan<br />
            ------------------------------------<br />
            SELECT STATEMENT [CHOOSE] Cost=1<br />
            INDEX UNIQUE SCAN EMP_I1
            <p>&nbsp;</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p>进一步讲，如果sql语句中对索引列进行排序，因为索引已经预先排序好了，所以在执行计划中不需要再对索引列进行排序</p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre>
            <p>SQL&gt; explain plan for select empno, ename from emp<br />
            where empno &gt; 7876 order by empno;<br />
            Query Plan<br />
            --------------------------------------------------------------------------------<br />
            SELECT STATEMENT[CHOOSE] Cost=1<br />
            TABLE ACCESS BY ROWID EMP [ANALYZED] <br />
            INDEX RANGE SCAN EMP_I1 [ANALYZED] </p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p>从这个例子中可以看到：因为索引是已经排序了的，所以将按照索引的顺序查询出符合条件的行，因此避免了进一步排序操作。</p>
<p>根据索引的类型与where限制条件的不同，有4种类型的索引扫描：<br />
索引唯一扫描(index unique scan)<br />
索引范围扫描(index range scan)<br />
索引全扫描(index full scan)<br />
索引快速扫描(index fast full scan)<br />
(1) 索引唯一扫描(index unique scan)</p>
<p>通过唯一索引查找一个数值经常返回单个ROWID。如果存在UNIQUE 或PRIMARY KEY 约束（它保证了语句只存取单行）的话，Oracle经常实现唯一性扫描。<br />
使用唯一性约束的例子：</p>
<p>SQL&gt; explain plan for<br />
select empno,ename from emp where empno=10;<br />
Query Plan<br />
------------------------------------<br />
SELECT STATEMENT [CHOOSE] Cost=1<br />
TABLE ACCESS BY ROWID EMP [ANALYZED] <br />
INDEX UNIQUE SCAN EMP_I1<br />
(2) 索引范围扫描(index range scan)</p>
<p>使用一个索引存取多行数据，在唯一索引上使用索引范围扫描的典型情况下是在谓词(where限制条件)中使用了范围操作符(如&gt;、&lt;、&lt;&gt;、&gt;=、&lt;=、between)<br />
使用索引范围扫描的例子： </p>
<p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><br />
            SQL&gt; explain plan for select empno,ename from emp<br />
            where empno &gt; 7876 order by empno;<br />
            Query Plan<br />
            --------------------------------------------------------------------------------<br />
            SELECT STATEMENT[CHOOSE] Cost=1<br />
            TABLE ACCESS BY ROWID EMP [ANALYZED] <br />
            INDEX RANGE SCAN EMP_I1 [ANALYZED] </pre>
            </td>
        </tr>
    </tbody>
</table>
在非唯一索引上，谓词col = 5可能返回多行数据，所以在非唯一索引上都使用索引范围扫描。<br />
使用index rang scan的3种情况：
<p>(a) 在唯一索引列上使用了range操作符(&gt; &lt; &lt;&gt; &gt;= &lt;= between)<br />
(b) 在组合索引上，只使用部分列进行查询，导致查询出多行<br />
(c) 对非唯一索引列上进行的任何查询。<br />
(3) 索引全扫描(index full scan)</p>
<p>与全表扫描对应，也有相应的全索引扫描。而且此时查询出的数据都必须从索引中可以直接得到。<br />
全索引扫描的例子：</p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><br />
            An Index full scan will not perform single block i/o's and so it may prove to be inefficient.
            <p>e.g.<br />
            Index BE_IX is a concatenated index on big_emp (empno, ename)</p>
            <p>SQL&gt; explain plan for select empno, ename from big_emp order by empno,ename;<br />
            Query Plan<br />
            --------------------------------------------------------------------------------<br />
            SELECT STATEMENT[CHOOSE] Cost=26<br />
            INDEX FULL SCAN BE_IX [ANALYZED]</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p>(4) 索引快速扫描(index fast full scan)
<p>扫描索引中的所有的数据块，与 index full scan很类似，但是一个显著的区别就是它不对查询出的数据进行排序，即数据不是以排序顺序被返回。在这种存取方法中，可以使用多块读功能，也可以使用并行读入，以便获得最大吞吐量与缩短执行时间。</p>
<p>索引快速扫描的例子：</p>
<p>BE_IX索引是一个多列索引： </p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre>big_emp (empno,ename)
            <p>&nbsp;</p>
            <p>SQL&gt; explain plan for select empno,ename from big_emp;<br />
            Query Plan<br />
            ------------------------------------------<br />
            SELECT STATEMENT[CHOOSE] Cost=1<br />
            INDEX FAST FULL SCAN BE_IX [ANALYZED]</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p>只选择多列索引的第2列：
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><br />
            SQL&gt; explain plan for select ename from big_emp;<br />
            Query Plan<br />
            ------------------------------------------<br />
            SELECT STATEMENT[CHOOSE] Cost=1<br />
            INDEX FAST FULL SCAN BE_IX [ANALYZED]</pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>ORACLE执行计划的一些基本概念(2)<br />
<strong>三.表之间的连接</strong> </p>
<p>&nbsp;</p>
<p>Join是一种试图将两个表结合在一起的谓词，一次只能连接2个表，表连接也可以被称为表关联。在后面的叙述中，我们将会使用&#8221;row source&#8221;来代替&#8221;表&#8221;，因为使用row source更严谨一些，并且将参与连接的2个row source分别称为row source1和row source 2。Join过程的各个步骤经常是串行操作，即使相关的row source可以被并行访问，即可以并行的读取做join连接的两个row source的数据，但是在将表中符合限制条件的数据读入到内存形成row source后，join的其它步骤一般是串行的。有多种方法可以将2个表连接起来，当然每种方法都有自己的优缺点，每种连接类型只有在特定的条件下才会发挥出其最大优势。</p>
<p>row source(表)之间的连接顺序对于查询的效率有非常大的影响。通过首先存取特定的表，即将该表作为驱动表，这样可以先应用某些限制条件，从而得到一个较小的row source，使连接的效率较高，这也就是我们常说的要先执行限制条件的原因。一般是在将表读入内存时，应用where子句中对该表的限制条件。<br />
根据2个row source的连接条件的中操作符的不同，可以将连接分为等值连接(如WHERE A.COL3 = B.COL4)、非等值连接(WHERE A.COL3 &gt; B.COL4)、外连接(WHERE A.COL3 = B.COL4(+))。上面的各个连接的连接原理都基本一样，所以为了简单期间，下面以等值连接为例进行介绍。</p>
<p>在后面的介绍中，都已：<br />
SELECT A.COL1, B.COL2 <br />
FROM A, B<br />
WHERE A.COL3 = B.COL4;<br />
为例进行说明，假设A表为Row Soruce1，则其对应的连接操作关联列为COL 3；B表为Row Soruce2，则其对应的连接操作关联列为COL 4；</p>
<p>连接类型：<br />
目前为止，无论连接操作符如何，典型的连接类型共有3种：<br />
排序 - - 合并连接(Sort Merge Join (SMJ) )<br />
嵌套循环(Nested Loops (NL) )<br />
哈希连接(Hash Join)</p>
<p>排序 - - 合并连接(Sort Merge Join, SMJ)<br />
内部连接过程：<br />
1) 首先生成row source1需要的数据，然后对这些数据按照连接操作关联列(如A.col3)进行排序。<br />
2) 随后生成row source2需要的数据，然后对这些数据按照与sort source1对应的连接操作关联列(如B.col4)进行排序。<br />
3) 最后两边已排序的行被放在一起执行合并操作，即将2个row source按照连接条件连接起来<br />
下面是连接步骤的图形表示：<br />
MERGE<br />
/\<br />
SORTSORT<br />
||<br />
Row Source 1Row Source 2</p>
<p>如果row source已经在连接关联列上被排序，则该连接操作就不需要再进行sort操作，这样可以大大提高这种连接操作的连接速度，因为排序是个极其费资源的操作，特别是对于较大的表。预先排序的row source包括已经被索引的列(如a.col3或b.col4上有索引)或row source已经在前面的步骤中被排序了。尽管合并两个row source的过程是串行的，但是可以并行访问这两个row source(如并行读入数据，并行排序).</p>
<p>SMJ连接的例子：</p>
<p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre>
            <p>SQL&gt; explain plan for<br />
            select /*+ ordered */ e.deptno, d.deptno<br />
            from emp e, dept d<br />
            where e.deptno = d.deptno<br />
            order by e.deptno, d.deptno;</p>
            <p>Query Plan<br />
            -------------------------------------<br />
            SELECT STATEMENT [CHOOSE] Cost=17<br />
            MERGE JOIN<br />
            SORT JOIN<br />
            TABLE ACCESS FULL EMP [ANALYZED]<br />
            SORT JOIN<br />
            TABLE ACCESS FULL DEPT [ANALYZED]</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>排序是一个费时、费资源的操作，特别对于大表。基于这个原因，SMJ经常不是一个特别有效的连接方法，但是如果2个row source都已经预先排序，则这种连接方法的效率也是蛮高的。</p>
<p>嵌套循环(Nested Loops, NL)<br />
这个连接方法有驱动表(外部表)的概念。其实，该连接过程就是一个2层嵌套循环，所以外层循环的次数越少越好，这也就是我们为什么将小表或返回较小row source的表作为驱动表(用于外层循环)的理论依据。但是这个理论只是一般指导原则，因为遵循这个理论并不能总保证使语句产生的I/O次数最少。有时不遵守这个理论依据，反而会获得更好的效率。如果使用这种方法，决定使用哪个表作为驱动表很重要。有时如果驱动表选择不正确，将会导致语句的性能很差、很差。</p>
<p>内部连接过程：<br />
Row source1的Row 1 ---------------- Probe -&gt;Row source 2<br />
Row source1的Row 2 ---------------- Probe -&gt;Row source 2 <br />
Row source1的Row 3 ---------------- Probe -&gt;Row source 2<br />
&#8230;&#8230;.<br />
Row source1的Row n ---------------- Probe -&gt;Row source 2<br />
从内部连接过程来看，需要用row source1中的每一行，去匹配row source2中的所有行，所以此时保持row source1尽可能的小与高效的访问row source2(一般通过索引实现)是影响这个连接效率的关键问题。这只是理论指导原则，目的是使整个连接操作产生最少的物理I/O次数，而且如果遵守这个原则，一般也会使总的物理I/O数最少。但是如果不遵从这个指导原则，反而能用更少的物理I/O实现连接操作，那尽管违反指导原则吧！因为最少的物理I/O次数才是我们应该遵从的真正的指导原则，在后面的具体案例分析中就给出这样的例子。</p>
<p>在上面的连接过程中，我们称Row source1为驱动表或外部表。Row Source2被称为被探查表或内部表。</p>
<p>在NESTED LOOPS连接中，Oracle读取row source1中的每一行，然后在row sourc2中检查是否有匹配的行，所有被匹配的行都被放到结果集中，然后处理row source1中的下一行。这个过程一直继续，直到row source1中的所有行都被处理。这是从连接操作中可以得到第一个匹配行的最快的方法之一，这种类型的连接可以用在需要快速响应的语句中，以响应速度为主要目标。</p>
<p>如果driving row source(外部表)比较小，并且在inner row source(内部表)上有唯一索引，或有高选择性非唯一索引时，使用这种方法可以得到较好的效率。NESTED LOOPS有其它连接方法没有的的一个优点是：可以先返回已经连接的行，而不必等待所有的连接操作处理完才返回数据，这可以实现快速的响应时间。</p>
<p>如果不使用并行操作，最好的驱动表是那些应用了where 限制条件后，可以返回较少行数据的的表，所以大表也可能称为驱动表，关键看限制条件。对于并行查询，我们经常选择大表作为驱动表，因为大表可以充分利用并行功能。当然，有时对查询使用并行操作并不一定会比查询不使用并行操作效率高，因为最后可能每个表只有很少的行符合限制条件，而且还要看你的硬件配置是否可以支持并行(如是否有多个CPU，多个硬盘控制器)，所以要具体问题具体对待。 </p>
<p>NL连接的例子：
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><br />
            SQL&gt; explain plan for<br />
            select a.dname,b.sql<br />
            from dept a,emp b<br />
            where a.deptno = b.deptno;
            <p>Query Plan<br />
            -------------------------<br />
            SELECT STATEMENT [CHOOSE] Cost=5<br />
            NESTED LOOPS<br />
            TABLE ACCESS FULL DEPT [ANALYZED]<br />
            TABLE ACCESS FULL EMP [ANALYZED]</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p>哈希连接(Hash Join, HJ)</p>
<p>这种连接是在oracle 7.3以后引入的，从理论上来说比NL与SMJ更高效，而且只用在CBO优化器中。<br />
较小的row source被用来构建hash table与bitmap，第2个row source被用来被hansed，并与第一个row source生成的hash table进行匹配，以便进行进一步的连接。Bitmap被用来作为一种比较快的查找方法，来检查在hash table中是否有匹配的行。特别的，当hash table比较大而不能全部容纳在内存中时，这种查找方法更为有用。这种连接方法也有NL连接中所谓的驱动表的概念，被构建为hash table与bitmap的表为驱动表，当被构建的hash table与bitmap能被容纳在内存中时，这种连接方式的效率极高。 </p>
<p>HASH连接的例子：</p>
<p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><br />
            SQL&gt; explain plan for<br />
            select /*+ use_hash(emp) */ empno <br />
            from emp, dept<br />
            where emp.deptno = dept.deptno;
            <p>Query Plan<br />
            ----------------------------<br />
            SELECT STATEMENT[CHOOSE] Cost=3<br />
            HASH JOIN<br />
            TABLE ACCESS FULL DEPT<br />
            TABLE ACCESS FULL EMP</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>要使哈希连接有效，需要设置HASH_JOIN_ENABLED=TRUE，缺省情况下该参数为TRUE，另外，不要忘了还要设置hash_area_size参数，以使哈希连接高效运行，因为哈希连接会在该参数指定大小的内存中运行，过小的参数会使哈希连接的性能比其他连接方式还要低。
<p>总结一下，在哪种情况下用哪种连接方法比较好：</p>
<p>排序 - - 合并连接(Sort Merge Join, SMJ)：<br />
a) 对于非等值连接，这种连接方式的效率是比较高的。<br />
b) 如果在关联的列上都有索引，效果更好。<br />
c) 对于将2个较大的row source做连接，该连接方法比NL连接要好一些。<br />
d) 但是如果sort merge返回的row source过大，则又会导致使用过多的rowid在表中查询数据时，数据库性能下降，因为过多的I/O。</p>
<p>嵌套循环(Nested Loops, NL)：<br />
a) 如果driving row source(外部表)比较小，并且在inner row source(内部表)上有唯一索引，或有高选择性非唯一索引时，使用这种方法可以得到较好的效率。<br />
b) NESTED LOOPS有其它连接方法没有的的一个优点是：可以先返回已经连接的行，而不必等待所有的连接操作处理完才返回数据，这可以实现快速的响应时间。</p>
<p>哈希连接(Hash Join, HJ)：<br />
a) 这种方法是在oracle7后来引入的，使用了比较先进的连接理论，一般来说，其效率应该好于其它2种连接，但是这种连接只能用在CBO优化器中，而且需要设置合适的hash_area_size参数，才能取得较好的性能。<br />
b) 在2个较大的row source之间连接时会取得相对较好的效率，在一个row source较小时则能取得更好的效率。<br />
c) 只能用于等值连接中</p>
<p>笛卡儿乘积(Cartesian Product) </p>
<p>当两个row source做连接，但是它们之间没有关联条件时，就会在两个row source中做笛卡儿乘积，这通常由编写代码疏漏造成(即程序员忘了写关联条件)。笛卡尔乘积是一个表的每一行依次与另一个表中的所有行匹配。在特殊情况下我们可以使用笛卡儿乘积，如在星形连接中，除此之外，我们要尽量使用笛卡儿乘积，否则，自己想结果是什么吧！</p>
<p>注意在下面的语句中，在2个表之间没有连接。</p>
<p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><br />
            SQL&gt; explain plan for<br />
            select emp.deptno,dept,deptno <br />
            from emp,dept
            <p>Query Plan<br />
            ------------------------<br />
            SLECT STATEMENT [CHOOSE] Cost=5<br />
            MERGE JOIN CARTESIAN<br />
            TABLE ACCESS FULL DEPT<br />
            SORT JOIN<br />
            TABLE ACCESS FULL EMP</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>CARTESIAN关键字指出了在2个表之间做笛卡尔乘积。假如表emp有n行，dept表有m行，笛卡尔乘积的结果就是得到n * m行结果。 </p>
<p><br />
</p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/312193.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-06 16:24 <a href="http://www.blogjava.net/caizh2009/articles/312193.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle系统表 字典表</title><link>http://www.blogjava.net/caizh2009/articles/312099.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Fri, 05 Feb 2010 05:38:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/312099.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/312099.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/312099.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/312099.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/312099.html</trackback:ping><description><![CDATA[<span class="hilite1">ORACLE</span>系统表处理 <br />
<br />
1.取得指定用户的所有表名： <br />
<li><span><span>SELECT&nbsp;OWNER&nbsp;&nbsp;AS&nbsp;</span><span class="string">"对象所有者"</span><span>,OBJECT_NAME&nbsp;AS&nbsp;</span><span class="string">"表名"</span><span>,OBJECT_ID&nbsp;AS&nbsp;</span><span class="string">"对象编号"</span><span>&nbsp;from&nbsp;dba_objects&nbsp;where&nbsp;owner&nbsp;=&nbsp;</span><span class="string">'RAXNYB'</span><span>&nbsp;AND&nbsp;OBJECT_TYPE&nbsp;=&nbsp;</span><span class="string">'TABLE'</span><span>&nbsp;ORDER&nbsp;BY&nbsp;OWNER,OBJECT_TYPE; &nbsp;&nbsp;</span></span></li>
<li><span>或 &nbsp;&nbsp;</span></li>
<li><span>OWNER&nbsp;&nbsp;AS&nbsp;</span><span class="string">"对象所有者"</span><span>,TABLE_NAME&nbsp;AS&nbsp;</span><span class="string">"表名"</span><span>&nbsp;from&nbsp;DBA_TABLES&nbsp;where&nbsp;owner&nbsp;=&nbsp;</span><span class="string">'RAXNYB'</span><span>&nbsp;&nbsp;ORDER&nbsp;BY&nbsp;OWNER,TABLE_NAME;&nbsp;</span></li>
<p><span><br />
2.取得指定用户的所有视图名称：<br />
<span><span>SELECT&nbsp;OWNER&nbsp;&nbsp;AS&nbsp;</span><span class="string">"对象所有者"</span><span>,VIEW_NAME&nbsp;AS&nbsp;</span><span class="string">"视图名称"</span><span>&nbsp;from&nbsp;DBA_VIEWS&nbsp;&nbsp;where&nbsp;owner&nbsp;=&nbsp;</span><span class="string">'RAXNYB'</span><span>&nbsp;&nbsp;ORDER&nbsp;BY&nbsp;OWNER,VIEW_NAME;&nbsp;</span></span><br />
<br />
Oracle系统表查询<br />
数据字典dict总是属于Oracle用户sys的。 <br />
1、用户： <br />
　select username from dba_users; <br />
改口令 <br />
　alter user spgroup identified by spgtest; <br />
2、表空间： <br />
　select * from dba_data_files; <br />
　select * from dba_tablespaces;//表空间 <br />
　select tablespace_name,sum(bytes), sum(blocks) <br />
from dba_free_space group by tablespace_name;//空闲表空间 <br />
　select * from dba_data_files <br />
where tablespace_name='RBS';//表空间对应的数据文件 <br />
　select * from dba_segments <br />
where tablespace_name='INDEXS'; <br />
3、数据库对象： <br />
　select * from dba_objects; <br />
　CLUSTER、DATABASE LINK、FUNCTION、INDEX、LIBRARY、PACKAGE、PACKAGE BODY、 <br />
　PROCEDURE、SEQUENCE、SYNONYM、TABLE、TRIGGER、TYPE、UNDEFINED、VIEW。 <br />
4、表： <br />
　select * from dba_tables; <br />
　analyze my_table compute statistics;-&gt;dba_tables后6列 <br />
　select extent_id,bytes from dba_extents <br />
　where segment_name='CUSTOMERS' and segment_type='TABLE' <br />
　order by extent_id;//表使用的extent的信息。segment_type='ROLLBACK'查看回滚段的空间分配信息 <br />
　列信息： <br />
select distinct table_name <br />
from user_tab_columns <br />
where column_name='SO_TYPE_ID'; <br />
5、索引：　 <br />
　select * from dba_indexes;//索引，包括主键索引 <br />
　select * from dba_ind_columns;//索引列 <br />
　select i.index_name,i.uniqueness,c.column_name <br />
from user_indexes i,user_ind_columns c <br />
　where i.index_name=c.index_name <br />
　and i.table_name ='ACC_NBR';//联接使用 <br />
6、序列： <br />
　select * from dba_sequences; <br />
7、视图： <br />
　select * from dba_views; <br />
　select * from all_views; <br />
text 可用于查询视图生成的脚本 <br />
8、聚簇： <br />
　select * from dba_clusters; <br />
9、快照： <br />
　select * from dba_snapshots; <br />
快照、分区应存在相应的表空间。 <br />
10、同义词： <br />
　select * from dba_synonyms <br />
where table_owner='SPGROUP'; <br />
//if owner is PUBLIC,then the synonyms is a public synonym. <br />
　if owner is one of users,then the synonyms is a private synonym. <br />
11、数据库链： <br />
　select * from dba_db_links; <br />
在spbase下建数据库链 <br />
　create database link dbl_spnew <br />
　connect to spnew identified by spnew using 'jhhx'; <br />
　insert into acc_nbr@dbl_spnew <br />
　select * from acc_nbr where nxx_nbr='237' and line_nbr='8888'; <br />
12、触发器： <br />
　select * from dba_trigers; <br />
存储过程，函数从dba_objects查找。 <br />
其文本：select text from user_source where name='BOOK_SP_EXAMPLE'; <br />
建立出错：select * from user_errors; <br />
oracle总是将存储过程，函数等软件放在SYSTEM表空间。 <br />
13、约束： <br />
（1）约束是和表关联的，可在create table或alter table table_name add/drop/modify来建立、修改、删除约束。 <br />
可以临时禁止约束，如： <br />
　alter table book_example <br />
　disable constraint book_example_1; <br />
　alter table book_example <br />
　enable constraint book_example_1; <br />
（2）主键和外键被称为表约束，而not null和unique之类的约束被称为列约束。通常将主键和外键作为单独的命名约束放在字段列表下面，而列约束可放在列定义的同一行，这样更具有可读性。 <br />
（3）列约束可从表定义看出，即describe;表约束即主键和外键，可从dba_constraints和dba_cons_columns 查。 <br />
　select * from user_constraints <br />
　where table_name='BOOK_EXAMPLE'; <br />
　select owner,CONSTRAINT_NAME,TABLE_NAME <br />
from user_constraints <br />
where constraint_type='R' <br />
order by table_name; <br />
（4）定义约束可以无名（系统自动生成约束名）和自己定义约束名（特别是主键、外键） <br />
如：create table book_example <br />
(identifier number not null); <br />
create table book_example <br />
(identifier number constranit book_example_1 not null); <br />
14、回滚段： <br />
在所有的修改结果存入磁盘前，回滚段中保持恢复该事务所需的全部信息，必须以数据库发生的事务来相应确定其大小（DML语句才可回滚，create,drop,truncate等DDL不能回滚）。 <br />
回滚段数量=并发事务/4，但不能超过50；使每个回滚段大小足够处理一个完整的事务； <br />
　create rollback segment r05 <br />
　tablespace rbs; <br />
　create rollback segment rbs_cvt <br />
　tablespace rbs <br />
　storage(initial 1M next 500k); <br />
使回滚段在线 <br />
　alter rollback segment r04 online; <br />
用dba_extents,v$rollback_segs监测回滚段的大小和动态增长。 <br />
回滚段的区间信息 <br />
　select * from dba_extents <br />
　where segment_type='ROLLBACK' and segment_name='RB1'; <br />
回滚段的段信息,其中bytes显示目前回滚段的字节数 <br />
　select * from dba_segments <br />
where segment_type='ROLLBACK' and segment_name='RB1'; <br />
为事物指定回归段 <br />
　set transaction use rollback segment rbs_cvt <br />
针对bytes可以使用回滚段回缩。 <br />
　alter rollback segment rbs_cvt shrink; <br />
　select bytes,extents,max_extents from dba_segments <br />
where segment_type='ROLLBACK' and segment_name='RBS_CVT'; <br />
回滚段的当前状态信息： <br />
　select * from dba_rollback_segs <br />
where segment_name='RB1'; <br />
比多回滚段状态status，回滚段所属实例instance_num <br />
查优化值optimal <br />
　select n.name,s.optsize <br />
from v$rollname n,v$rollstat s <br />
　where n.usn=s.usn; <br />
回滚段中的数据 <br />
　set transaction use rollback segment rb1;/*回滚段名*/ <br />
　select n.name,s.writes <br />
from v$rollname n,v$rollstat s <br />
　where n.usn=s.usn; <br />
当事务处理完毕，再次查询$rollstat，比较writes(回滚段条目字节数)差值，可确定事务的大小。 <br />
查询回滚段中的事务 <br />
　column rr heading 'RB Segment' format a18 <br />
　column us heading 'Username' format a15 <br />
　column os heading 'Os User' format a10 <br />
　column te heading 'Terminal' format a10 <br />
　select r.name rr,nvl(s.username,'no transaction') us,s.osuser os,s.terminal te <br />
from v$lock l,v$session s,v$rollname r <br />
　where l.sid=s.sid(+) <br />
　and trunc(l.id1/65536)=R.USN <br />
　and l.type='TX' <br />
　and l.lmode=6 <br />
　order by r.name; <br />
15、作业 <br />
查询作业信息 <br />
　select job,broken,next_date,interval,what from user_jobs; <br />
　select job,broken,next_date,interval,what from dba_jobs; <br />
查询正在运行的作业 <br />
　select * from dba_jobs_running; <br />
使用包exec dbms_job.submit(:v_num,'a;',sysdate,'sysdate + (10/(24*60*60))')加入作业。间隔10秒钟 <br />
exec dbms_job.submit(:v_num,'a;',sysdate,'sysdate + (11/(24*60))')加入作业。间隔11分钟使用包exec dbms_job.remove(21)删除21号作业。 <br />
</span></p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/312099.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-05 13:38 <a href="http://www.blogjava.net/caizh2009/articles/312099.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入学习Oracle分区表及分区索引</title><link>http://www.blogjava.net/caizh2009/articles/312092.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Fri, 05 Feb 2010 04:56:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/312092.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/312092.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/312092.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/312092.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/312092.html</trackback:ping><description><![CDATA[关于分区表和分区索引(About Partitioned Tables and Indexes)对于10gR2而言，基本上可以分成几类：
<ul>
    <li>　　 Range(范围)分区
    <li>　　 Hash(哈希)分区
    <li>　　 List(列表)分区
    <li>　　 以及组合分区：Range-Hash,Range-List。 </li>
</ul>
<p>　　对于表而言(常规意义上的堆组织表)，上述分区形式都可以应用(甚至可以对某个分区指定compress属性)，只不过分区依赖列不能是lob,long之类数据类型，每个表的分区或子分区数的总数不能超过1023个。</p>
<p>　　对于索引组织表，只能够支持普通分区方式，不支持组合分区，常规表的限制对于索引组织表同样有效，除此之外呢，还有一些其实的限制，比如要求索引组织表的分区依赖列必须是主键才可以等。</p>
<p>　　注：本篇所有示例仅针对常规表，即堆组织表!</p>
<p>　　对于索引，需要区分创建的是全局索引，或本地索引：</p>
<p>　　l 全局索引(global index)：即可以分区，也可以不分区。即可以建range分区，也可以建hash分区，即可建于分区表，又可创建于非分区表上，就是说，全局索引是完全独立的，因此它也需要我们更多的维护操作。</p>
<p>　　l 本地索引(local index)：其分区形式与表的分区完全相同，依赖列相同，存储属性也相同。对于本地索引，其索引分区的维护自动进行，就是说你add/drop/split/truncate表的分区时，本地索引会自动维护其索引分区。</p>
<p>　　Oracle建议如果单个表超过2G就最好对其进行分区，对于大表创建分区的好处是显而易见的，这里不多论述why，而将重点放在when以及how。</p>
<p>　　<strong>WHEN</strong></p>
<p>　　一、When使用Range分区</p>
<p>　　Range分区呢是应用范围比较广的表分区方式，它是以列的值的范围来做为分区的划分条件，将记录存放到列值所在的range分区中，比如按照时间划分，2008年1季度的数据放到a分区，08年2季度的数据放到b分区，因此在创建的时候呢，需要你指定基于的列，以及分区的范围值，如果某些记录暂无法预测范围，可以创建maxvalue分区，所有不在指定范围内的记录都会被存储到maxvalue所在分区中，并且支持指定多列做为依赖列，后面在讲how的时候会详细谈到。</p>
<p>　　二、When使用Hash分区</p>
<p>　　通常呢，对于那些无法有效划分范围的表，可以使用hash分区，这样对于提高性能还是会有一定的帮助。hash分区会将表中的数据平均分配到你指定的几个分区中，列所在分区是依据分区列的hash值自动分配，因此你并不能控制也不知道哪条记录会被放到哪个分区中，hash分区也可以支持多个依赖列。</p>
<p>　　三、When使用List分区</p>
<p>　　List分区与range分区和hash分区都有类似之处，该分区与range分区类似的是也需要你指定列的值，但这又不同与range分区的范围式列值---其分区值必须明确指定，也不同与hash分区---通过明确指定分区值，你能控制记录存储在哪个分区。它的分区列只能有一个，而不能像range或者hash分区那样同时指定多个列做为分区依赖列，不过呢，它的单个分区对应值可以是多个。</p>
<p>　　你在分区时必须确定分区列可能存在的值，一旦插入的列值不在分区范围内，则插入/更新就会失败，因此通常建议使用list分区时，要创建一个default分区存储那些不在指定范围内的记录，类似range分区中的maxvalue分区。</p>
<p>　　四、When使用组合分区</p>
<p>　　如果某表按照某列分区之后，仍然较大，或者是一些其它的需求，还可以通过分区内再建子分区的方式将分区再分区，即组合分区的方式。</p>
<p>　　组合分区呢在10g中有两种：range-hash，range-list。注意顺序哟，根分区只能是range分区，子分区可以是hash分区或list分区。</p>
<p>　　提示：11g在组合分区功能这块有所增强，又推出了range-range,list-range,list-list,list-hash，这就相当于除hash外三种分区方式的笛卡尔形式都有了。为什么会没有hash做为根分区的组合分区形式呢，再仔细回味一下第二点，你一定能够想明白~~。</p>
<strong>一、如何创建</strong>
<p>　　如果想对某个表做分区，必须在创建表时就指定分区，我们可以对一个包含分区的表中的分区做修改，但不能直接将一个未分区的表修改成分区表(起码在10g是不行的，当然你可能会说，可以通过在线重定义的方式，但是这不是直接哟，这也是借助临时表间接实现的)。</p>
<p>　　创建表或索引的语法就不说了，大家肯定比我还熟悉，而想在建表(索引)同时指定分区也非常容易，只需要把创建分区的子句放到";"前就行啦，同时需要注意表的row movement属性，它用来控制是否允许修改列值所造成的记录移动至其它分区存储，有enable|disable两种状态，默认是disable row movement，当disable时，如果记录要被更新至其它分区，则更新语句会报错。</p>
<p>　　下面分别演示不同分区方式的表和索引的创建：</p>
<p>　　<strong>1、创建range分区</strong></p>
<p>　　语法如下，图：[range_partitioning.gif]</p>
<p>　　<img height="102" alt="" src="http://space.itpub.net/attachments/2008/05/7607759_200805070916581.gif" width="400" /></p>
<p>　　需要我们指定的有：</p>
<p>　　l column:分区依赖列(如果是多个，以逗号分隔);</p>
<p>　　l partition:分区名称;</p>
<p>　　l values less than:后跟分区范围值(如果依赖列有多个，范围对应值也应是多个，中间以逗号分隔);</p>
<p>　　l tablespace_clause:分区的存储属性，例如所在表空间等属性(可为空)，默认继承基表所在表空间的属性。</p>
<p>　　<strong>①　创建一个标准的range分区表：</strong></p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3">　　JSSWEB&gt;&nbsp;create&nbsp;table&nbsp;t_partition_range&nbsp;(id&nbsp;number,name&nbsp;varchar2(50)) <br />
            　　2&nbsp;partition&nbsp;by&nbsp;range(id)( <br />
            　　3&nbsp;partition&nbsp;t_range_p1&nbsp;values&nbsp;less&nbsp;than&nbsp;(10)&nbsp;tablespace&nbsp;tbspart01, <br />
            　　4&nbsp;partition&nbsp;t_range_p2&nbsp;values&nbsp;less&nbsp;than&nbsp;(20)&nbsp;tablespace&nbsp;tbspart02, <br />
            　　5&nbsp;partition&nbsp;t_range_p3&nbsp;values&nbsp;less&nbsp;than&nbsp;(30)&nbsp;tablespace&nbsp;tbspart03, <br />
            　　6&nbsp;partition&nbsp;t_range_pmax&nbsp;values&nbsp;less&nbsp;than&nbsp;(maxvalue)&nbsp;tablespace&nbsp;tbspart04 <br />
            　　7&nbsp;);</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　表已创建。</p>
　要查询创建分区的信息，可以通过查询user_part_tables,user_tab_partitions两个数据字典(索引分区、组织分区等信息也有对应的数据字典，后续示例会逐步提及)。
<p>　　user_part_tables：记录分区的表的信息;</p>
<p>　　user_tab_partitions：记录表的分区的信息。</p>
<p>　　例如：</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3"><font face="Verdana">JSSWEB&gt; select table_name,partitioning_type,partition_count</font>
            <p><font face="Verdana">&nbsp; 2&nbsp; From user_part_tables where table_name='T_PARTITION_RANGE';</font></p>
            <font face="Verdana">
            <p><br />
            TABLE_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PARTITI PARTITION_COUNT</p>
            <p>------------------------------ ------- ---------------</p>
            <p>T_PARTITION_RANGE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RANGE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4</p>
            <p><br />
            JSSWEB&gt; select partition_name,high_value,tablespace_name</p>
            <p>&nbsp; 2&nbsp; from user_tab_partitions where table_name='T_PARTITION_RANGE'</p>
            <p>&nbsp; 3&nbsp; order by partition_position;</p>
            <p><br />
            PARTITION_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HIGH_VALUE TABLESPACE_NAME</p>
            <p>------------------------------ ---------- --------------------</p>
            <p>T_RANGE_P1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART01</p>
            <p>T_RANGE_P2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART02</p>
            <p>T_RANGE_P3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART03</p>
            <p>T_RANGE_PMAX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MAXVALUE&nbsp;&nbsp; TBSPART04</font></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
创建global索引range分区：
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3">　　JSSWEB&gt;&nbsp;create&nbsp;index&nbsp;idx_parti_range_id&nbsp;on&nbsp;t_partition_range(id) <br />
            　　2&nbsp;global&nbsp;partition&nbsp;by&nbsp;range(id)( <br />
            　　3&nbsp;partition&nbsp;i_range_p1&nbsp;values&nbsp;less&nbsp;than&nbsp;(10)&nbsp;tablespace&nbsp;tbspart01, <br />
            　　4&nbsp;partition&nbsp;i_range_p2&nbsp;values&nbsp;less&nbsp;than&nbsp;(40)&nbsp;tablespace&nbsp;tbspart02, <br />
            　　5&nbsp;partition&nbsp;i_range_pmax&nbsp;values&nbsp;less&nbsp;than&nbsp;(maxvalue)&nbsp;tablespace&nbsp;tbspart03);</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　索引已创建。</p>
<p>　　由上例可以看出，创建global索引的分区与创建表的分区语句格式完全相同，而且其分区形式与索引所在表的分区形式没有关联关系。</p>
<p>　　注意：我们这里借助上面的表t_partition_range来演示创建range分区的global索引，并不表示range分区的表，只能创建range分区的global索引，只要你想，也可以为其创建hash分区的global索引。</p>
<p>　　查询索引的分区信息可以通过user_part_indexes、user_ind_partitions两个数据字典：</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3"><font face="Verdana">JSSWEB&gt; select index_name, partitioning_type, partition_count</font>
            <p><font face="Verdana">&nbsp; 2&nbsp;&nbsp;&nbsp; From user_part_indexes</font></p>
            <p><font face="Verdana">&nbsp; 3&nbsp;&nbsp; where index_name = 'IDX_PARTI_RANGE_ID';</font></p>
            <font face="Verdana">
            <p><br />
            INDEX_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PARTITI PARTITION_COUNT</p>
            <p>------------------------------ ------- ---------------</p>
            <p>IDX_PARTI_RANGE_ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RANGE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3</p>
            <p><br />
            JSSWEB&gt; select partition_name, high_value, tablespace_name</p>
            <p>&nbsp; 2&nbsp;&nbsp;&nbsp; from user_ind_partitions</p>
            <p>&nbsp; 3&nbsp;&nbsp; where index_name = 'IDX_PARTI_RANGE_ID'</p>
            <p>&nbsp; 4&nbsp;&nbsp; order by partition_position;</p>
            <p><br />
            PARTITION_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HIGH_VALUE TABLESPACE_NAME</p>
            <p>------------------------------ ---------- --------------------</p>
            <p>I_RANGE_P1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART01</p>
            <p>I_RANGE_P2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 40&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART02</p>
            <p>I_RANGE_PMAX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MAXVALUE&nbsp;&nbsp; TBSPART03</font></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<strong>③　Local分区索引的创建最简单</strong>，例如：
<p>　　仍然借助t_partition_range表来创建索引</p>
<p>　　--首先删除之前创建的global索引</p>
<p>　　JSSWEB&gt; drop index IDX_PARTI_RANGE_ID;</p>
<p>　　索引已删除。</p>
<p>　　JSSWEB&gt; create index IDX_PARTI_RANGE_ID on T_PARTITION_RANGE(id) local;</p>
<p>　　索引已创建。</p>
<p>　　查询相关数据字典：</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3"><font face="Verdana">JSSWEB&gt; select index_name, partitioning_type, partition_count</font>
            <p><font face="Verdana">&nbsp; 2&nbsp;&nbsp;&nbsp; From user_part_indexes</font></p>
            <p><font face="Verdana">&nbsp; 3&nbsp;&nbsp; where index_name = 'IDX_PARTI_RANGE_ID';</font></p>
            <font face="Verdana">
            <p><br />
            INDEX_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PARTITI PARTITION_COUNT</p>
            <p>------------------------------ ------- ---------------</p>
            <p>IDX_PARTI_RANGE_ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RANGE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4</p>
            <p><br />
            JSSWEB&gt; select partition_name, high_value, tablespace_name</p>
            <p>&nbsp; 2&nbsp;&nbsp;&nbsp; from user_ind_partitions</p>
            <p>&nbsp; 3&nbsp;&nbsp; where index_name = 'IDX_PARTI_RANGE_ID'</p>
            <p>&nbsp; 4&nbsp;&nbsp; order by partition_position;</p>
            <p><br />
            PARTITION_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HIGH_VALUE TABLESPACE_NAME</p>
            <p>------------------------------ ---------- --------------------</p>
            <p>T_RANGE_P1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART01</p>
            <p>T_RANGE_P2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART02</p>
            <p>T_RANGE_P3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART03</p>
            <p>T_RANGE_PMAX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MAXVALUE&nbsp;&nbsp; TBSPART04</font></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
可以看出，local索引的分区完全继承表的分区的属性，包括分区类型，分区的范围值即不需指定也不能更改，这就是前面说的：local索引的分区维护完全依赖于其索引所在表。
<p>　　不过呢分区名称，以及分区所在表空间等信息是可以自定义的，例如：</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3">　　SQL&gt;&nbsp;create&nbsp;index&nbsp;IDX_PART_RANGE_ID&nbsp;ON&nbsp;T_PARTITION_RANGE(id)&nbsp;local&nbsp;( <br />
            　　2&nbsp;partition&nbsp;i_range_p1&nbsp;tablespace&nbsp;tbspart01, <br />
            　　3&nbsp;partition&nbsp;i_range_p2&nbsp;tablespace&nbsp;tbspart01, <br />
            　　4&nbsp;partition&nbsp;i_range_p3&nbsp;tablespace&nbsp;tbspart02, <br />
            　　5&nbsp;partition&nbsp;i_range_pmax&nbsp;tablespace&nbsp;tbspart02 <br />
            　　6&nbsp;);</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　索引已创建。</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3"><font face="Verdana">SQL&gt; select index_name, partitioning_type, partition_count</font>
            <p><font face="Verdana">&nbsp; 2&nbsp;&nbsp; From user_part_indexes</font></p>
            <p><font face="Verdana">&nbsp; 3&nbsp; where index_name = 'IDX_PART_RANGE_ID';</font></p>
            <font face="Verdana">
            <p><br />
            INDEX_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PARTITI PARTITION_COUNT</p>
            <p>------------------------------ ------- ---------------</p>
            <p>IDX_PART_RANGE_ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RANGE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4</p>
            <p><br />
            SQL&gt; select partition_name, high_value, tablespace_name</p>
            <p>&nbsp; 2&nbsp;&nbsp; from user_ind_partitions</p>
            <p>&nbsp; 3&nbsp; where index_name = 'IDX_PART_RANGE_ID'</p>
            <p>&nbsp; 4&nbsp; order by partition_position;</p>
            <p><br />
            PARTITION_NAME&nbsp; HIGH_VALUE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLESPACE_NAME</p>
            <p>--------------- --------------- --------------------</p>
            <p>I_RANGE_P1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART01</p>
            <p>I_RANGE_P2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART01</p>
            <p>I_RANGE_P3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART02</p>
            <p>I_RANGE_PMAX&nbsp;&nbsp;&nbsp; MAXVALUE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART02</font></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<strong>创建hash分区</strong>
<p>　　语法如下：[图:hash_partitioning.gif]</p>
<p>　　<img height="166" alt="" src="http://space.itpub.net/attachments/2008/05/7607759_200805081300421.gif" width="400" /></p>
<p>　　语法看起来比range复杂，其实使用起来比range更简单，这里需要我们指定的有：</p>
<p>　　l column:分区依赖列(支持多个，中间以逗号分隔);</p>
<p>　　l partition:指定分区，有两种方式：</p>
<p>　　n 直接指定分区名，分区所在表空间等信息</p>
<p>　　n 只指定分区数量，和可供使用的表空间。</p>
<p>　　<strong>①　创建hash分区表</strong></p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3">　　JSSWEB&gt;&nbsp;create&nbsp;table&nbsp;t_partition_hash&nbsp;(id&nbsp;number,name&nbsp;varchar2(50)) <br />
            　　2&nbsp;partition&nbsp;by&nbsp;hash(id)( <br />
            　　3&nbsp;partition&nbsp;t_hash_p1&nbsp;tablespace&nbsp;tbspart01, <br />
            　　4&nbsp;partition&nbsp;t_hash_p2&nbsp;tablespace&nbsp;tbspart02, <br />
            　　5&nbsp;partition&nbsp;t_hash_p3&nbsp;tablespace&nbsp;tbspart03);</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　表已创建。</p>
<p>　　要实现同样效果，你还可以这样：</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3">　　JSSWEB&gt;&nbsp;create&nbsp;table&nbsp;t_partition_hash2&nbsp;(id&nbsp;number,name&nbsp;varchar2(50)) <br />
            　　2&nbsp;partition&nbsp;by&nbsp;hash(id) <br />
            　　3&nbsp;partitions&nbsp;3&nbsp;store&nbsp;in(tbspart01,tbspart02,tbspart03);</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　表已创建。</p>
这就是上面说的，直接指定分区数量和可供使用的表空间。
<p>　　提示：这里分区数量和可供使用的表空间数量之间没有直接对应关系。分区数并不一定要等于表空间数。</p>
<p>　　要查询表的分区信息，仍然是通过user_part_tables,user_tab_partitions两个数据字典，这里不再举例。</p>
<p>　　<strong>②　Global索引hash分区</strong></p>
<p>　　Hash分区索引的子句与hash分区表的创建子句完全相同，例如：</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3">　　JSSWEB&gt;&nbsp;create&nbsp;index&nbsp;idx_part_hash_id&nbsp;on&nbsp;t_partition_hash(id) <br />
            　　2&nbsp;global&nbsp;partition&nbsp;by&nbsp;hash(id) <br />
            　　3&nbsp;partitions&nbsp;3&nbsp;store&nbsp;in(tbspart01,tbspart02,tbspart03);</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　索引已创建。</p>
<p>　　查询索引的分区信息也仍是通过user_part_indexes、user_ind_partitions两个数据字典，不再举例。</p>
<p>　　<strong>③　创建Local索引</strong></p>
<p>　　在前面学习range分区时，我们已经对Local索引的特性做了非常清晰的概述，因此这里也不再举例，如有疑问，建议再仔细复习range分区的相关示例，如果还有疑问，当面问我好了:)</p>
<p>　　综上：</p>
<p>　　&#216; 对于global索引分区而言，在10g中只能支持range分区和hash分区，因此后续示例中不会再提及。</p>
<p>　　&#216; 对于local索引分区而言，其分区形式完全依赖于索引所在表的分区形式，不管从创建语法还是理解难度均无技术含量，因此后续也不再提供示例。</p>
<p>　　&#216; 注意，在创建索引时如果不显式指定global或local，则默认是global。</p>
<p>　　&#216; 注意，在创建global索引时如果不显式指定分区子句，则默认不分区(废话)。<br />
全面学习Oracle分区表及分区索引(4)-创建list分区</p>
<strong>创建list分区</strong>
<p>　　创建语法如下：[图：list_partitioning.gif]</p>
<p>　　<img height="111" alt="" src="http://space.itpub.net/attachments/2008/05/7607759_200805120936071.gif" width="400" /></p>
<p>　　<strong>需要我们指定的有：</strong></p>
<p>　　l column:分区依赖列，注意：只能是一个;</p>
<p>　　l <a class="fllink" href="http://whatis.ctocio.com.cn/searchwhatis/427/6025927.shtml" target="_bank">partition</a>:分区名称;</p>
<p>　　l literal:分区对应值，注意：每个分区可以对应多个值;</p>
<p>　　l tablespace_clause:分区的存储属性，例如所在表空间等属性(可为空)，默认继承基表所在表空间的属性。</p>
<p>　<strong>　创建list分区表示例：</strong></p>
<p>　　JSSWEB&gt; create <a class="fllink" href="http://whatis.ctocio.com.cn/searchwhatis/456/6028456.shtml" target="_bank">table</a> t_partition_list (id number,name varchar2(50))</p>
<p>　　2 partition by list(id)(</p>
<p>　　3 partition t_list_p1 values (1,2,3,4,5,6,7,8,9) <a class="fllink" href="http://whatis.ctocio.com.cn/searchwhatis/458/6028458.shtml" target="_bank">tablespace</a> tbspart01,</p>
<p>　　4 partition t_list_p2 values (10,11,12,13,14,15,16,17,18,19) tablespace tbspart02,</p>
<p>　　5 partition t_list_p3 values (20,21,22,23,24,25,26,27,28,29) tablespace tbspart03,</p>
<p>　　6 partition t_list_pd values (default) tablespace tbspart04);</p>
<p>　　表已创建。</p>
<p>　　上例能够实现与前面range分区示例相同的效果，当然针对本示例而言，list分区显然不好用啊~~~</p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/312092.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-05 12:56 <a href="http://www.blogjava.net/caizh2009/articles/312092.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle 触发器 trigger 调试</title><link>http://www.blogjava.net/caizh2009/articles/312015.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 04 Feb 2010 10:25:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/312015.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/312015.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/312015.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/312015.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/312015.html</trackback:ping><description><![CDATA[trigger不能直接使用断点调式：<br />
不过可以通过 抛出异常 确定出现问题的位置，并通过打印出相关变量的值<br />
&nbsp;RAISE_APPLICATION_ERROR(-20001, '工单状态已经为最终状态,不能变更!');<br />
&nbsp;exception <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; when others then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbms_output.put_line(:new.task_info_id||' '||sqlerrm||'&nbsp; '||sqlcode);
<img src ="http://www.blogjava.net/caizh2009/aggbug/312015.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-04 18:25 <a href="http://www.blogjava.net/caizh2009/articles/312015.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于错误:"ORA-04091: table is mutating, trigger/function may not see it"的分析(触发器操作自身表)</title><link>http://www.blogjava.net/caizh2009/articles/312014.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 04 Feb 2010 10:22:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/312014.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/312014.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/312014.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/312014.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/312014.html</trackback:ping><description><![CDATA[<p>在写trigger的时候,经常会遇到这种情况<br />
当在程序块中需要对trigger本表进行修改或查询的时候,系统会提示错误:&nbsp;&nbsp;ORA-04091: table is mutating, trigger/function may not see it<br />
<br />
关于这个错误,其实是由于对本表的操作造成的.ORACLE DB里默认在写TRIGGER的时候把本表锁死,不允许对其进行操作,也就是说这个错误是不能通过系统的手段解决的,只能改用一些其它的SQL来绕开它.<br />
<br />
<span style="background-color: yellow">对此可通过<span style="color: red">自治事物</span>解决：<br />
<br />
</p>
<div class="t_msgfont" id="message11143957">SQL&gt; CREATE TABLE T(ID NUMBER(18),MC VARCHAR2(20),DT DATE);<br />
<br />
表已创建。<br />
<br />
SQL&gt; CREATE OR REPLACE TRIGGER TR_T<br />
&nbsp;&nbsp;2&nbsp;&nbsp;AFTER DELETE ON T<br />
&nbsp;&nbsp;3&nbsp;&nbsp;FOR EACH ROW<br />
&nbsp;&nbsp;4&nbsp;&nbsp;DECLARE V_COUNT NUMBER;<br />
&nbsp;&nbsp;5&nbsp;<span style="color: red">&nbsp;--PRAGMA AUTONOMOUS_TRANSACTION;<br />
</span>&nbsp;&nbsp;6&nbsp;&nbsp;BEGIN<br />
&nbsp;&nbsp;7&nbsp; &nbsp;&nbsp;&nbsp;INSERT INTO T VALUES(:OLD.ID,:OLD.MC,SYSDATE);<br />
&nbsp;&nbsp;8&nbsp; &nbsp;&nbsp;&nbsp;COMMIT;<br />
&nbsp;&nbsp;9&nbsp;&nbsp;END TR_DEL_CABLE;<br />
10&nbsp;&nbsp;/<br />
<br />
触发器已创建<br />
<br />
SQL&gt; INSERT INTO T VALUES(1,'111111',SYSDATE);<br />
<br />
已创建 1 行。<br />
<br />
SQL&gt; INSERT INTO T VALUES(2,'222222',SYSDATE);<br />
<br />
已创建 1 行。<br />
<br />
SQL&gt; COMMIT;<br />
<br />
提交完成。<br />
<br />
SQL&gt; SELECT ID,MC,TO_CHAR(DT,'YYYYMMDD HH24:MI:SS') FROM T;<br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;ID MC&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; TO_CHAR(DT,'YYYYM<br />
---------- -------------------- -----------------<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;1 111111&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;20080802 11:07:36<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;2 222222&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;20080802 11:07:43<br />
<br />
SQL&gt; DELETE FROM T WHERE ID=1;<br />
DELETE FROM T WHERE ID=1<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;*<br />
第 1 行出现错误:<br />
ORA-04091: 表 TEST.T 发生了变化, 触发器/函数不能读它<br />
ORA-06512: 在 "TEST.TR_T", line 4<br />
ORA-04088: 触发器 'TEST.TR_T' 执行过程中出错<br />
<br />
<br />
SQL&gt; SELECT ID,MC,TO_CHAR(DT,'YYYYMMDD HH24:MI:SS') FROM T;<br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;ID MC&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; TO_CHAR(DT,'YYYYM<br />
---------- -------------------- -----------------<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;1 111111&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;20080802 11:07:36<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;2 222222&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;20080802 11:07:43<br />
<br />
SQL&gt; CREATE OR REPLACE TRIGGER TR_T<br />
&nbsp;&nbsp;2&nbsp;&nbsp;AFTER DELETE ON T<br />
&nbsp;&nbsp;3&nbsp;&nbsp;FOR EACH ROW<br />
&nbsp;&nbsp;4&nbsp;&nbsp;DECLARE V_COUNT NUMBER;<br />
&nbsp;&nbsp;5&nbsp;&nbsp;<span style="color: red">PRAGMA AUTONOMOUS_TRANSACTION;--开启自治事物</span><br />
&nbsp;&nbsp;6&nbsp;&nbsp;BEGIN<br />
&nbsp;&nbsp;7&nbsp; &nbsp;&nbsp;&nbsp;INSERT INTO T VALUES(:OLD.ID,:OLD.MC,SYSDATE);<br />
&nbsp;&nbsp;8&nbsp; &nbsp;&nbsp;&nbsp;COMMIT<span style="color: red">;--提交自治事物</span><br />
&nbsp;&nbsp;9&nbsp;&nbsp;END TR_DEL_CABLE;<br />
10&nbsp;&nbsp;/<br />
<br />
触发器已创建<br />
<br />
SQL&gt; DELETE FROM T WHERE ID=1;<br />
<br />
已删除 1 行。<br />
<br />
SQL&gt; COMMIT;<br />
<br />
提交完成。<br />
<br />
SQL&gt; SELECT ID,MC,TO_CHAR(DT,'YYYYMMDD HH24:MI:SS') FROM T;<br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;ID MC&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; TO_CHAR(DT,'YYYYM<br />
---------- -------------------- -----------------<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;2 222222&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;20080802 11:07:43<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;1 111111&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;20080802 11:08:32<br />
<br />
</div>
</span>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/312014.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-04 18:22 <a href="http://www.blogjava.net/caizh2009/articles/312014.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle java</title><link>http://www.blogjava.net/caizh2009/articles/311933.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 04 Feb 2010 04:48:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/311933.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/311933.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/311933.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/311933.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/311933.html</trackback:ping><description><![CDATA[<p>利用Java存储过程沟通SQL、XML、Java、J2EE和Web服务。 </p>
<p>存储过程（stored procedure）允许将运行于数据库层中的持久性逻辑与运行于中间层中的商务逻辑有效地分离开来。这种分离可以降低整个应用程序的复杂性，并提供其重用性、安全性、性能和可伸缩性。 </p>
<p>但是，妨碍存储过程广泛采用的一个主要障碍是不同数据库厂商使用各种专有的、且依赖于数据库的实现语言。使用基于Java的存储过程可以解决这一问题。Oracle已经实现了ANSI标准，这些标准规定了从SQL中将静态Java方法作为过程或函数进行调用的能力。这种实现被简单地称作"Java存储过程"。</p>
<p>在本文中，你将了解基于Java的存储过程如何帮助简化商务逻辑、提高其性能，并扩展数据库的功能。本文将介绍Oracle如何在数据库内启用基于Java的存储过程。还会介绍Java存储过程如何访问数据，以及如何创建基本Java存储过程。 </p>
<p>选择PL/SQL还是Java</p>
<p>在考虑Oracle存储过程时，你可能会想到PL/SQL。不过，从Oracle8i开始，Oracle已经在数据库中支持Java，从而为存储过程提供了不同于PL/SQL的开放式和可移植的方法。我可以听到"$64 000问题"："我如何在PL/SQL和Java之间做出选择？我是否应当忘记已经学习的所有PL/SQL相关知识，而变为一个Java天地的新手？" </p>
<p>两种语言都适用于数据库编程，都有自己的优点和弱点。在决定选择哪一种语言时，可以参考下面根据经验得出的通用规则： </p>
<p><br />
对于要求与SQL进行无缝集成的数据库中心来说则逻辑使用PL/SQL，从而完成对数据库对象、类型和特性的访问。 </p>
<p><br />
出于与数据库的无关性考虑时，可以选择Java作为开放式的语言来取代PL/SQL，同时也为了集成和沟通SQL、XML、J2EE和Web服务等各个领域。 <br />
OralceJVM使得Java可以运行在数据库中</p>
<p>从Oracle8i版本1（Oralce8.1.5）开始，Oracle便提供紧密集成的Java虚拟机（JVM），JVM支持Oralce的数据库会话期结构。任何数据库对话期都可以在第一Java代码调用时启动一个虚拟上专用的JVM，后续的用户可以使用这一已经存在的支持Java的会话期。事实上，所有会话共享同一JVM代码并保持"仅静态"的私有状态，而垃圾则收集在单个对话期空间内，从而为各个Java对话期提供了和SQL操作相同的对话期隔离和数据完整性能力。这里，不需要为了数据完整性而进行单独的Java支持的过程。这一基于对话期的结构提供了较小的内存占用率，并使OracleJVM具有与Oracle数据库一样的线性SMP可伸缩性。 </p>
<p>创建Java存储过程 </p>
<p>要将Java方法转换为Java存储过程需要几个步骤，包括：用loadjava实用程序将Java类加载到数据库中，利用调用规范（Call Spec）发布Java方法，将Java方法、参数类型和返回类型映射到其SQL的对应部分。下面部分说明如何完成这些步骤。 </p>
<p>我将使用一个简单的Hello类，它有一个方法Hello.world()，返回字符串"Hello world"：</p>
<p><br />
public class Hello { public static String world () { return "Hello world"; } } <br />
Loadjava 实用程序</p>
<p>Loadjava是加载Java源文件、Java类文件和Java资源文件的实用程序，它可以用来验证字节码，并将Java类和JAR文件布置到数据库中。它既可以通过命令行调用，也可以通过包含于DBMS_JAVA类中的loadjava()方法调用。为了加载我们的Hello.class示例，输入：</p>
<p><br />
loadjava -user scott/tiger Hello.class </p>
<p>从Oracle9i版本2开始，loadjava允许通过为包含在被处理的类中的方法创建相应的Call Specs来自动将Java类发布为存储过程。Oracle为开发、测试、调试和布置Java存储过程提供了Oracle9i JDeveloper。</p>
<p>The Resolver Spec </p>
<p>基于JDK的JVM在列于CLASSPATH中的目录中查找类引用，并对其进行解析。因为Oracle数据库类存在于数据库模式中，所以OracleJVM利用数据库解析器（resolver）通过列于Resolver Spec中的模式查找并解析类引用。与CLASSPATH不同（CLASSPATH可以应用于所有的类），Resover Spec根据每类的情况进行应用。缺省解析器首先在加载类的模式中搜寻类，然后在公共同义词（public synonyms）中搜索。 </p>
<p><br />
&nbsp;loadjava -resolve &lt;myclass&gt; <br />
你可能需要指定不同的解析器，也可以在使用loadjava时强制进行解析，从而在布置时确定可能在以后运行时发生的任何问题。 </p>
<p><br />
loadjava -resolve -resolver "((* SCOTT) (foo/bar/* OTHERS) (* PUBLIC))" <br />
Call Spec和存储过程调用 </p>
<p>为了从SQL中调用Java方法（以及从PL/SQl和JDBC中调用），必须首先通过Call Spec发布公共静态方法，它为SQL定义方法采用的参数以及返回的SQL类型。</p>
<p>在我们的例子中，我们将利用SQL＊Plus连接到数据库，并为Hello.world()定义一个顶级Call Spec： </p>
<p><br />
SQL&gt; connect scott/tiger SQL&gt; create or replace function helloworld return VARCHAR2 as language java name 'Hello.world () return java.lang.String'; / Function created. <br />
可以像下面这样调用Java存储过程：</p>
<p><br />
SQL&gt; variable myString varchar2[20]; SQL&gt; call helloworld() into :myString; Call completed. SQL&gt; print myString; MYSTRING --------------------- Hello world <br />
Java存储过程可以通过其Call Spec从以下各项中进行调用：SQL DML语句（INSERT, UPDATE、DELETE、SELECT、CALL、EXPLAIN PLAN、LOCK TABLE和MERGE）、PL/SQL块、子程序、程序包以及数据库触发器。Call Spec的美妙之处在于存储过程实现可以从PL/SQL转换为Java，反之亦可，这一点对于请求者是透明的。</p>
<p>Call Spec从实现语言中（PL/SQL或Java）中抽象出调用界面，因而使之能够在原有应用程序和新的基于Java／J2EE的应用程序之间共享商务逻辑。但是，在从Java客户程序调用在数据库驻留的Java类时，你可能不希望通过PL/SQL包装器(wrapper)。在以后的版本中，Oracle计划提供一种机制，它可以使开发人员略过Call Spec。</p>
<p>高级数据访问控制 </p>
<p>Java存储过程可用于控制和限制对Oracle数据的访问，其方法是只允许用户通过存储过程管理数据，而存储过程在其调用者的权限内执行，而不能对表本身进行访问。例如，你可以在特定时间内禁止更新数据，或者使管理者只具有查询工资数据的权利，而不能进行更新，或者记录所有的访问并通知某一安全机构。</p>
<p>原有应用程序与J2EE应用程序之间的数据逻辑共享</p>
<p>因为原有应用程序与J2EE应用程序都通过Call Spec调用存储过程，所以J2EE和非J2EE应用程序可以共享相同的数据逻辑。由于有了Call Spec，所以不用考虑所用的是何种实现语言（无论是PL/SQL还是Java），该数据逻辑都可以共享。 </p>
<p>为BMP实体Bean自动生成主关键字</p>
<p>在对EJB实体bean应用BMP时，一个bean实例可以由自动生成的与新插入的数据相关联的主关键字惟一确定，它是ejbCreate()的返回值。可以利用一个插入相应数据的存储过程在一个数据库操作中检索ejbCeater()中的该值，并检索或计算主关键字。作为另一种方法，也可以利用JDBC3.0的RETURN_GENERATED_KEYS特性，以一个SQL语句插入该数据并检索相应的关键字（或ROWID）。但是，存储过程方法在各个JDBC驱动器版本和数据库之间更具可移植性。</p>
<p>可以用以下三个步骤实现这一模式：</p>
&gt;<br />
创建一个Java存储过程，在公共GenPk类中定义一个公共静态Java方法insertAccount()。此方法将插入数据、计算惟一的关键字（通过发出一个序列号），并返回计算出的关键字作为主关键字。
<p>&nbsp;</p>
<p><br />
定义Call Spec </p>
<p><br />
CREATE OR REPLACE PROCEDURE insertAccount(owner IN varchar, bal IN number, newid OUT number) AS LANGUAGE JAVA NAME 'GenPK.insertAccount( java.lang.String [])'; / </p>
<p><br />
在ejbCreate()内调用存储过程 </p>
<p><br />
Public AccountPK ejbCreate(String ownerName, int balance) throws CreateException { try { CallableStatement call = conn.prepareCall{ "{call insertAccount(?, ?, ?)}"}; return new AccountPK(accountID); } } <br />
为CMP实体Bean定制主关键字查找器 </p>
<p>查找器方法（Finder methods）用于检索已存在的EJB实体bean实例。主关键字查找器使你能够检索惟一标识的EJB实例。对于CMP实体bean，EJB容器根据声明描述，自动生成主关键字查找器findByPrimaryKey()方法。但是，在某些情况下，可能需要更多的控制，例如可能需要专门的查找器，如findByStoredProcKey()。在这些情况下，你可以结合使用Java存储过程和对象关系框架（如Oracle9i应用服务器[Oracle9iAS] TopLink）来实现定制的主关键字查找器方法。在将EJB查找器定义为REDIRECT或NAMED查找器后，TopLink将生成一个SQL查询用于检索bean实例。</p>
<p>数据驱动的EJB调用 </p>
<p>在数据驱动体系结构中，商务逻辑调用可以作为数据库操作（如插入、更新或删除）的结果来触发。实现该数据逻辑的Java存储过程可以被声明为数据库触发器，用以调用运行于中间层J2EE应用服务器的EJB。EJB的调用既可以采用J2EE1.3兼容的服务器通过Interoperable Inter-ORB Protocol（IIOP）标准远程方法调用（remote method invocation，RMI）实现，也可以通过销售商特定的传输协议（如Oracle9iAS/Oc4J的ORMI，或者通过BEA WebLogic的T3）用RMI来实现。每个应用服务器提供商在提供基于IIOP的RMI，以提供互操作性的同时，都有其自己优化的协议。Oracle9iAS同时支持基于IIOP的RMI调用和基于ORMI协议的RMI调用。 </p>
<p>数据驱动的消息传送 </p>
<p>Oracle9i数据库嵌入了Advanced Queuing（AQ，高级排队），它是一种集成的、稳定、可靠、安全、可扩展和事务处理式的消息排队框架。Oracle通过标准的Java消息传送系统（Java Messaging System，JMS）API为Java开发人员提供AQ功能。Java存储过程可以通过JMS接口调用AQ操作，从而能够实现快速、在会话期内、可扩展的、数据驱动的消息传送。 </p>
<p>Java存储过程可以利用JMS调用AQ操作。可以用以下4个步骤实现这一模式：</p>
<p><br />
创建并启动JMS Queue（为此，可以将以下一些操作嵌入SQL脚本内）： </p>
<p><br />
execute dbms_aqadm.create_queue_table(queue_table =&gt; 'queue1', queue_payload_type =&gt; 'SYS.AQ$_JMS_TEXT_MESSAGE', comment =&gt; 'a test queue', multiple_consumers =&gt; false, compatible =&gt; '8.1.0'); execute dbms_aqadm.create_queue( queue_name =&gt; 'queue1', queue_table =&gt; 'queue1' ); execute dbms_aqadm.start_queue(queue_name =&gt; 'queue1'); </p>
<p><br />
创建Java存储过程（代码摘录如下）： </p>
<p><br />
public static void runTest(String msgBody) { try { // get database connection ora_drv = new OracleDriver(); db_conn = ora_drv.defaultConnection(); // setup sender (cf online code sample) .. // create message s_msg = s_session.createTextMessage(msgBody); // send message sender.send(s_msg); s_session.commit(); // receive message r_msg = (TextMessage) receiver.receive(); r_session.commit(); // output message text String body = r_msg.getText(); System.out.println("message was '"+body+"'"); ..} } </p>
<p><br />
创建Call Spec： </p>
<p><br />
create or replace procedure jmsproc (t1 IN VARCHAR) as language java name 'jmsSample.main (java.lang.String[])'; / </p>
<p><br />
调用存储过程： </p>
<p><br />
call jmsproc('hello'); <br />
数据库辅助的Web发布（缓冲失效）</p>
<p>各应用程序结构必须面对的一个共同问题是如果可靠地将数据库信息进行缓存，以提高整个系统的性能。JCACHE是一种即将公布的标准规范（JSR 107），它可以解决这一问题。它说明了一种对Java对象临时在内存中进行缓存的方法，包括对象的创建、共享访问、假脱机（spooling）、失效、各JVM的一致性等。它可被用于缓存JSP内最经常读取的数据，如产品目录和价格列表。利用JCACHE，多数查询的反应时间会因为有缓存的数据而加快（内部测试表明反应时间大约快15倍）。 </p>
<p>为了跟踪原始数据的所有变化，并刷新已缓存的数据，Java存储过程会作为一个触发器被附加在一个表上。这个表的任何变化都会自动调用该存储过程，后者再调出一个已定义的JSP使JCACHE对象失效，该对象将其状态映射到该数据库表。在失效时，紧跟其后的查询将强制缓存器根据数据库的数据进行更新。 下面的步骤 <br />
阅读关于Java存储过程的更多信息<br />
本文摘自白皮书"释放Java存储过程的能量（Unleash the Power of Java Stored Procedures）"，可以在以下位置找到该白皮书：<br />
otn.oracle.com/tech/java/java_db/pdf/<br />
OW_30820_JAVA_STORED_PROC_paper.PDF </p>
<p>Oracle9i数据库第2版中的新PL/SQL特性<br />
otn.oracle.com/tech/pl_sql/pdf/<br />
Paper_30720_Doc.pdf </p>
<p>Resolver Spec<br />
otn.oracle.com/docs/products/oracle9i/<br />
doc_library/release2/java.920/a96659.pdf </p>
<p>OracleJVM and Java 2 Security<br />
otn.oracle.com/docs/products/oracle9i/<br />
doc_library/release2/java.920/a96656.pdf </p>
<p>下载代码<br />
练习本文中的代码示例： <br />
otn.oracle.com/sample_code/tech/<br />
java/jsp/Oracle9iJSPSamples.html </p>
<p>了解作为Web服务的存储过程<br />
otn.oracle.com/tech/webservices <br />
&nbsp;</p>
<p><br />
扩展数据库的功能 </p>
<p>在数据库中直接运行Java代码的一个妙处就在于要实现新的功能，只需要简单地加载代码或库，并利用Call Spec制作可用于SQL、PL/SQL、Java、J2EE和非Java API的进入点（公共静态方法）。Oracle9i数据库用户可以很容易地扩展数据库</p>
功能。Oracle自己利用这种能力来获得新的应用程序和工具包，如XML Developer Kits（XDKs）。
<p>&nbsp;</p>
<p>沟通SQL、PL/SQL、Java、J2EE、.NET和XML </p>
<p>Oracle XDK是用Java编写的，并将其公共方法可用作Java存储过程，从而扩展了数据库的XML可编程能力。SQL、PL/SQL、Java、J2EE和非Java（.NET）商务逻辑都能够访问XML分析器、XSLT处理器、XPath引擎和XML SQL Utility（XSU）。 </p>
<p>XML分析器可以通过xmlparser和xmldom包进行访问。XSU是一种Java实用程序，它可以由SQL查询结果或JDBC ResultSet生成XML文档，并将XML文档中的数据写入数据库表或视图中。利用XSU，XML输出可以输出为文本、Dom树或DTS。通过dbms_xmlquery和dbms_xmlsave包，XSU即可用于PL/SQL。 </p>
<p>结论</p>
<p>Oracle数据库与Java VM的集成可以创建可移植、功能强大和与数据库无关的数据逻辑和持续性逻辑（persistence logic）。运行于中间层的商务逻辑和运行于数据库层的数据逻辑之间的分离提高了应用程序的可扩展性、灵活性和可维护性。</p>
<p<p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/311933.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-04 12:48 <a href="http://www.blogjava.net/caizh2009/articles/311933.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle 调用 java简单示例</title><link>http://www.blogjava.net/caizh2009/articles/311926.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 04 Feb 2010 04:39:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/311926.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/311926.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/311926.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/311926.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/311926.html</trackback:ping><description><![CDATA[<div id="hunter_recommended" style="border-right: #ccc 1px solid; padding-right: 4px; border-top: #ccc 1px solid; padding-left: 4px; background: #fff; float: left; margin-bottom: 10px; padding-bottom: 4px; border-left: #ccc 1px solid; width: 557px; padding-top: 4px; border-bottom: #ccc 1px solid"><span id="hunters_nav" style="margin-right: 5px"><a style="border-right: #ccc 1px solid; padding-right: 3px; border-top: #ccc 1px solid; padding-left: 3px; padding-bottom: 0px; border-left: #ccc 1px solid; padding-top: 0px; border-bottom: #ccc 1px solid; text-decoration: none; size: 13px" onclick="hunter_id <= 0 ? hunter_id = hunters.length - 1 : hunter_id--; $('hunters').update(hunters[hunter_id]);return false;" href="http://www.javaeye.com/topic/248953#">&lt;</a> <a style="border-right: #ccc 1px solid; padding-right: 3px; border-top: #ccc 1px solid; padding-left: 3px; padding-bottom: 0px; border-left: #ccc 1px solid; padding-top: 0px; border-bottom: #ccc 1px solid; text-decoration: none; size: 13px" onclick="hunter_id >= hunters.length - 1 ? hunter_id = 0 : hunter_id++; $('hunters').update(hunters[hunter_id]);return false;" href="http://www.javaeye.com/topic/248953#">&gt;</a> </span>猎头职位: <span id="hunters"><script type="text/javascript">document.write(hunters[hunter_id]);</script><a style="color: #000" href="http://www.javaeye.com/jobs/522" target="_blank"><span style="font-weight: bold">上海: </span>上海:25---40万年薪诚聘技术经理</a></span> </div>
<div style="position: relative" _madepositioned="true">前提是数据库上需要安装java虚拟机(JVM),使用下面的语句查看 </div>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/248953#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>select&nbsp;*&nbsp;from&nbsp;dba_registry&nbsp;where&nbsp;comp_id&nbsp;=&nbsp;</span><span class="string">'JAVAVM'</span><span>&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">select * from dba_registry where comp_id = 'JAVAVM'</pre>
<br />
为空,则未安装,请执行 $ORACLE_HOME/javavm/install/initjvm.sql安装. <br />
创建函数 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/248953#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>create&nbsp;or&nbsp;replace&nbsp;function&nbsp;fn_oraclecall(mArea&nbsp;in&nbsp;VARCHAR2,mDevID&nbsp;in&nbsp;Number,mPORT&nbsp;in&nbsp;Number) &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">return</span><span>&nbsp;varchar2 &nbsp;&nbsp;</span></span></li>
    <li><span>as &nbsp;&nbsp;</span></li>
    <li><span>language&nbsp;java&nbsp;name&nbsp;</span><span class="string">'Caller.call(java.lang.String,Integer,Integer)&nbsp;return&nbsp;java.lang.String'</span><span>;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">create or replace function fn_oraclecall(mArea in VARCHAR2,mDevID in Number,mPORT in Number)
return varchar2
as
language java name 'Caller.call(java.lang.String,Integer,Integer) return java.lang.String';</pre>
<br />
<br />
创建存储过程 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/248953#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>create&nbsp;or&nbsp;replace&nbsp;procedure&nbsp;CHK_SETCAB_NUM &nbsp;&nbsp;</span></span></li>
    <li><span>(mArea&nbsp;in&nbsp;VARCHAR2,mDevID&nbsp;in&nbsp;Number,mPORT&nbsp;in&nbsp;Number,v_out&nbsp;out&nbsp;varchar2)&nbsp;is &nbsp;&nbsp;</span></li>
    <li><span>begin &nbsp;&nbsp;</span></li>
    <li><span>v_out&nbsp;:=&nbsp;fn_oraclecall(mArea,mDevID,mPORT); &nbsp;&nbsp;</span></li>
    <li><span>end&nbsp;CHK_SETCAB_NUM;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">create or replace procedure CHK_SETCAB_NUM
(mArea in VARCHAR2,mDevID in Number,mPORT in Number,v_out out varchar2) is
begin
v_out := fn_oraclecall(mArea,mDevID,mPORT);
end CHK_SETCAB_NUM;</pre>
<br />
<br />
loadjava <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/248953#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>loadjava&nbsp;-u&nbsp;sys/sys</span><span class="annotation">@sid</span><span>&nbsp;&nbsp;-oci8&nbsp;-verbose&nbsp;-grant&nbsp;user&nbsp;-synonym&nbsp;-resolve&nbsp;-schema&nbsp;user&nbsp;D:\Caller.jar &nbsp;&nbsp;</span></span></li>
    <li><span>--这里也可以是</span><span class="keyword">class</span><span>文件,注意兼容oracle的jre版本&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">loadjava -u sys/sys@sid  -oci8 -verbose -grant user -synonym -resolve -schema user D:\Caller.jar
--这里也可以是class文件,注意兼容oracle的jre版本
</pre>
<br />
<br />
注意编写的java文件里,即Caller.java的call()方法,需要是staic <br />
<img src ="http://www.blogjava.net/caizh2009/aggbug/311926.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-04 12:39 <a href="http://www.blogjava.net/caizh2009/articles/311926.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle调用java</title><link>http://www.blogjava.net/caizh2009/articles/311923.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 04 Feb 2010 04:36:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/311923.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/311923.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/311923.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/311923.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/311923.html</trackback:ping><description><![CDATA[前提是数据库上需要安装java虚拟机(JVM),使用下面的语句查看 <br />
<span><span>select&nbsp;*&nbsp;from&nbsp;dba_registry&nbsp;where&nbsp;comp_id&nbsp;=&nbsp;</span><span class="string">'JAVAVM'</span><span>&nbsp;&nbsp;</span></span><br />
为空,则未安装,请执行 $ORACLE_HOME/javavm/install/initjvm.sql安装. <br />
<p>一、如何创建java存储过程？<br />
通常有三种方法来创建java存储过程。</p>
<p>1. 使用oracle的sql语句来创建：</p>
<p>e.g. 使用create or replace and compile java source named "&lt;name&gt;" as<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 后边跟上java源程序。要求类的方法必须是public static的，才能用于存储过程。</p>
<p>SQL&gt; create or replace and compile java source named "javademo1"<br />
&nbsp; 2&nbsp; as<br />
&nbsp; 3&nbsp; import java.sql.*;<br />
&nbsp; 4&nbsp; public class JavaDemo1<br />
&nbsp; 5&nbsp; {<br />
&nbsp; 6&nbsp; public static void main(String[] argv)<br />
&nbsp; 7&nbsp; {<br />
&nbsp; 8&nbsp; System.out.println("hello, java demo1");<br />
&nbsp; 9&nbsp; }<br />
&nbsp;10&nbsp; }<br />
&nbsp;11&nbsp; /</p>
<p>Java 已创建。</p>
<p>SQL&gt; show errors java source "javademo1"<br />
没有错误。</p>
<p>SQL&gt; create or replace procedure javademo1<br />
&nbsp; 2&nbsp; as<br />
&nbsp; 3&nbsp; language java name ''JavaDemo1.main(java.lang.String[])'';<br />
&nbsp; 4&nbsp; /</p>
<p>过程已创建。</p>
<p>SQL&gt; set serveroutput on<br />
SQL&gt; call javademo1();</p>
<p>调用完成。</p>
<p>SQL&gt; call dbms_java.set_output(5000);</p>
<p>调用完成。</p>
<p>SQL&gt; call javademo1();<br />
hello, java demo1</p>
<p>调用完成。</p>
<p>SQL&gt; call javademo1();<br />
hello, java demo1<br />
调用完成。<br />
2. 使用外部class文件来装载创建<br />
e.g. 这里既然用到了外部文件，必然要将class文件放到oracle Server的某一目录下边。</p>
<p><br />
public class OracleJavaProc<br />
{<br />
&nbsp;&nbsp;&nbsp; public static void main(String[] argv)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("It''s a Java Oracle procedure.");<br />
&nbsp;&nbsp;&nbsp; }<br />
}</p>
<p><br />
SQL&gt; grant create any directory to scott;</p>
<p>授权成功。</p>
<p>SQL&gt; conn scott/tiger@iihero.oracledb<br />
已连接。<br />
SQL&gt; create or&nbsp;&nbsp; replace&nbsp;&nbsp; directory&nbsp;&nbsp; test_dir&nbsp;&nbsp; as&nbsp; ''d:\oracle'';</p>
<p>目录已创建。</p>
<p>SQL&gt; create or replace java class using bfile(test_dir, ''OracleJavaProc.CLASS'')<br />
&nbsp; 2&nbsp; /</p>
<p>Java 已创建。</p>
<p>SQL&gt; create or replace procedure testjavaproc as language java name ''OracleJavaProc.main(java.lang.String[])'';<br />
&nbsp; 2&nbsp; /</p>
<p>过程已创建。</p>
<p>SQL&gt; call testjavaproc();</p>
<p>调用完成。</p>
<p>SQL&gt; execute testjavaproc;</p>
<p>PL/SQL 过程已成功完成。</p>
<p>SQL&gt; set serveroutput on size 5000<br />
SQL&gt; call dbms_java.set_output(5000);</p>
<p>调用完成。</p>
<p>SQL&gt; execute testjavaproc;<br />
It''s a Java Oracle procedure.<br />
3. 我推荐的一种方法，直接使用loadjava命令远程装载并创建。<br />
&nbsp;&nbsp;&nbsp; 先创建一个类, e.g.</p>
<p><br />
import java.sql.*;<br />
import oracle.jdbc.*;</p>
<p>public class OracleJavaProc ...{</p>
<p>&nbsp;&nbsp; //Add a salgrade to the database.<br />
&nbsp;&nbsp; public static void addSalGrade(int grade, int losal, int hisal) ...{</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Creating new salgrade for EMPLOYEE...");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try ...{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Connection conn =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DriverManager.getConnection("jdbc:default:connection:");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String sql =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "INSERT INTO salgrade " +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "(GRADE,LOSAL,HISAL) " +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "VALUES(?,?,?)";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PreparedStatement pstmt = conn.prepareStatement(sql);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.setInt(1,grade);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.setInt(2,losal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.setInt(3,hisal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.executeUpdate();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(SQLException e) ...{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.err.println("ERROR! Adding Salgrade: " <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + e.getMessage());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; }<br />
}<br />
使用loadjava命令将其装载到服务器端并编译：</p>
<p><br />
D:eclipse3.1workspacedbtest&gt;loadjava -u scott/tiger@iihero.oracledb -v -resolve Or<br />
acleJavaProc.java<br />
arguments: ''-u'' ''scott/tiger@iihero.oracledb ''-v'' ''-resolve'' ''OracleJavaProc.java''<br />
creating : source OracleJavaProc<br />
loading&nbsp; : source OracleJavaProc<br />
resolving: source OracleJavaProc<br />
查询一下状态：</p>
<p><br />
连接到:<br />
Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production<br />
With the Partitioning, OLAP and Oracle Data Mining options<br />
JServer Release 9.2.0.1.0 - Production</p>
<p>SQL&gt; SELECT object_name, object_type, status FROM user_objects WHERE object_type LIKE ''JAVA%'';</p>
<p>OBJECT_NAME<br />
--------------------------------------------------------------------------------</p>
<p>OBJECT_TYPE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; STATUS<br />
------------------------------------ --------------<br />
OracleJavaProc<br />
JAVA CLASS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VALID</p>
<p>OracleJavaProc<br />
JAVA SOURCE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VALID<br />
测试一下存储过程：</p>
<p><br />
SQL&gt; create or replace procedure add_salgrade(id number, losal number, hisal num<br />
ber) as language java name ''OracleJavaProc.addSalGrade(int, int, int)'';<br />
&nbsp; 2&nbsp; /</p>
<p>过程已创建。</p>
<p>SQL&gt; set serveroutput on size 2000<br />
SQL&gt; call dbms_java.set_output(2000);</p>
<p>调用完成。</p>
<p>SQL&gt; execute add_salgrade(6, 10000, 15000);<br />
Creating new salgrade for EMPLOYEE...</p>
<p>PL/SQL 过程已成功完成。</p>
<p>SQL&gt; select * from salgrade where grade=6;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; GRADE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOSAL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HISAL<br />
---------- ---------- ----------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 15000<br />
&nbsp;</p>
<p>二、如何更新你已经编写的java存储过程？&nbsp; </p>
<p>假如要往类OracleJavaProc里添加一个存储过程方法，如何开发？<br />
正确的步骤应该是先dropjava, 改程序，再loadjava。</p>
<p>e.g.修改OracleJavaProc类内容如下：</p>
<p><br />
import java.sql.*;<br />
import oracle.jdbc.*;</p>
<p>public class OracleJavaProc ...{</p>
<p>&nbsp;&nbsp; // Add a salgrade to the database.<br />
&nbsp;&nbsp; public static void addSalGrade(int grade, int losal, int hisal) ...{</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Creating new salgrade for EMPLOYEE...");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try ...{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Connection conn =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DriverManager.getConnection("jdbc:default:connection:");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String sql =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "INSERT INTO salgrade " +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "(GRADE,LOSAL,HISAL) " +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "VALUES(?,?,?)";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PreparedStatement pstmt = conn.prepareStatement(sql);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.setInt(1,grade);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.setInt(2,losal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.setInt(3,hisal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.executeUpdate();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(SQLException e) ...{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.err.println("ERROR! Adding Salgrade: " <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + e.getMessage());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; public static int getHiSal(int grade)<br />
&nbsp;&nbsp; ...{<br />
&nbsp;&nbsp;&nbsp; try ...{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Connection conn =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DriverManager.getConnection("jdbc:default:connection:");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String sql = "SELECT hisal FROM salgrade WHERE grade = ?";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PreparedStatement pstmt = conn.prepareStatement(sql);pstmt.setInt(1, grade);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ResultSet rset = pstmt.executeQuery();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int res = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (rset.next())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; res = rset.getInt(1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rset.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return res;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; catch (SQLException e) <br />
&nbsp;&nbsp;&nbsp; ...{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.err.println("ERROR! Querying Salgrade: " <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + e.getMessage());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br />
&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
}</p>
<p>如何更新呢？</p>
<p><br />
D:eclipse3.1workspacedbtest&gt;dropjava -u scott -v OracleJavaProc</p>
<p>D:/tiger@iihero.oracledbeclipse3.1workspacedbtest&gt;loadjava -u scott -v -resolve Or<br />
acleJavaProc/tiger@iihero.oracledb.java<br />
arguments: ''-u'' ''scott/tiger@iihero.oracledb'' ''-v'' ''-resolve'' ''OracleJavaProc.java''<br />
creating : source OracleJavaProc<br />
loading&nbsp; : source OracleJavaProc<br />
resolving: source OracleJavaProc<br />
后边的应用示例：</p>
<p><br />
SQL&gt; create or replace function query_hisal(grade number) return number as langu<br />
age java name ''OracleJavaProc.getHiSal(int) return int'';<br />
&nbsp; 2&nbsp; /</p>
<p>函数已创建。</p>
<p>SQL&gt; set serveroutput on size 2000<br />
SQL&gt; call dbms_java.set_output(2000);</p>
<p>调用完成。<br />
SQL&gt; select query_hisal(5) from dual;</p>
<p>QUERY_HISAL(5)<br />
--------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9999<br />
全文完！</p>
<p>&nbsp;</p>
<p>本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/thinker28754/archive/2009/03/07/3962989.aspx</p>
<br />
<img src ="http://www.blogjava.net/caizh2009/aggbug/311923.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-04 12:36 <a href="http://www.blogjava.net/caizh2009/articles/311923.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>有效创建oracle dblink 的两种方式</title><link>http://www.blogjava.net/caizh2009/articles/308439.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Wed, 06 Jan 2010 06:32:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/308439.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/308439.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/308439.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/308439.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/308439.html</trackback:ping><description><![CDATA[两台不同的数据库服务器，从一台数据库服务器的一个用户读取另一台数据库服务器下的某个用户的数据，这个时候可以使用dblink。
<p>　　其实dblink和数据库中的view差不多，建dblink的时候需要知道待读取数据库的ip地址，ssid以及数据库用户名和密码。</p>
<p>　　创建可以采用两种方式：</p>
<p>　　1、已经配置本地服务</p>
<p>&nbsp;</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3">以下是引用片段：<br />
            　　create&nbsp;public&nbsp;database <br />
            　　link&nbsp;fwq12&nbsp;connect&nbsp;to&nbsp;fzept <br />
            　　identified&nbsp;by&nbsp;neu&nbsp;using&nbsp;'fjept'</td>
        </tr>
    </tbody>
</table>
　　CREATE DATABASE LINK数据库链接名CONNECT TO 用户名 IDENTIFIED BY 密码 USING &#8216;本地配置的数据的实例名&#8217;;</p>
<p>　　2、未配置本地服务</p>
<p>　　<img height="16" alt="有效创建oracle dblink 的两种方式图片1" src="http://www.abcdown.net/uploadImages/2007-8-28/2007828927317346.gif" width="11" align="top" />
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3">以下是引用片段：<br />
            create&nbsp;database&nbsp;link&nbsp;linkfwq <br />
            　　&nbsp;connect&nbsp;to&nbsp;fzept&nbsp;identified&nbsp;by&nbsp;neu <br />
            　　&nbsp;using&nbsp;'(DESCRIPTION&nbsp;= <br />
            　　&nbsp;(ADDRESS_LIST&nbsp;= <br />
            　　&nbsp;(ADDRESS&nbsp;=&nbsp;(PROTOCOL&nbsp;=&nbsp;TCP)(HOST&nbsp;=&nbsp;10.142.202.12)(PORT&nbsp;=&nbsp;1521)) <br />
            　　&nbsp;) <br />
            　　&nbsp;(CONNECT_DATA&nbsp;= <br />
            　　&nbsp;(SERVICE_NAME&nbsp;=&nbsp;fjept) <br />
            　　&nbsp;) <br />
            　　&nbsp;)';</td>
        </tr>
    </tbody>
</table>
　　host=数据库的ip地址，service_name=数据库的ssid。</p>
<p>　　其实两种方法配置dblink是差不多的，我个人感觉还是第二种方法比较好，这样不受本地服务的影响。</p>
<p>　　数据库连接字符串可以用NET8 EASY CONFIG或者直接修改TNSNAMES.ORA里定义.</p>
<p>　　数据库参数global_name=true时要求数据库链接名称跟远端数据库名称一样</p>
<p>　　数据库全局名称可以用以下命令查出</p>
<p>　　SELECT * FROM GLOBAL_NAME;</p>
<p>　　查询远端数据库里的表</p>
<p>　　SELECT &#8230;&#8230; FROM 表名@数据库链接名;</p>
<p>　　查询、删除和插入数据和操作本地的数据库是一样的，只不过表名需要写成&#8220;表名@dblink服务器&#8221;而已。</p>
<p>　　附带说下同义词创建:</p>
<p>　　CREATE SYNONYM同义词名FOR 表名;</p>
<p>　　CREATE SYNONYM同义词名FOR 表名@数据库链接名;</p>
<p>　　删除dblink：DROP PUBLIC DATABASE LINK linkfwq。</p>
<p>　　如果创建全局dblink，必须使用systm或sys用户，在database前加public。</p>
<p>　　参考资料:</p>
<p>　　<a href="http://download-west.oracle.com/docs/cd/B19306_01/server.102/b14231/ds_admin.htm#i1008271">http://download-west.oracle.com/docs/cd/B19306_01/server.102/b14231/ds_admin.htm#i1008271</a> </p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/308439.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-01-06 14:32 <a href="http://www.blogjava.net/caizh2009/articles/308439.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>分区表PARTITION table </title><link>http://www.blogjava.net/caizh2009/articles/306536.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Fri, 18 Dec 2009 05:28:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/306536.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/306536.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/306536.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/306536.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/306536.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1.1 分区表PARTITION table在ORACLE里如果遇到特别大的表，可以使用分区的表来改变其应用程序的性能。1.1.1 分区表的建立： 某公司的每年产生巨大的销售记录，DBA向公司建议每季度的数据放在一个分区内，以下示范的是该公司1999年的数据(假设每月产生30M的数据)，操作如下： 范围分区表：CREATE TABLE sales (invoice_no N...&nbsp;&nbsp;<a href='http://www.blogjava.net/caizh2009/articles/306536.html'>阅读全文</a><img src ="http://www.blogjava.net/caizh2009/aggbug/306536.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-12-18 13:28 <a href="http://www.blogjava.net/caizh2009/articles/306536.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle 的redo和undo 收藏</title><link>http://www.blogjava.net/caizh2009/articles/306534.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Fri, 18 Dec 2009 05:17:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/306534.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/306534.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/306534.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/306534.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/306534.html</trackback:ping><description><![CDATA[在这里会介绍UNDO，REDO是如何产生的，对TRANSACTIONS的影响，<br />
以及他们之间如何协同工作的。 什么是REDO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REDO记录transaction logs，分为online和archived。<br />
以恢复为目的。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 比如，机器停电，那么在重起之后需要online redo logs去恢复系统到失败点。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
比如，磁盘坏了，需要用archived redo logs和online redo logs区恢复数据。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
比如，truncate一个表或其他的操作，想恢复到之前的状态，同样也需要。 <br />
什么是UNDO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
REDO是为了重新实现你的操作，而UNDO相反，是为了撤销你做的操作，比如你得一个TRANSACTION执行失败了或你自己后悔了，<br />
则需要用ROLLBACK命令回退到操作之前。<br />
回滚是在逻辑层面实现而不是物理层面，因为在一个多用户系统中，数据结构，blocks等都在时时变化，<br />
比如我们INSERT一个数据，表的空间不够，扩展了一个新的EXTENT，我们的数据保存在这新的EXTENT里，其它用户随后也在这EXTENT里插入了数据，<br />
而此时我想ROLLBACK，那么显然物理上讲这EXTENT撤销是不可能的，因为这么做会影响其他用户的操作。<br />
所以，ROLLBACK是逻辑上回滚，比如对INSERT来说，那么ROLLBACK就是DELETE了。<br />
COMMIT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
以前，常想当然地认为，一个大的TRANSACTION（比如大批量地INSERT数据）的COMMIT会花费时间比短的TRANSACTION长。<br />
而事实上是没有什么区别的，因为ORACLE在COMMIT之前已经把该写的东西写到DISK中了，<br />
我们COMMIT只是 <br />
1，产生一个SCN给我们TRANSACTION，SCN简单理解就是给TRANSACTION排队，以便恢复和保持一致性。 <br />
2，REDO写REDO到DISK中（LGWR，这就是log file sync），记录SCN在ONLINE REDO LOG，当这一步发生时，我们可以说事实上已经提交了，<br />
&nbsp;&nbsp;&nbsp;&nbsp; 这个TRANSACTION已经结束（在V$TRANSACTION里消失了） <br />
3，SESSION所拥有的LOCK（V$LOCK）被释放。 <br />
4，Block Cleanout（这个问题是产生ORA-01555: snapshot too old的根本原因） ROLLBACK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
ROLLBACK和COMMIT正好相反，ROLLBACK的时间和TRANSACTION的大小有直接关系。<br />
因为ROLLBACK必须物理上恢复数据。COMMIT之所以快，是因为ORACLE在COMMIT之前已经作了很多工作（产生UNDO，修改BLOCK，REDO，LATCH分配），<br />
ROLLBACK慢也是基于相同的原因。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
ROLLBACK会&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
1，恢复数据，DELETE的就重新INSERT，INSERT的就重新DELETE，UPDATE的就再UPDATE。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
2，RELEASE LOCK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ROLLBACK要比COMMIT消耗更多资源，因为ORACLE认为你一旦做数据更新，<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 那么就意味着你要COMMIT（其他数据库不全是这种设计理念，比如DB2），所以在你更新数据的时候就做了大量的工作，<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这也可以理解为什么不建议用TABLE来做TEMPORARY TABLE。<br />
（TEMP TABLE消耗的REDO比固定表在INSERT时要少很多&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ，UPDATE时差不多是1/2，但是DELETE却相差无几） REDO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
产生REDO 越多，你的系统越慢，不但影响你自己的SESSION，还影响其他SESSION，LGWR管理REDO，并且是TRANSACTION的结束标志。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
首先要知道怎么监控REDO，当然，SET AUTOTRACE ON可以，不过只能监控DML语句，而像PROCEDURE则无法监视。那么我们就需要观察字典了，<br />
V$MYSTAT, V$STATNAME，<br />
前面有两个脚本，<br />
mystat，mystat2 SQL&gt; @mystat "redo size" NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
VALUE ---------------------------------------------------------------- ---------- redo size&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 1016784 SQL&gt; insert into t select * from big_table; 已创建46990行。 <br />
SQL&gt; @mystat2 NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
V ---------------------------------------------------------------- ---------- DIFF ---------------- redo size&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
6604308&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5,587,524&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 看到产生了5,587,524的REDO，再对比下用NOLOG插入<br />
SQL&gt; @mystat "redo size" NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
VALUE ---------------------------------------------------------------- ---------- redo size&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp; 6604308 SQL&gt; insert /*+ APPEND */ into t select * from big_table; 已创建46990行。 <br />
SQL&gt; @mystat2 NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; V ---------------------------------------------------------------- ---------- DIFF ---------------- redo size&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6616220&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 11,912&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 看到APPEND插入用了11,912字节的REDO，比一般性插入要少很多。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
或者用这个PROCEDURE也可以观察SQL消耗的REDO create or replace procedure do_sql( p_sql in varchar2 ) 2 as 3 l_start_redo number; 4 l_redo number; <br />
5 begin 6 select v$mystat.value 7 into l_start_redo 8 from v$mystat, v$statname 9 where v$mystat.statistic# = v$statname.statistic# 10 and v$statname.name = 'redo size'; <br />
11 12 execute immediate p_sql; 13 commit; 14 15 select v$mystat.value-l_start_redo 16 into l_redo 17 from v$mystat, <br />
v$statname 18 where v$mystat.statistic# = v$statname.statistic# 19 and v$statname.name = 'redo size'; <br />
20 21 dbms_output.put_line 22 ( to_char(l_redo,'9,999,999') ||' bytes of redo generated for "' || 23 substr( replace( p_sql, chr(10), ' '), 1, 25 ) || '"...' ); 24 end; 25 /&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp; 用法就不多说了。 减少REDO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 既然REDO这么消耗资源，那我们能屏蔽REDO吗？显然不能，那我们能减少REDO吗？这是可以的<br />
（注意，9.2以后，可以用FORCE LOGGING开关来控制是否强制REDO，如果YES，则不管NOLOGGING还是APPEND都是不起任何作用的，<br />
可以SELECT FORCE_LOGGING FROM V$DATABASE查看是否FORCE。另外需要明白，没有一个办法能彻底不记录REDO，只能是减少REDO。<br />
因为不管如何，数据字典总是要产生一些REDO的。 create table nologging as select xxx新建的表没有原来表的索引和默认值,只有非空(not null)的约束素条件可以继承过来. <br />
INSERT /*+ APPEND */ INTO target_tablename SELECT 如果运行此命令时还有对target_tablename的DML操作会排队在它后面,对OLTP系统在用的表操作是不合适的。<br />
快速插入数据可以指定append提示，但是需要注意 noarchivelog模式下，默认用了append就是nologging模式的。 在archivelog下，需要把表设置程Nologging模式。<br />
可以通过如下语句设置为NO FORCE LOGGING。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Alter database no force logging; 这两种方法转移数据时没有用SGA里数据缓冲区和事物处理的回滚段, <br />
也不写联机事物日志，就象数据库装载工具SQLLOAD一样直接把数据写到物理文件。 REDO的问题 <br />
&nbsp;&nbsp;&nbsp; 有时，会在ALERT中发现 Thread 1 cannot allocate new log, sequence 1466 Checkpoint not complete Current log# 3 seq# 1465 mem# 0: /home/ora10g/oradata/ora10g/redo03.log&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp; 这问题出现在系统尝试reuse online redo log file但是却没有可用的。可能是由于DBWR没有完成(Checkpoint not complete)或ARCH没有完成。&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 1，DBWR，用多DBWR process，合理分布数据，&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
2，增加REDO LOG FILE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
3，扩大REDO的大小&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 4，让CHECKPOINT发生更频繁，可以减少block buffer cache，FAST_START_MTTR_TARGET，<br />
LOG_CHECKPOINT_INTERVAL，LOG_CHECKPOINT_TIMEOUT。（要考虑全面哟）
<img src ="http://www.blogjava.net/caizh2009/aggbug/306534.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-12-18 13:17 <a href="http://www.blogjava.net/caizh2009/articles/306534.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle的Nologging何时生效 与 批量insert加载数据速度(zt) </title><link>http://www.blogjava.net/caizh2009/articles/306531.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Fri, 18 Dec 2009 05:11:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/306531.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/306531.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/306531.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/306531.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/306531.html</trackback:ping><description><![CDATA[<div class="storytext">Oracle的Nologging何时生效 与 批量insert加载数据速度(zt)<br />
<div class="storytext">
<p><font size="2">一 非归档模式下</font></p>
<p><font size="2">D:&gt;sqlplus "/ as sysdba"</font></p>
<p><font size="2">数据库版本为9.2.0.1.0</font></p>
<p><font size="2">SQL*Plus: Release 9.2.0.1.0 - Production on 星期一 8月 14 10:20:39 2006</font></p>
<p><font size="2">Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.</font></p>
<br />
<p>
<p><br />
<font size="2">连接到:<br />
Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production<br />
With the Partitioning, OLAP and Oracle Data Mining options<br />
JServer Release 9.2.0.1.0 - Production</font>
<p>
<p><font size="2">当前session产生的redo<br />
SQL&gt; create or replace view redo_size<br />
2 as<br />
3 select value<br />
4 from v$mystat, v$statname<br />
5 where v$mystat.statistic# = v$statname.statistic#<br />
6 and v$statname.name = 'redo size';</font></p>
<p><font size="2">视图已建立。</font></p>
<p><font size="2">授权给相应数据库schema<br />
SQL&gt; grant select on redo_size to liyong;</font></p>
<p><font size="2">授权成功。</font></p>
<p><font size="2">SQL&gt; shutdown immediate;<br />
数据库已经关闭。<br />
已经卸载数据库。<br />
ORACLE 例程已经关闭。</font></p>
<p><font size="2">SQL&gt; startup mount;<br />
ORACLE 例程已经启动。</font></p>
<p><font size="2">Total System Global Area 122755896 bytes<br />
Fixed Size 453432 bytes<br />
Variable Size 88080384 bytes<br />
Database Buffers 33554432 bytes<br />
Redo Buffers 667648 bytes<br />
数据库装载完毕。</font></p>
<p><font size="2">非归档模式<br />
SQL&gt; alter database noarchivelog;</font></p>
<p><font size="2">数据库已更改。</font></p>
<p><font size="2">SQL&gt; alter database open;</font></p>
<p><font size="2">数据库已更改。</font></p>
<p><font size="2">SQL&gt; create table redo_test as<br />
2 select * from all_objects where 1=2;</font></p>
<p><font size="2">表已创建。</font></p>
<p><font size="2">SQL&gt; select * from sys.redo_size;</font></p>
<p><font size="2">VALUE<br />
----------<br />
59488</font></p>
<p><font size="2">SQL&gt; insert into redo_test<br />
2 select * from all_objects;</font></p>
<p><font size="2">已创建28260行。</font></p>
<p><font size="2">SQL&gt; select * from sys.redo_size;</font></p>
<p><font size="2">VALUE<br />
----------<br />
3446080</font></p>
<p><font size="2">SQL&gt; insert /*+ append */ into redo_test<br />
2 select * from all_objects;</font></p>
<p><font size="2">已创建28260行。</font></p>
<p><font size="2">SQL&gt; commit;</font></p>
<p><font size="2">提交完成。</font></p>
<p><font size="2">SQL&gt; select * from sys.redo_size;</font></p>
<p><font size="2">VALUE<br />
----------<br />
3458156</font></p>
<p><font size="2">可以看到insert /*+ append */ into方式redo产生很少.<br />
SQL&gt; select 3446080-59488,3458156-3446080 from dual;</font></p>
<p><font size="2">3446080-59488 3458156-3446080<br />
------------- ---------------<br />
3386592 12076</font></p>
<p>
<p><font size="2">将表redo_test置为nologging状态.<br />
SQL&gt; alter table redo_test nologging;</font></p>
<p><font size="2">表已更改。</font></p>
<p><font size="2">SQL&gt; select * from sys.redo_size;</font></p>
<p><font size="2">VALUE<br />
----------<br />
3460052</font></p>
<p><font size="2">SQL&gt; insert into redo_test<br />
2 select * from all_objects;</font></p>
<p><font size="2">已创建28260行。</font></p>
<p><font size="2">SQL&gt; commit;</font></p>
<p><font size="2">提交完成。</font></p>
<p><font size="2">SQL&gt; select * from sys.redo_size;</font></p>
<p><font size="2">VALUE<br />
----------<br />
6805876</font></p>
<p><font size="2">SQL&gt; insert /*+ append */ into redo_test<br />
2 select * from all_objects;</font></p>
<p><font size="2">已创建28260行。</font></p>
<p><font size="2">SQL&gt; commit;</font></p>
<p><font size="2">提交完成。</font></p>
<p><font size="2">SQL&gt; select * from sys.redo_size;</font></p>
<p><font size="2">VALUE<br />
----------<br />
6818144</font></p>
<p><font size="2">非归档模式下表的nologging状态对于redo影响不大<br />
SQL&gt; select 6805876-3460052,6818144-6805876 from dual;</font></p>
<p><font size="2">6805876-3460052 6818144-6805876<br />
--------------- ---------------<br />
3345824 12268</font></p>
<p><br />
<font size="2">结论: 在非归档模式下通过insert /*+ append */ into方式批量加载数据可以大大减少redo产生.</font></p>
<p>
<p>
<p>
<p>
<p><font size="2">二 归档模式下</font></p>
<p><br />
<font size="2">SQL&gt; shutdown immediate;<br />
数据库已经关闭。<br />
已经卸载数据库。<br />
ORACLE 例程已经关闭。<br />
SQL&gt; startup mount;<br />
ORACLE 例程已经启动。</font></p>
<p><font size="2">Total System Global Area 122755896 bytes<br />
Fixed Size 453432 bytes<br />
Variable Size 88080384 bytes<br />
Database Buffers 33554432 bytes<br />
Redo Buffers 667648 bytes<br />
数据库装载完毕。<br />
SQL&gt; alter database archivelog;</font></p>
<p><font size="2">数据库已更改。</font></p>
<p><font size="2">SQL&gt; alter database open;</font></p>
<p><font size="2">数据库已更改。</font></p>
<p><font size="2">SQL&gt; conn liyong<br />
请输入口令:<br />
已连接。</font></p>
<p><br />
<font size="2">将表redo_test重新置为logging<br />
SQL&gt; alter table redo_test logging;</font></p>
<p><font size="2">表已更改。</font></p>
<p><font size="2">SQL&gt; select * from sys.redo_size;</font></p>
<p><font size="2">VALUE<br />
----------<br />
5172</font></p>
<p><font size="2">SQL&gt; insert into redo_test<br />
2 select * from all_objects;</font></p>
<p><font size="2">已创建28260行。</font></p>
<p><font size="2">SQL&gt; commit;</font></p>
<p><font size="2">提交完成。</font></p>
<p><font size="2">SQL&gt; select * from sys.redo_size;</font></p>
<p><font size="2">VALUE<br />
----------<br />
3351344</font></p>
<p><font size="2">SQL&gt; insert /*+ append */ into redo_test<br />
2 select * from all_objects;</font></p>
<p><font size="2">已创建28260行。</font></p>
<p><font size="2">SQL&gt; commit;</font></p>
<p><font size="2">提交完成。</font></p>
<p><font size="2">SQL&gt; select * from sys.redo_size;</font></p>
<p><font size="2">VALUE<br />
----------<br />
6659932</font></p>
<p><font size="2">可以看到在归档模式下，且表的logging属性为true,insert /*+ append */ into这种方式也会纪录大量redo<br />
SQL&gt; select 3351344-5172,6659932-3351344 from dual;</font></p>
<p><font size="2">3351344-5172 6659932-3351344<br />
------------ ---------------<br />
3346172 3308588</font></p>
<p><br />
<font size="2">将表置为nologging</font></p>
<p><font size="2">SQL&gt; alter table redo_test nologging;</font></p>
<p><font size="2">表已更改。</font></p>
<p><font size="2">SQL&gt; select * from sys.redo_size;</font></p>
<p><font size="2">VALUE<br />
----------<br />
6661820</font></p>
<p><font size="2">SQL&gt; insert into redo_test<br />
2 select * from all_objects;</font></p>
<p><font size="2">已创建28260行。</font></p>
<p><font size="2">SQL&gt; commit;</font></p>
<p><font size="2">提交完成。</font></p>
<p><font size="2">SQL&gt; select * from sys.redo_size;</font></p>
<p><font size="2">VALUE<br />
----------<br />
10008060</font></p>
<p><font size="2">SQL&gt; insert /*+ append */ into redo_test<br />
2 select * from all_objects;</font></p>
<p><font size="2">已创建28260行。</font></p>
<p><font size="2">SQL&gt; commit;</font></p>
<p><font size="2">提交完成。</font></p>
<p><font size="2">SQL&gt; select * from sys.redo_size;</font></p>
<p><font size="2">VALUE<br />
----------<br />
10022852</font></p>
<p><font size="2">可以发现在归档模式，要设置表的logging属性为false，才能通过insert /*+ append */ into大大减少redo产生.<br />
SQL&gt; select 10008060-6661820,10022852-10008060 from dual;</font></p>
<p><font size="2">10008060-6661820 10022852-10008060<br />
---------------- -----------------<br />
3346240 14792</font></p>
<p>
<p><font size="2">结论: 在归档模式下,要设置表的logging属性为false，<br />
才能通过insert /*+ append */ into大大减少redo.</font></p>
<p>
<p>
<p>
<p>
<p><font size="2">三 下面我们再看一下在归档模式下，几种批量insert操作的效率对比.</font></p>
<p>
<p><font size="2">redo_test表有45W条记录</font></p>
<p><font size="2">SQL&gt; select count(*) from redo_test;</font></p>
<p><font size="2">COUNT(*)<br />
----------<br />
452160</font></p>
<p><br />
<font size="2">1 最常见的批量数据加载 25秒</font></p>
<p><font size="2">SQL&gt; create table insert_normal as<br />
2 select * from redo_test where 0=2;</font></p>
<p><font size="2">表已创建。</font></p>
<p><font size="2">SQL&gt; set timing on</font></p>
<p><font size="2">SQL&gt; insert into insert_normal<br />
2 select * from redo_test;</font></p>
<p><font size="2">已创建452160行。</font></p>
<p><font size="2">提交完成。<br />
已用时间: 00: 00: 25.00</font></p>
<p><br />
<font size="2">2 使用insert /*+ append */ into方式(这个的原理可以参见&lt;&lt;批量DML操作优化建议.txt&gt;&gt;)，但纪录redo. 17.07秒<br />
SQL&gt; create table insert_hwt<br />
2 as<br />
3 select * from redo_test where 0=2;</font></p>
<p><font size="2">表已创建。<br />
SQL&gt; insert /*+ append */ into insert_hwt<br />
2 select * from redo_test;</font></p>
<p><font size="2">已创建452160行。</font></p>
<p><font size="2">提交完成。<br />
已用时间: 00: 00: 17.07</font></p>
<p><br />
<font size="2">3 使用insert /*+ append */ into方式，且通过设置表nologging不纪录redo.</font></p>
<p><font size="2">SQL&gt; create table insert_hwt_with_nologging nologging<br />
2 as<br />
3 select * from redo_test where 2=0;</font></p>
<p><font size="2">表已创建。</font></p>
<p><font size="2">/*<br />
或者通过<br />
alter table table_name nologging设置<br />
*/</font></p>
<p><font size="2">SQL&gt; insert /*+ append */ into insert_hwt_with_nologging 11.03秒<br />
2 select * from redo_test;</font></p>
<p><font size="2">已创建452160行。</font></p>
<p><font size="2">提交完成。<br />
已用时间: 00: 00: 11.03</font></p>
<p>
<p><font size="2">总结:</font></p>
<p><font size="2">我们看到对于批量操作，如果设置表nologging，可以大大提高性能.原因就是Oracle没有纪录DML所产生的redo.<br />
当然，这样会影响到备份。nologging加载数据后要做数据库全备.</font></p>
</div>
</div>
<div class="storyposted">jolly10 发表于:2008.03.18 13:19 ::分类: ( <a href="http://jolly10.itpub.net/category/7268/56630">转载学习内容</a> ) ::阅读:(1097次) :: <a href="http://jolly10.itpub.net/post/7268/457533">评论 (3)</a> :: <a href="http://jolly10.itpub.net/trackbacks/7268/457533">引用 (0)</a> </div>
<div class="story">
<div class="storyTitle"><img alt="" src="http://blog.itpub.net//imgs/comment_icon1.gif" /> re: Oracle的Nologging何时生效 与 批量insert加载数据速度(zt) <span class="categoryinfo">[<a href="http://jolly10.itpub.net/index.php?op=Comment&amp;articleId=457533&amp;parentId=21193736&amp;blogId=7268">回复</a>]</span> </div>
<div class="storytext">
<p>下面我又试了试insert into XXX values (XXX)能不能少产生redo,做了试验发现,不行的,下面的过程.<br />
SQL&gt; select * from v$version where rownum archive log list;<br />
Database log mode No Archive Mode<br />
Automatic archival Disabled<br />
Archive destination USE_DB_RECOVERY_FILE_DEST<br />
Oldest online log sequence 17<br />
Current log sequence 19</p>
<p>SQL&gt; create or replace view redo_size<br />
2 as<br />
3 select value<br />
4 from v$mystat, v$statname<br />
5 where v$mystat.statistic# = v$statname.statistic#<br />
6 and v$statname.name = 'redo size';</p>
<p>View created.</p>
<p>SQL&gt; grant select on redo_size to ljg;</p>
<p>SQL&gt; conn ljg/ljg<br />
Connected.</p>
<p>SQL&gt; create table redo_test as<br />
2 select * from all_objects where 1=2;</p>
<p>SQL&gt; CREATE OR REPLACE PROCEDURE p_loging<br />
2 as<br />
3 CURSOR c_a IS<br />
4 SELECT * FROM all_objects;<br />
5<br />
6 BEGIN<br />
7 FOR x IN c_a LOOP<br />
8 INSERT INTO REDO_TEST<br />
9 VALUES(x.OWNER, x.OBJECT_NAME, x.SUBOBJECT_NAME, x.OBJECT_ID, x.DATA_OBJE CT_ID,<br />
10 x.OBJECT_TYPE, x.CREATED, x.LAST_DDL_TIME, x.TIMESTAMP, x.STATUS, x.TEMPORARY, x.GENERATED, x.SECONDARY);<br />
11 END LOOP;<br />
12 COMMIT;<br />
13<br />
14 END;<br />
15 /</p>
<p>Procedure created.</p>
<p>SQL&gt; CREATE OR REPLACE PROCEDURE p_nologing<br />
2 as<br />
3 CURSOR c_a IS<br />
4 SELECT * FROM all_objects;<br />
5<br />
6 BEGIN<br />
7 FOR x IN c_a LOOP<br />
8 INSERT /*+ APPEND */ INTO REDO_TEST<br />
9 VALUES(x.OWNER, x.OBJECT_NAME, x.SUBOBJECT_NAME, x.OBJECT_ID, x.DATA_OBJECT_ID,<br />
10 x.OBJECT_TYPE, x.CREATED, x.LAST_DDL_TIME, x.TIMESTAMP, x.STATUS, x.TEMPORARY, x.GENERATED, x.SECONDARY);<br />
11 END LOOP;<br />
12 COMMIT;<br />
13<br />
14 END;<br />
15 /</p>
<p>Procedure created.</p>
<p>SQL&gt; select * from sys.redo_size;</p>
<p>VALUE<br />
----------<br />
85940</p>
<p>SQL&gt; exec p_loging;</p>
<p>PL/SQL procedure successfully completed.</p>
<p>SQL&gt; select * from sys.redo_size;</p>
<p>VALUE<br />
----------<br />
15273968</p>
<p>SQL&gt; exec p_nologing;</p>
<p>PL/SQL procedure successfully completed.</p>
<p>SQL&gt; select * from sys.redo_size;</p>
<p>VALUE<br />
----------<br />
30411272</p>
<p>SQL&gt; select 15273968- 85940 logging,30411272-15273968 nologging from dual;</p>
<p>LOGGING NOLOGGING<br />
---------- ----------<br />
15188028 15137304</p>
<p>可以看到nologging和logging产生的redo差不多.</p>
</div>
<div class="storyposted">jolly10 评论于：2008.06.05 11:07 </div>
</div>
<div class="story">
<div class="storyTitle"><img alt="" src="http://blog.itpub.net//imgs/comment_icon1.gif" /> re: Oracle的Nologging何时生效 与 批量insert加载数据速度(zt) <span class="categoryinfo">[<a href="http://jolly10.itpub.net/index.php?op=Comment&amp;articleId=457533&amp;parentId=21193743&amp;blogId=7268">回复</a>]</span> </div>
<div class="storytext">
<p>下面我又试了试insert into XXX values (XXX)能不能少产生redo,做了试验发现,不行的,下面的过程.<br />
SQL&gt; select * from v$version where rownum archive log list;<br />
Database log mode No Archive Mode<br />
Automatic archival Disabled<br />
Archive destination USE_DB_RECOVERY_FILE_DEST<br />
Oldest online log sequence 17<br />
Current log sequence 19</p>
<p>SQL&gt; create or replace view redo_size<br />
2 as<br />
3 select value<br />
4 from v$mystat, v$statname<br />
5 where v$mystat.statistic# = v$statname.statistic#<br />
6 and v$statname.name = 'redo size';</p>
<p>View created.</p>
<p>SQL&gt; grant select on redo_size to ljg;</p>
<p>SQL&gt; conn ljg/ljg<br />
Connected.</p>
<p>SQL&gt; create table redo_test as<br />
2 select * from all_objects where 1=2;</p>
<p>SQL&gt; CREATE OR REPLACE PROCEDURE p_loging<br />
2 as<br />
3 CURSOR c_a IS<br />
4 SELECT * FROM all_objects;<br />
5<br />
6 BEGIN<br />
7 FOR x IN c_a LOOP<br />
8 INSERT INTO REDO_TEST<br />
9 VALUES(x.OWNER, x.OBJECT_NAME, x.SUBOBJECT_NAME, x.OBJECT_ID, x.DATA_OBJE CT_ID,<br />
10 x.OBJECT_TYPE, x.CREATED, x.LAST_DDL_TIME, x.TIMESTAMP, x.STATUS, x.TEMPORARY, x.GENERATED, x.SECONDARY);<br />
11 END LOOP;<br />
12 COMMIT;<br />
13<br />
14 END;<br />
15 /</p>
<p>Procedure created.</p>
<p>SQL&gt; CREATE OR REPLACE PROCEDURE p_nologing<br />
2 as<br />
3 CURSOR c_a IS<br />
4 SELECT * FROM all_objects;<br />
5<br />
6 BEGIN<br />
7 FOR x IN c_a LOOP<br />
8 INSERT /*+ APPEND */ INTO REDO_TEST<br />
9 VALUES(x.OWNER, x.OBJECT_NAME, x.SUBOBJECT_NAME, x.OBJECT_ID, x.DATA_OBJECT_ID,<br />
10 x.OBJECT_TYPE, x.CREATED, x.LAST_DDL_TIME, x.TIMESTAMP, x.STATUS, x.TEMPORARY, x.GENERATED, x.SECONDARY);<br />
11 END LOOP;<br />
12 COMMIT;<br />
13<br />
14 END;<br />
15 /</p>
<p>Procedure created.</p>
<p>SQL&gt; select * from sys.redo_size;</p>
<p>VALUE<br />
----------<br />
85940</p>
<p>SQL&gt; exec p_loging;</p>
<p>PL/SQL procedure successfully completed.</p>
<p>SQL&gt; select * from sys.redo_size;</p>
<p>VALUE<br />
----------<br />
15273968</p>
<p>SQL&gt; exec p_nologing;</p>
<p>PL/SQL procedure successfully completed.</p>
<p>SQL&gt; select * from sys.redo_size;</p>
<p>VALUE<br />
----------<br />
30411272</p>
<p>SQL&gt; select 15273968- 85940 logging,30411272-15273968 nologging from dual;</p>
<p>LOGGING NOLOGGING<br />
---------- ----------<br />
15188028 15137304</p>
<p>可以看到nologging和logging产生的redo差不多.</p>
</div>
<div class="storyposted">jolly10 评论于：2008.06.05 11:07 </div>
</div>
<div class="story">
<div class="storyTitle"><img alt="" src="http://blog.itpub.net//imgs/comment_icon1.gif" /> re: Oracle的Nologging何时生效 与 批量insert加载数据速度(zt) <span class="categoryinfo">[<a href="http://jolly10.itpub.net/index.php?op=Comment&amp;articleId=457533&amp;parentId=21194307&amp;blogId=7268">回复</a>]</span> </div>
<div class="storytext">
<p>在ITPUB中问到可以用BULK COLLECT 来减少insert into values的redo.<br />
CREATE OR REPLACE PROCEDURE p_BulkAdd<br />
AS<br />
TYPE Tredo_test IS TABLE OF REDO_TEST%ROWTYPE;<br />
V_REDO_TEST Tredo_test;<br />
BEGIN<br />
SELECT * BULK COLLECT INTO V_REDO_TEST FROM ALL_OBJECTS;<br />
FORALL X IN V_REDO_TEST.FIRST..V_REDO_TEST.LAST<br />
INSERT INTO REDO_TEST VALUES V_REDO_TEST(X);<br />
END;<br />
/</p>
<p>SQL&gt; select * from sys.redo_size;</p>
<p>VALUE<br />
----------<br />
30411272</p>
<p>SQL&gt; exec p_bulkadd;</p>
<p>PL/SQL procedure successfully completed.</p>
<p>SQL&gt; select * from sys.redo_size;</p>
<p>VALUE<br />
----------<br />
35050796</p>
<p>SQL&gt; select 35050796-30411272 from dual;</p>
<p>35050796-30411272<br />
-----------------<br />
4639524</p>
<p>这个做的确是少了很多redo.是一个方法.</p>
</div>
</div>
<img src ="http://www.blogjava.net/caizh2009/aggbug/306531.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-12-18 13:11 <a href="http://www.blogjava.net/caizh2009/articles/306531.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在Java/JDBC中透明处理“ORA-04068”错误</title><link>http://www.blogjava.net/caizh2009/articles/306451.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 17 Dec 2009 16:09:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/306451.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/306451.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/306451.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/306451.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/306451.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转载自：http://database.ctocio.com.cn/tips/14/8106014.shtml在Oracle 里，如果你想编写存储过程你当然应该使用PL/SQL包。在这篇文章里，假设你一般了解PL/SQL 和非常熟悉PL/SQL 包。这篇文章关注于一个令人讨厌的错误，这个错误使许多使用PL/SQL以及使用API(例如JDBC)从应用层调用它的开发人员很苦恼。...&nbsp;&nbsp;<a href='http://www.blogjava.net/caizh2009/articles/306451.html'>阅读全文</a><img src ="http://www.blogjava.net/caizh2009/aggbug/306451.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-12-18 00:09 <a href="http://www.blogjava.net/caizh2009/articles/306451.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>触发器 操作 自身表</title><link>http://www.blogjava.net/caizh2009/articles/304717.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 03 Dec 2009 16:04:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/304717.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/304717.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/304717.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/304717.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/304717.html</trackback:ping><description><![CDATA[<h1 class="post-title">一则父子表下trigger抛出ORA-04091异常的变通处理</h1>
<div id="copyright">07月 1st, 2008&nbsp;|post by Kevin.yuan&nbsp; |【转载时请务必以超链接形式标明文章原始出处和作者信息】</div>
<p>&nbsp;&nbsp;&nbsp;trigger抛出ORA-04091异常,无非是当前trigger下的事务access了一mutating table,比较常见的就是trigger访问了自身上的表.在一个指定on delete cascade模式下的父子表中,trigger中如果有对其相关的父/子表的访问,依然会抛出ORA-04091.这是比较隐性的. </p>
<p>&nbsp;&nbsp;&nbsp;拿oracle的示例表emp和dept来做这个试验.<br />
&nbsp;&nbsp;&nbsp;dept的表结构如下:</p>
<div class="hl-surround">
<div class="hl-main"><span style="color: green">create</span><span style="color: gray"> </span><span style="color: green">table</span><span style="color: gray"> </span><span style="color: blue">DEPT</span><span style="color: gray"><br />
&nbsp;&nbsp; &nbsp;</span><span style="color: olive">(</span><span style="color: blue">DEPTNO</span><span style="color: gray"> </span><span style="color: #00008b">NUMBER</span><span style="color: olive">(</span><span style="color: maroon">2</span><span style="color: olive">)</span><span style="color: gray"> </span><span style="color: green">not</span><span style="color: gray"> </span><span style="color: green">null</span><span style="color: gray"> </span><span style="color: green">primary</span><span style="color: gray"> </span><span style="color: green">key</span><span style="color: gray">,<br />
&nbsp;&nbsp; &nbsp; </span><span style="color: blue">DNAME</span><span style="color: gray">&nbsp; </span><span style="color: blue">VARCHAR2</span><span style="color: olive">(</span><span style="color: maroon">14</span><span style="color: olive">)</span><span style="color: gray">,<br />
&nbsp;&nbsp; &nbsp; </span><span style="color: blue">LOC</span><span style="color: gray">&nbsp; &nbsp; </span><span style="color: blue">VARCHAR2</span><span style="color: olive">(</span><span style="color: maroon">13</span><span style="color: olive">))</span><span style="color: gray">;</span></div>
</div>
<p>&nbsp;&nbsp;&nbsp; emp表结构如下:<br />
</p>
<div class="hl-surround">
<div class="hl-main"><span style="color: green">create</span><span style="color: gray"> </span><span style="color: green">table</span><span style="color: gray"> </span><span style="color: blue">EMP</span><span style="color: gray"><br />
&nbsp;&nbsp; &nbsp;</span><span style="color: olive">(</span><span style="color: blue">EMPNO</span><span style="color: gray">&nbsp; &nbsp; </span><span style="color: #00008b">NUMBER</span><span style="color: olive">(</span><span style="color: maroon">4</span><span style="color: olive">)</span><span style="color: gray">,<br />
&nbsp;&nbsp; &nbsp; </span><span style="color: blue">ENAME</span><span style="color: gray">&nbsp; &nbsp; </span><span style="color: blue">VARCHAR2</span><span style="color: olive">(</span><span style="color: maroon">10</span><span style="color: olive">)</span><span style="color: gray">,<br />
&nbsp;&nbsp; &nbsp; </span><span style="color: blue">JOB</span><span style="color: gray">&nbsp; &nbsp; &nbsp; </span><span style="color: blue">VARCHAR2</span><span style="color: olive">(</span><span style="color: maroon">9</span><span style="color: olive">)</span><span style="color: gray">,<br />
&nbsp;&nbsp; &nbsp; </span><span style="color: blue">MGR</span><span style="color: gray">&nbsp; &nbsp; &nbsp; </span><span style="color: #00008b">NUMBER</span><span style="color: olive">(</span><span style="color: maroon">4</span><span style="color: olive">)</span><span style="color: gray">,<br />
&nbsp;&nbsp; &nbsp; </span><span style="color: blue">HIREDATE</span><span style="color: gray"> </span><span style="color: green">DATE</span><span style="color: gray">,<br />
&nbsp;&nbsp; &nbsp; </span><span style="color: blue">SAL</span><span style="color: gray">&nbsp; &nbsp; &nbsp; </span><span style="color: #00008b">NUMBER</span><span style="color: olive">(</span><span style="color: maroon">7</span><span style="color: gray">,</span><span style="color: maroon">2</span><span style="color: olive">)</span><span style="color: gray">,<br />
&nbsp;&nbsp; &nbsp; </span><span style="color: blue">COMM</span><span style="color: gray">&nbsp; &nbsp; &nbsp;</span><span style="color: #00008b">NUMBER</span><span style="color: olive">(</span><span style="color: maroon">7</span><span style="color: gray">,</span><span style="color: maroon">2</span><span style="color: olive">)</span><span style="color: gray">,<br />
&nbsp;&nbsp; &nbsp; </span><span style="color: blue">DEPTNO</span><span style="color: gray">&nbsp; &nbsp;</span><span style="color: #00008b">NUMBER</span><span style="color: olive">(</span><span style="color: maroon">2</span><span style="color: olive">)</span><span style="color: gray">,<br />
&nbsp;&nbsp; &nbsp; </span><span style="color: green">foreign</span><span style="color: gray"> </span><span style="color: green">key</span><span style="color: olive">(</span><span style="color: blue">deptno</span><span style="color: olive">)</span><span style="color: gray"> </span><span style="color: green">references</span><span style="color: gray"> </span><span style="color: blue">dept</span><span style="color: olive">(</span><span style="color: blue">deptno</span><span style="color: olive">)</span><span style="color: gray"> </span><span style="color: green">on</span><span style="color: gray"> </span><span style="color: green">delete</span><span style="color: gray"> </span><span style="color: green">cascade</span><span style="color: olive">)</span><span style="color: gray">;</span></div>
</div>
<p>&nbsp;&nbsp;&nbsp; emp和dept是一对父子表,关联column为DEPTNO.</p>
<p>&nbsp;&nbsp;&nbsp; 接下来创建1个 table:emp_log 和1个语句级 trigger: emp_del_trg.取一个<br />
最简单的业务功能,emp_del_trg的作用就是当表emp记录被删除的时候,触发器将删除的记录的 EMPNO,DNAME和删除时间写入到emp_log中,当子表依赖的父表相关记录删除的时候,emp_log不做处理.<br />
&nbsp;&nbsp;&nbsp; 表emp_log的结构如下:</p>
<div class="hl-surround">
<div class="hl-main"><span style="color: green">create</span><span style="color: gray"> </span><span style="color: green">table</span><span style="color: gray"> </span><span style="color: blue">EMP_LOG</span><span style="color: gray"><br />
&nbsp;&nbsp; &nbsp;</span><span style="color: olive">(</span><span style="color: blue">ENAME</span><span style="color: gray"> </span><span style="color: blue">VARCHAR2</span><span style="color: olive">(</span><span style="color: maroon">20</span><span style="color: olive">)</span><span style="color: gray">,<br />
&nbsp;&nbsp; &nbsp; </span><span style="color: blue">DNAME</span><span style="color: gray"> </span><span style="color: blue">VARCHAR2</span><span style="color: olive">(</span><span style="color: maroon">20</span><span style="color: olive">)</span><span style="color: gray">,<br />
&nbsp;&nbsp; &nbsp; </span><span style="color: blue">DATES</span><span style="color: gray"> </span><span style="color: green">DATE</span><span style="color: gray"> </span><span style="color: olive">)</span><span style="color: gray">;</span></div>
</div>
<p>&nbsp;&nbsp;&nbsp; 触发器trigger代码如下:</p>
<div class="hl-surround">
<div class="hl-main"><span style="color: green">create</span><span style="color: gray"> </span><span style="color: green">or</span><span style="color: gray"> </span><span style="color: blue">replace</span><span style="color: gray"> </span><span style="color: green">trigger</span><span style="color: gray"> </span><span style="color: blue">emp_del_trg</span><span style="color: gray"> </span><span style="color: green">after</span><span style="color: gray"> </span><span style="color: green">delete</span><span style="color: gray"> </span><span style="color: green">on</span><span style="color: gray"> </span><span style="color: blue">emp</span><span style="color: gray"> </span><span style="color: green">for</span><span style="color: gray"> </span><span style="color: green">each</span><span style="color: gray"> </span><span style="color: green">row</span><span style="color: gray"> <br />
&nbsp;&nbsp; &nbsp; </span><span style="color: green">begin</span><span style="color: gray"><br />
&nbsp;&nbsp; &nbsp; </span><span style="color: green">insert</span><span style="color: gray"> </span><span style="color: green">into</span><span style="color: gray"> </span><span style="color: blue">emp_log</span><span style="color: gray"><br />
&nbsp;&nbsp; &nbsp; </span><span style="color: green">select</span><span style="color: gray"> :</span><span style="color: green">old</span><span style="color: gray">.</span><span style="color: blue">ename</span><span style="color: gray">, </span><span style="color: blue">dname</span><span style="color: gray">, </span><span style="color: blue">sysdate</span><span style="color: gray"> </span><span style="color: green">from</span><span style="color: gray"> </span><span style="color: blue">dept</span><span style="color: gray"> </span><span style="color: green">where</span><span style="color: gray"> </span><span style="color: blue">deptno</span><span style="color: gray"> = :</span><span style="color: green">old</span><span style="color: gray">.</span><span style="color: blue">deptno</span><span style="color: gray">;<br />
&nbsp;&nbsp; &nbsp; </span><span style="color: green">end</span><span style="color: gray">;</span></div>
</div>
<p>&nbsp;&nbsp;&nbsp; 来看看这个触发器是否能正常工作,首先删除emp的记录.</p>
<p>SQL&gt; delete from emp where rownum&lt;5;</p>
<p>4 rows deleted</p>
<p>SQL&gt; select * from emp_log;</p>
<p>ENAME DNAME DATES<br />
——————&#8211; ——————&#8211; ———&#8211;<br />
SMITH RESEARCH 2008-7-1 18<br />
ALLEN SALES 2008-7-1 18<br />
WARD SALES 2008-7-1 18<br />
JONES RESEARCH 2008-7-1 18</p>
<p>SQL&gt; rollback;</p>
<p>Rollback complete</p>
<p>&nbsp;&nbsp;&nbsp; 看似trigger工作正常,删除dept的记录呢?</p>
<p>SQL&gt; delete from dept where rownum&lt;3;</p>
<p>delete from dept</p>
<p>ORA-04091: 表 KEVINYUAN.DEPT 发生了变化, 触发器/函数不能读它<br />
ORA-06512: 在 &#8220;KEVINYUAN.EMP_DEL_TRG&#8221;, line 2<br />
ORA-04088: 触发器 &#8216;KEVINYUAN.EMP_DEL_TRG&#8217; 执行过程中出错</p>
<p>&nbsp;&nbsp;&nbsp; ORA-04091错误如约而至.不难解释,因为父子表指定了级联删除,删除dept的记录<br />
从而引起删除emp表上的相应数据,然后触发了emp_del_trg,由于trigger里有对dept的访问,对当前事务说,dept就是一个mutating table,这是不被允许的.</p>
<p>&nbsp;&nbsp;&nbsp; 如何来解决这个问题而实现这个简单的业务逻辑功能呢?当然,从表结构逻辑设计上来讲,可以将dept表上的dname字段add到emp表,或者不要显式的指定references,用程序来维护数据的完整性和约束,然后调整业务代码.最直接的方法，在trigger中声明一个ora-04091的exception，对此异常不做处理，也可完成目的。</p>
<p>&nbsp;&nbsp;&nbsp; 我们不妨做一下变通处理.将行级级触发器变通成语句级触发器.看下面的处理.</p>
<p>&nbsp;&nbsp;&nbsp; 1.创建一个package:emp_pkg .</p>
<div class="hl-surround">
<ol class="hl-main ln-show" ondblclick="linenumber(this)" title="Double click to hide line number.">
    <li class="hl-firstline"><span style="color: green">CREATE</span><span style="color: gray"> </span><span style="color: green">OR</span><span style="color: gray"> </span><span style="color: blue">REPLACE</span><span style="color: gray"> </span><span style="color: blue">PACKAGE</span><span style="color: gray"> </span><span style="color: blue">emp_pkg</span><span style="color: gray"> </span><span style="color: green">AS</span>
    <li><span style="color: gray">&nbsp; &nbsp; </span><span style="color: #ffa500">/* ----------------------------------</span>
    <li><span style="color: #ffa500">&nbsp; &nbsp; &nbsp;&nbsp; --Author:Kevin.yuan</span>
    <li><span style="color: #ffa500">&nbsp; &nbsp; &nbsp;&nbsp; --create_time: 2008 -07-01</span>
    <li><span style="color: #ffa500">&nbsp; &nbsp; ---------------------------------- */</span><span style="color: gray">&nbsp;</span>
    <li><span style="color: gray">&nbsp; &nbsp;&nbsp; </span><span style="color: #00008b">TYPE</span><span style="color: gray">&nbsp;</span><span style="color: blue">crArray</span><span style="color: gray"> </span><span style="color: green">IS</span><span style="color: gray"> </span><span style="color: green">TABLE</span><span style="color: gray"> </span><span style="color: green">OF</span><span style="color: gray"> </span><span style="color: blue">emp</span><span style="color: gray">%</span><span style="color: blue">ROWTYPE</span><span style="color: gray"> </span><span style="color: blue">INDEX</span><span style="color: gray"> </span><span style="color: green">BY</span><span style="color: gray"> </span><span style="color: blue">BINARY_INTEGER</span><span style="color: gray">;</span>
    <li><span style="color: gray">&nbsp; &nbsp;&nbsp; </span><span style="color: blue">oldRows</span><span style="color: gray">&nbsp;</span><span style="color: blue">crArray</span><span style="color: gray">; --</span><span style="color: blue">accept</span><span style="color: gray"> </span><span style="color: blue">the</span><span style="color: gray"> </span><span style="color: green">old</span><span style="color: gray"> </span><span style="color: green">values</span><span style="color: gray"> </span><span style="color: green">of</span><span style="color: gray"> </span><span style="color: blue">emp</span>
    <li><span style="color: gray">&nbsp; &nbsp;&nbsp; </span><span style="color: blue">oldEmpty</span><span style="color: gray">&nbsp;</span><span style="color: blue">crArray</span><span style="color: gray">;&nbsp; --</span><span style="color: green">initialize</span><span style="color: gray"> </span><span style="color: green">values</span>
    <li><span style="color: gray">&nbsp; &nbsp;&nbsp; </span><span style="color: green">END</span><span style="color: gray">&nbsp;</span><span style="color: blue">emp_pkg</span><span style="color: gray">;</span></li>
</ol>
</div>
<p>&nbsp;&nbsp;&nbsp; 2.创建一个语句级trigger,用来触发trigger的时候清空初始化数据.</p>
<div class="hl-surround">
<ol class="hl-main ln-show" ondblclick="linenumber(this)" title="Double click to hide line number.">
    <li class="hl-firstline"><span style="color: green">CREATE</span><span style="color: gray"> </span><span style="color: green">OR</span><span style="color: gray"> </span><span style="color: blue">REPLACE</span><span style="color: gray"> </span><span style="color: green">TRIGGER</span><span style="color: gray"> </span><span style="color: blue">emp_bd_st</span><span style="color: gray"> </span><span style="color: green">BEFORE</span><span style="color: gray"> </span><span style="color: green">DELETE</span><span style="color: gray"> </span><span style="color: green">ON</span><span style="color: gray"> </span><span style="color: blue">emp</span>
    <li><span style="color: gray">&nbsp; &nbsp; </span><span style="color: #ffa500">/*----------------------------------</span>
    <li><span style="color: #ffa500">&nbsp; &nbsp; &nbsp; Author:Kevin.yuan</span>
    <li><span style="color: #ffa500">&nbsp; &nbsp; &nbsp; create_time: 2008 -07-01</span>
    <li><span style="color: #ffa500">&nbsp; &nbsp; ---------------------------------- */</span><span style="color: gray">&nbsp;</span>
    <li><span style="color: gray">&nbsp; &nbsp;&nbsp; </span><span style="color: green">BEGIN</span>
    <li><span style="color: gray">&nbsp; &nbsp; &nbsp;&nbsp; </span><span style="color: blue">emp_pkg</span><span style="color: gray">.</span><span style="color: blue">oldRows</span><span style="color: gray"> := </span><span style="color: blue">emp_pkg</span><span style="color: gray">.</span><span style="color: blue">oldEmpty</span><span style="color: gray">;</span>
    <li><span style="color: gray">&nbsp; &nbsp;&nbsp; </span><span style="color: green">END</span><span style="color: gray">&nbsp;</span><span style="color: blue">emp_bd_st</span><span style="color: gray">;</span></li>
</ol>
</div>
<p>&nbsp;&nbsp;&nbsp; 3.创建一个行级trigger:emp_d,问题的核心和关键就在这里,这个trigger<br />
并不参与业务逻辑,只是将触发到的数据载入到emp_pkg.oldRows记录表里面去.</p>
<div class="hl-surround">
<ol class="hl-main ln-show" ondblclick="linenumber(this)" title="Double click to hide line number.">
    <li class="hl-firstline"><span style="color: green">CREATE</span><span style="color: gray"> </span><span style="color: green">OR</span><span style="color: gray"> </span><span style="color: blue">REPLACE</span><span style="color: gray"> </span><span style="color: green">TRIGGER</span><span style="color: gray"> </span><span style="color: blue">emp_d</span><span style="color: gray"> </span><span style="color: green">AFTER</span><span style="color: gray"> </span><span style="color: green">DELETE</span><span style="color: gray"> </span><span style="color: green">ON</span><span style="color: gray"> </span><span style="color: blue">emp</span><span style="color: gray"> </span><span style="color: green">FOR</span><span style="color: gray"> </span><span style="color: green">EACH</span><span style="color: gray"> </span><span style="color: green">ROW</span>
    <li><span style="color: gray">&nbsp; &nbsp; </span><span style="color: #ffa500">/* ----------------------------------</span>
    <li><span style="color: #ffa500">&nbsp; &nbsp; &nbsp;&nbsp; --Author:Kevin.yuan</span>
    <li><span style="color: #ffa500">&nbsp; &nbsp; &nbsp;&nbsp; --create_time: 2008 -07-01</span>
    <li><span style="color: #ffa500">&nbsp; &nbsp; ---------------------------------- */</span><span style="color: gray">&nbsp;</span>
    <li><span style="color: gray">&nbsp; &nbsp; </span><span style="color: green">DECLARE</span>
    <li><span style="color: gray">&nbsp; &nbsp; --</span><span style="color: blue">ct</span><span style="color: gray">&nbsp;</span><span style="color: green">is</span><span style="color: gray"> </span><span style="color: blue">the</span><span style="color: gray"> </span><span style="color: #00008b">position</span><span style="color: gray"> </span><span style="color: green">of</span><span style="color: gray"> </span><span style="color: blue">the</span><span style="color: gray"> </span><span style="color: blue">deleted</span><span style="color: gray"> </span><span style="color: blue">records</span>
    <li><span style="color: gray">&nbsp; &nbsp; </span><span style="color: blue">ct</span><span style="color: gray">&nbsp;</span><span style="color: green">INTEGER</span><span style="color: gray"> := </span><span style="color: blue">emp_pkg</span><span style="color: gray">.</span><span style="color: blue">oldRows</span><span style="color: gray">.</span><span style="color: #00008b">COUNT</span><span style="color: gray"> + </span><span style="color: maroon">1</span><span style="color: gray">; </span>
    <li><span style="color: gray">&nbsp; &nbsp; </span><span style="color: green">BEGIN</span>
    <li><span style="color: gray">&nbsp; &nbsp;&nbsp; </span><span style="color: blue">emp_pkg</span><span style="color: gray">.</span><span style="color: blue">oldRows</span><span style="color: olive">(</span><span style="color: blue">ct</span><span style="color: olive">)</span><span style="color: gray">.</span><span style="color: blue">ename</span><span style="color: gray"> := :</span><span style="color: green">OLD</span><span style="color: gray">.</span><span style="color: blue">ename</span><span style="color: gray">;</span>
    <li><span style="color: gray">&nbsp; &nbsp;&nbsp; </span><span style="color: blue">emp_pkg</span><span style="color: gray">.</span><span style="color: blue">oldRows</span><span style="color: olive">(</span><span style="color: blue">ct</span><span style="color: olive">)</span><span style="color: gray">.</span><span style="color: blue">deptno</span><span style="color: gray"> := :</span><span style="color: green">OLD</span><span style="color: gray">.</span><span style="color: blue">deptno</span><span style="color: gray">;</span>
    <li><span style="color: gray">&nbsp; &nbsp; </span><span style="color: green">END</span><span style="color: gray">&nbsp;</span><span style="color: blue">emp_d</span><span style="color: gray">;</span></li>
</ol>
</div>
<p>&nbsp;&nbsp;&nbsp; 4.创建一个语句级trigger:emp_d_st,前面3步都是为这一步服务的,这一步<br />
真正参与业务逻辑处理.</p>
<div class="hl-surround">
<ol class="hl-main ln-show" ondblclick="linenumber(this)" title="Double click to hide line number.">
    <li class="hl-firstline"><span style="color: green">CREATE</span><span style="color: gray"> </span><span style="color: green">OR</span><span style="color: gray"> </span><span style="color: blue">REPLACE</span><span style="color: gray"> </span><span style="color: green">TRIGGER</span><span style="color: gray"> </span><span style="color: blue">emp_d_st</span><span style="color: gray"> </span><span style="color: green">AFTER</span><span style="color: gray"> </span><span style="color: green">DELETE</span><span style="color: gray"> </span><span style="color: green">ON</span><span style="color: gray"> </span><span style="color: blue">emp</span>
    <li><span style="color: gray">&nbsp; &nbsp; </span><span style="color: #ffa500">/* ----------------------------------</span>
    <li><span style="color: #ffa500">&nbsp; &nbsp; &nbsp;&nbsp; --Author:Kevin.yuan</span>
    <li><span style="color: #ffa500">&nbsp; &nbsp; &nbsp;&nbsp; --create_time: 2008 -07-01</span>
    <li><span style="color: #ffa500">&nbsp; &nbsp;&nbsp; ---------------------------------- */</span><span style="color: gray">&nbsp;</span>
    <li><span style="color: gray">&nbsp; &nbsp; </span><span style="color: green">DECLARE</span>
    <li><span style="color: gray">&nbsp; &nbsp; </span><span style="color: green">BEGIN</span>
    <li><span style="color: gray">&nbsp; &nbsp; </span><span style="color: green">FOR</span><span style="color: gray">&nbsp;</span><span style="color: blue">i</span><span style="color: gray"> </span><span style="color: green">IN</span><span style="color: gray"> </span><span style="color: maroon">1</span><span style="color: gray"> .. </span><span style="color: blue">emp_pkg</span><span style="color: gray">.</span><span style="color: blue">oldRows</span><span style="color: gray">.</span><span style="color: #00008b">COUNT</span><span style="color: gray"> </span><span style="color: blue">LOOP</span>
    <li><span style="color: gray">&nbsp; &nbsp; </span><span style="color: green">INSERT</span><span style="color: gray">&nbsp;</span><span style="color: green">INTO</span><span style="color: gray"> </span><span style="color: blue">emp_log</span>
    <li><span style="color: gray">&nbsp; &nbsp; &nbsp; </span><span style="color: olive">(</span><span style="color: blue">ename</span><span style="color: gray">, </span><span style="color: blue">dname</span><span style="color: gray">, </span><span style="color: blue">dates</span><span style="color: olive">)</span>
    <li><span style="color: gray">&nbsp; &nbsp; &nbsp; </span><span style="color: green">select</span><span style="color: gray">&nbsp;</span><span style="color: blue">emp_pkg</span><span style="color: gray">.</span><span style="color: blue">oldRows</span><span style="color: olive">(</span><span style="color: blue">i</span><span style="color: olive">)</span><span style="color: gray"> .</span><span style="color: blue">ename</span><span style="color: gray">, </span><span style="color: blue">dname</span><span style="color: gray">, </span><span style="color: blue">sysdate</span>
    <li><span style="color: gray">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: green">from</span><span style="color: gray">&nbsp;</span><span style="color: blue">dept</span>
    <li><span style="color: gray">&nbsp; &nbsp; &nbsp;&nbsp; </span><span style="color: green">WHERE</span><span style="color: gray">&nbsp;</span><span style="color: blue">deptno</span><span style="color: gray"> = </span><span style="color: blue">emp_pkg</span><span style="color: gray">.</span><span style="color: blue">oldRows</span><span style="color: olive">(</span><span style="color: blue">i</span><span style="color: olive">)</span><span style="color: gray">.</span><span style="color: blue">deptno</span><span style="color: gray">;</span>
    <li><span style="color: gray">&nbsp; &nbsp; </span><span style="color: green">END</span><span style="color: gray">&nbsp;</span><span style="color: blue">LOOP</span><span style="color: gray">;</span>
    <li><span style="color: gray">&nbsp; &nbsp; </span><span style="color: green">END</span><span style="color: gray">&nbsp;</span><span style="color: blue">emp_d_st</span><span style="color: gray">;</span></li>
</ol>
</div>
<p>&nbsp;&nbsp;&nbsp; 来看一下变通后的触发器是否满足我们的业务要求:</p>
<p>SQL&gt; alter trigger emp_del_trg disable;</p>
<p>Trigger altered</p>
<p>&nbsp;&nbsp;&nbsp; 删除emp数据</p>
<p>SQL&gt; delete from emp where rownum&lt;3;</p>
<p>2 rows deleted</p>
<p>SQL&gt; select * from emp_log;</p>
<p>ENAME DNAME DATES<br />
——————&#8211; ——————&#8211; ———&#8211;<br />
SMITH RESEARCH 2008-7-1 19<br />
ALLEN SALES 2008-7-1 19</p>
<p>SQL&gt; rollback;</p>
<p>Rollback complete</p>
<p>&nbsp;&nbsp;&nbsp; 删除dept数据.</p>
<p>SQL&gt; delete from dept;</p>
<p>4 rows deleted</p>
<p>SQL&gt; select * from emp_log;</p>
<p>ENAME DNAME DATES<br />
——————&#8211; ——————&#8211; ———&#8211;</p>
<p>&nbsp;&nbsp;&nbsp;至此,目的实现.由于用了多于常规数量的触发器,对系统性能会造成一定影响,而且,无疑会加重系统后期业务维护负担,因此,良好的数据库逻辑设计和代码编写思路是很必要的,否则,只能走另外一些路径,不过,这个由行级触发器变语句级别触发器的思路,还是有必要的，当trigger中无法避免的需要access自身表的时候，这无疑是个可以借鉴的解决方案。</p>
<p>&nbsp;&nbsp;&nbsp; THE END;</p>
<br />
<br />
<br />
另外一种方法：<br />
在declare中加入语句PRAGMA AUTONOMOUS_TRANSACTION; <br />
<br />
最后再提交操作方法，此方法的缺点是触发器是一个事务，外<br />
面程序又是一个事务
<img src ="http://www.blogjava.net/caizh2009/aggbug/304717.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-12-04 00:04 <a href="http://www.blogjava.net/caizh2009/articles/304717.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle随机函数 </title><link>http://www.blogjava.net/caizh2009/articles/303161.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Sat, 21 Nov 2009 10:57:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/303161.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/303161.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/303161.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/303161.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/303161.html</trackback:ping><description><![CDATA[<p>Oracle随机函数—dbms_random&nbsp; </p>
<p>1.基础认识</p>
<p>关于这些函数及DBMS_RANDOM包的文件都包含在SQLPlus中：<br />
&nbsp;&nbsp;&nbsp;&nbsp; select text&nbsp;&nbsp; from all_source <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where name = 'DBMS_RANDOM' <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; and type = 'PACKAGE' order by line; </p>
<p>&nbsp;&nbsp; ◆ TYPE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num_array<br />
&nbsp;&nbsp; ◆ PROCEDURE terminate<br />
&nbsp;&nbsp; ◆ PROCEDURE seed<br />
&nbsp;&nbsp; ◆ PROCEDURE initialize<br />
&nbsp;&nbsp; ◆ FUNCTION random<br />
&nbsp;&nbsp; ◆ FUNCTION value RETURN NUMBER; <br />
&nbsp;&nbsp; ◆ FUNCTION value (low IN NUMBER, high IN NUMBER) RETURN NUMBER; <br />
&nbsp;&nbsp; ◆ FUNCTION normal RETURN NUMBER; <br />
&nbsp;&nbsp; ◆ FUNCTION string (opt char, len NUMBER) RETURN VARCHAR2; </p>
<p><br />
2.应用举例</p>
<p>SELECT DBMS_RANDOM.RANDOM FROM DUAL; <br />
&nbsp; <br />
再进一步的要求，比如，产生一个0－100的随机数，稍微变通一下就可以了： <br />
&nbsp; <br />
select abs(mod(dbms_random.random,100)) from dual</p>
<p>3.进阶说明</p>
<p>dbms_random又有新函数了可以实现这些功能 <br />
FUNCTION value RETURN NUMBER; <br />
FUNCTION value (low IN NUMBER, high IN NUMBER) RETURN NUMBER; <br />
FUNCTION normal RETURN NUMBER; <br />
FUNCTION string (opt char, len NUMBER)&nbsp;&nbsp; RETURN VARCHAR2;&nbsp; <br />
&nbsp; <br />
产生N到M之间的随机数 <br />
SELECT&nbsp;&nbsp; DBMS_RANDOM.VALUE(N,M) FROM DUAL; <br />
&nbsp; <br />
缺省DBMS_RANDOM.VALUE返回0到1之间的随机数 </p>
<p>SQL&gt; select dbms_random.value, dbms_random.value(55,100) from dual; <br />
VALUE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DBMS_RANDOM.VALUE(55,100) <br />
--------------- ----------------------------- <br />
0.714469037747011&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 68.5593418279622<br />
&nbsp; <br />
NORMAL函数返回服从正态分布的一组数。此正态分布标准偏差为1，期望值为0。这个函数返回的数值中有68%是介于-1与+1之间，95%介于-2与+2之间，99%介于-3与+3之间。 <br />
最后，是STRING函数。它返回一个长度达60个字符的随机字符串。</p>
<p>用DBMS_RANDOM生成文本和日期值 </p>
<p>数字、文本字符串和日期都是用户会在表格里碰到的三种常见数据类型。虽然你可以用PL／SQL程序包里的DBMS_RANDOM随机生成数字——它确实能够做到这一点——它还能够随机生成文本和日期值。</p>
<p>1.产生随机数字<br />
就让我们先从数字开始。VALUE函数会返回一个大于等于0但是小于1的数，精度是38位。</p>
<p>SELECT DBMS_RANDOM.VALUE FROM DUAL; </p>
<p>对于指定范围内的整数，要加入参数low_value和high_value，并从结果中截取小数（最大值不能被作为可能的值）。所以对于0到99之间的整数，你要使用下面的代码：</p>
<p>SELECT TRUNC(DBMS_RANDOM.VALUE(0, 100)) FROM DUAL;</p>
<p>2.产生随机文本字符串<br />
要随机生成文本字符串，就要使用STRING函数并编写代码指定字符串的类型和所希望的长度：</p>
<p>SELECT DBMS_RANDOM.STRING('A', 20) FROM DUAL; </p>
<p>类型代码在《Oracle Database 10g PL／SQL程序包和类型参考（Oracle Database 10g PL/SQL Packages and Types Reference）》有说明。</p>
<p>下面是一些类型的代码：</p>
<p>&#8216;U&#8217;用来生成大写字符</p>
<p>&#8216;L&#8217;用来生成小写字符</p>
<p>&#8216;A&#8217;用来生成大小写混合的字符</p>
<p>3.产生随机日期<br />
Oracle将日期作为过去某个关键日期（如果你好奇的话，我可以告诉你这个日期是公元前4712年1月1日）的整数偏移量来保存。这就意味着你可以通过寻找与你希望的起始日期相对应的整数，然后向它加入一个随机的整数来随机生成一个指定范围内的日期。</p>
<p>使用TO_CHAR函数和&#8216;J&#8217;格式代码，你可以为今天的日期生成一个内部日期数：</p>
<p>SELECT TO_CHAR(SYSDATE, 'J') FROM DUAL; </p>
<p>例如，要生成一个2003年内的任意日期，你可以首先确定2003年1月1日的日期整数；</p>
<p>SELECT TO_CHAR(TO_DATE('01/01/03','mm/dd/yy'),'J')FROM DUAL; </p>
<p>系统给的结果是2452641。所以要生成该年度内的任意日期，我们就要用带有low_value等于2452641和high_value等于2452641+364参数的DBMS_RANDOM.VALUE，再把它转换成日期：</p>
<p>SELECT TO_DATE(TRUNC(DBMS_RANDOM.VALUE(2452641,2452641+364)),'J') FROM DUAL;<br />
&nbsp;</p>
<p><br />
本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/luojun198610/archive/2009/02/27/3941491.aspx</p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/303161.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-11-21 18:57 <a href="http://www.blogjava.net/caizh2009/articles/303161.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle的rank,over partition涵数使用</title><link>http://www.blogjava.net/caizh2009/articles/301678.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Mon, 09 Nov 2009 04:16:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/301678.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/301678.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/301678.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/301678.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/301678.html</trackback:ping><description><![CDATA[<strong>关键字: 涵数<span class="hilite2">rank</span>, <span class="hilite3">over</span> partition使用</strong>
<div class="blog_content">
<p>排列（<span class="hilite2">rank</span>()）函数。这些排列函数提供了定义一个集合（使用 PARTITION 子句），然后根据某种排序方式对这个集合内的元素进行排列的能力，下面以scott用户的emp表为例来说明<span class="hilite2">rank</span> <span class="hilite3">over</span> partition如何使用</p>
<p>&nbsp;</p>
<p>1）查询员工薪水并连续求和</p>
<p>select deptno,ename,sal,</p>
<p>sum(sal)<span class="hilite3">over</span>(order by ename) sum1,&nbsp; /*表示连续求和*/<br />
sum(sal)<span class="hilite3">over</span>() sum2,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*相当于求和sum(sal)*/<br />
100* round(sal/sum(sal)<span class="hilite3">over</span>(),4) "bal%"<br />
from emp</p>
<p>结果如下：</p>
<p>&nbsp;&nbsp;&nbsp; DEPTNO ENAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SAL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bal%<br />
---------- ---------- ---------- ---------- ---------- ----------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20 ADAMS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 29025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.79<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 ALLEN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1600&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2700&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 29025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5.51<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 BLAKE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2850&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5550&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 29025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9.82<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10 CLARK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2450&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 29025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8.44<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20 FORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 11000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 29025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10.34<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 JAMES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 950&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 11950&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 29025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.27<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20 JONES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2975&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 14925&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 29025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10.25<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10 KING&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 19925&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 29025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 17.23<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 MARTIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1250&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 21175&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 29025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.31<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10 MILLER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1300&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 22475&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 29025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.48<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20 SCOTT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 25475&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 29025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10.34</p>
<p>&nbsp;&nbsp;&nbsp; DEPTNO ENAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SAL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bal%<br />
---------- ---------- ---------- ---------- ---------- ----------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20 SMITH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 800&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 26275&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 29025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.76<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 TURNER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1500&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 27775&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 29025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5.17<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 WARD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1250&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 29025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 29025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.31</p>
<p>&nbsp;</p>
<p>2）如下：</p>
<p>select deptno,ename,sal,<br />
sum(sal)<span class="hilite3">over</span>(partition by deptno order by ename) sum1,/*表示按部门号分氏，按姓名排序并连续求和*/<br />
sum(sal)<span class="hilite3">over</span>(partition by deptno) sum2,/*表示部门分区，求和*/<br />
sum(sal)<span class="hilite3">over</span>(partition by deptno order by sal) sum3,/*按部门分区，按薪水排序并连续求和*/<br />
100* round(sal/sum(sal)<span class="hilite3">over</span>(),4) "bal%"<br />
from emp</p>
<p>结果如下：</p>
<p>&nbsp;&nbsp;&nbsp; DEPTNO ENAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SAL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bal%<br />
---------- ---------- ---------- ---------- ---------- ---------- ----------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10 CLARK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2450&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2450&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8750&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3750&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8.44<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10 KING&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7450&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8750&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8750&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 17.23<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10 MILLER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1300&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8750&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8750&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1300&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.48<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20 ADAMS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10875&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1900&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.79<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20 FORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10875&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10875&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10.34<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20 JONES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2975&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7075&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10875&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4875&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10.25<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20 SCOTT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10075&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10875&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10875&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10.34<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20 SMITH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 800&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10875&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10875&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 800&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.76<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 ALLEN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1600&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1600&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9400&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6550&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5.51<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 BLAKE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2850&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4450&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9400&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9400&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9.82<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 JAMES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 950&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5400&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9400&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 950&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.27</p>
<p>&nbsp;&nbsp;&nbsp; DEPTNO ENAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SAL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bal%<br />
---------- ---------- ---------- ---------- ---------- ---------- ----------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 MARTIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1250&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6650&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9400&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3450&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.31<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 TURNER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1500&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8150&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9400&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4950&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5.17<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 WARD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1250&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9400&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9400&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3450&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.31</p>
<p>&nbsp;</p>
<p>3）如下：</p>
<p>select empno,deptno,sal,<br />
sum(sal)<span class="hilite3">over</span>(partition by deptno) "deptSum",/*按部门分区，并求和*/<br />
<span class="hilite2">rank</span>()<span class="hilite3">over</span>(partition by deptno order by sal desc nulls last)&nbsp; <span class="hilite2">rank</span>, /*按部门分区，按薪水排序并计算序号*/<br />
dense_rank()<span class="hilite3">over</span>(partition by deptno order by sal desc nulls last) d_rank,<br />
row_number()<span class="hilite3">over</span>(partition by deptno order by sal desc nulls last) row_rank<br />
from emp</p>
<p>注：</p>
<p>rang()涵数主要用于排序，并给出序号</p>
<p>dense_rank()：功能同<span class="hilite2">rank</span>()一样，区别在于，<span class="hilite2">rank</span>()对于排序并的数据给予相同序号，接下来的数据序号直接跳中跃，dense_rank()则不是，比如数据：1，2，2，4，5，6.。。。。这是<span class="hilite2">rank</span>()的形式</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1，2，2，3，4，5，。。。。这是dense_rank()的形式</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1，2，3，4，5，6.。。。。。这是row_number()涵数形式</p>
<p>row_number()涵数则是按照顺序依次使用，相当于我们普通查询里的rownum值</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>其实从上面三个例子当中，不难看出<span class="hilite3">over</span>(partition by ... order by ...)的整体概念，我理解是</p>
<p>partition by :按照指字的字段分区，如果没有则针对全体数据</p>
<p>order by&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :按照指定字段进行连续操作（如求和(sum),排序(<span class="hilite2">rank</span>()等)，如果没有指定，就相当于对指定分区集合内的数据进行整体sum操作</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
</div>
<img src ="http://www.blogjava.net/caizh2009/aggbug/301678.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-11-09 12:16 <a href="http://www.blogjava.net/caizh2009/articles/301678.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ORACLE查询树型关系（connect by prior start with）</title><link>http://www.blogjava.net/caizh2009/articles/295565.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Fri, 18 Sep 2009 05:47:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/295565.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/295565.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/295565.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/295565.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/295565.html</trackback:ping><description><![CDATA[<p><a class="postTitle2" id="ctl04_TitleUrl" href="http://www.cnblogs.com/ZHF/archive/2008/09/10/1288101.html">Oracle中start with...connect by prior子句用法</a><br />
<p>connect by 是结构化查询中用到的，其基本语法是： <br />
select ... from tablename start with&nbsp;条件1 <br />
connect by&nbsp;条件2 <br />
where 条件3;</p>
<p>例：</p>
<p>select * from table<br />
start with <font face="Verdana">org_id = 'HBHqfWGWPy'</font><br />
connect by <font face="Verdana">prior org_id = parent_id;</font></p>
<p>&nbsp;</p>
<p>简单说来是将一个树状结构存储在一张表里，比如一个表中存在两个字段: <br />
org_id,parent_id那么通过表示每一条记录的parent是谁，就可以形成一个树状结构。 <br />
用上述语法的查询可以取得这棵树的所有记录。 <br />
其中：</p>
<p>条件1 是根结点的限定语句，当然可以放宽限定条件，以取得多个根结点，实际就是多棵树。 <br />
条件2 是连接条件，其中用PRIOR表示上一条记录，比如 CONNECT BY PRIOR org_id = parent_id就是说上一条记录的org_id 是本条记录的parent_id，即本记录的父亲是上一条记录。 <br />
条件3 是过滤条件，用于对返回的所有记录进行过滤。</p>
<p>&nbsp;</p>
<p>简单介绍如下：</p>
<p><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">早扫描树结构表时，需要依此访问树结构的每个节点，一个节点只能访问一次，其访问的步骤如下：</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">第一步：从根节点开始；</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">第二步：访问该节点；</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">第三步：判断该节点有无未被访问的子节点，若有，则转向它最左侧的未被访问的子节，并执行第二步，否则执行第四步；</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">第四步：若该节点为根节点，则访问完毕，否则执行第五步；</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">第五步：返回到该节点的父节点，并执行第三步骤。</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
<br />
</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">总之：扫描整个树结构的过程也即是中序遍历树的过程。</span></p>
<p>&nbsp;</p>
<p><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">1<span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"> </span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">树结构的描述</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">树结构的数据存放在表中，数据之间的层次关系即父子关系，通过表中的列与列间的关系来描述，如</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">EMP</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">表中的</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">EMPNO</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">MGR</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">EMPNO</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">表示该雇员的编号，</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">MGR</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">表示领导该雇员的人的编号，即子节点的</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">MGR</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">值等于父节点的</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">EMPNO</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">值。在表的每一行中都有一个表示父节点的</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">MGR</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">（除根节点外），通过每个节点的父节点，就可以确定整个树结构。</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">SELECT</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">命令中使用</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">CONNECT BY </span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和蔼</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">START WITH </span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">子句可以查询表中的树型结构关系。其命令格式如下：</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
SELECT </span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。。。</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
CONNECT BY {PRIOR </span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">列名</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">1=</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">列名</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">2|</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">列名</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">1=PRIOR </span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">裂名</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">2}<br />
[START WITH]</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">；</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">其中：</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">CONNECT BY</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">子句说明每行数据将是按层次顺序检索，并规定将表中的数据连入树型结构的关系中。</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">PRIORY</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">运算符必须放置在连接关系的两列中某一个的前面。对于节点间的父子关系，</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">PRIOR</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">运算符在一侧表示父节点，在另一侧表示子节点，从而确定查找树结构是的顺序是自顶向下还是自底向上。在连接关系中，除了可以使用列名外，还允许使用列表达式。</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">START WITH </span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">子句为可选项，用来标识哪个节点作为查找树型结构的根节点。若该子句被省略，则表示所有满足查询条件的行作为根节点。</span></span></p>
<p><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">START WITH： <span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">不但可以指定一个根节点，还可以指定多个根节点。</span><br />
</span>2<span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"> </span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">关于</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">PRIOR<br />
</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">运算符</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">PRIOR</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">被放置于等号前后的位置，决定着查询时的检索顺序。</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
PRIOR</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">被置于</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">CONNECT BY</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">子句中等号的前面时，则强制从根节点到叶节点的顺序检索，即由父节点向子节点方向通过树结构，我们称之为自顶向下的方式。如：</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
CONNECT BY PRIOR EMPNO=MGR<br />
PIROR</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">运算符被置于</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">CONNECT BY </span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">子句中等号的后面时，则强制从叶节点到根节点的顺序检索，即由子节点向父节点方向通过树结构，我们称之为自底向上的方式。例如：</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
CONNECT BY EMPNO=PRIOR MGR<br />
</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在这种方式中也应指定一个开始的节点。</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
3<span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"> </span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">定义查找起始节点</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在自顶向下查询树结构时，不但可以从根节点开始，还可以定义任何节点为起始节点，以此开始向下查找。这样查找的结果就是以该节点为开始的结构树的一枝。</span></span></span></p>
<p><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">4<span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．使用</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">LEVEL<br />
</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在具有树结构的表中，每一行数据都是树结构中的一个节点，由于节点所处的层次位置不同，所以每行记录都可以有一个层号。层号根据节点与根节点的距离确定。不论从哪个节点开始，该起始根节点的层号始终为</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">1</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，根节点的子节点为</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">2</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"> </span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">依此类推。图</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">1.2</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">就表示了树结构的层次。</span></span></span></span></p>
<p><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">5<span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．节点和分支的裁剪</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在对树结构进行查询时，可以去掉表中的某些行，也可以剪掉树中的一个分支，使用</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">WHERE</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">子句来限定树型结构中的单个节点，以去掉树中的单个节点，但它却不影响其后代节点（自顶向下检索时）或前辈节点（自底向顶检索时）。</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
</span>6<span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．排序显示</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><br />
</span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">象在其它查询中一样，在树结构查询中也可以使用</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">ORDER BY </span><span style="font-size: 10.5pt; font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">子句，改变查询结果的显示顺序，而不必按照遍历树结构的顺序。</span><br />
</p>
<p></span></span>&nbsp;
<p><br />
</p>
<p></span>&nbsp;
<div id="MySignature">
<p><span style="font-size: 12pt; color: #0000ff; background-color: #ff6600"><span style="background-color: #333399"><span style="background-color: #333399"><span style="background-color: #339966"><span style="background-color: #339966"><span style="background-color: #99cc00"><span style="background-color: #99cc00">如需转载请加入本人Blog地址&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></span></span></span></span></span></p>
<p><span style="font-size: 12pt; color: #333399; background-color: #ff6600"><a style="font-size: 14pt; font-family: 宋体" href="http://zhf.cnblogs.com/"><span style="background-color: #333399"><span style="background-color: #333399"><span style="background-color: #339966"><span style="background-color: #339966"><span style="background-color: #99cc00"><span style="background-color: #99cc00">http://zhf.cnblogs.com/</span></span></span></span></span></span></a><a style="font-size: 14pt; font-family: 宋体" href="http://zhf.cnblogs.com/"><span style="background-color: #333399"><span style="background-color: #339966"><span style="background-color: #99cc00"> </span></span></span></span></a></p>
</div>
 <img src ="http://www.blogjava.net/caizh2009/aggbug/295565.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-09-18 13:47 <a href="http://www.blogjava.net/caizh2009/articles/295565.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle_学习使用SQL语五(统计分组语句)</title><link>http://www.blogjava.net/caizh2009/articles/291996.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 20 Aug 2009 12:30:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/291996.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/291996.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/291996.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/291996.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/291996.html</trackback:ping><description><![CDATA[<h3 class="type_original" title="原创"><a href="http://shawnfree.javaeye.com/blog/357375">Oracle_学习使用SQL语五(统计分组语句)</a></h3>
<div class="blog_content">&nbsp;&nbsp; 在应用系统开发中，进行需要统计数据库中的数据，当执行数据统计时，需要将表中的数据进行分组显示，在统计分组中是通过group by子句、分组函数、having子句共同实现的。其中group by子句用于指定要分组的列，而分组函数用户指定显示统计的结果，而having子句用户限制显示分组结果。 <br />
&nbsp;&nbsp; <strong>一、分组函数</strong> <br />
&nbsp;&nbsp; 分组函数用于统计表的数据，并作用于多行，但是返回一个结果，一般情况下，分组函数要与group by子句结合使用，Oracle数据库提供了大量的分组函数，常用的五个分组函数： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357375#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>Max：该函数用于取得列或表达式的最大值，适用于任何数据类型。 &nbsp;&nbsp;</span></span></li>
    <li><span>Min：该函数用于取得列或表达式的最小值，适用于任何数据类型。 &nbsp;&nbsp;</span></li>
    <li><span>Avg：该函数用于取得列或表达式的平均值，适用于数字类型。 &nbsp;&nbsp;</span></li>
    <li><span>Sum：该函数用于取得列或表达式的总和，&nbsp;&nbsp;适用于数字类型。 &nbsp;&nbsp;</span></li>
    <li><span>Count：该函数用于取的行数总和。&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">   Max：该函数用于取得列或表达式的最大值，适用于任何数据类型。
Min：该函数用于取得列或表达式的最小值，适用于任何数据类型。
Avg：该函数用于取得列或表达式的平均值，适用于数字类型。
Sum：该函数用于取得列或表达式的总和，  适用于数字类型。
Count：该函数用于取的行数总和。
</pre>
<br />
<span style="color: red"><br />
注意： <br />
1、当使用分组函数时,分组函数只能出现在选择列表、order by和having子句中，而不能出现在where、group by子句中。 <br />
2、当使用分组函数时，除了函数count(*)外，其他分组函数都会忽略NULL行。 <br />
3、当执行select语句时,如果选择列表同时包括列、表达式和分组函数,那么这些列、表达式必须出现在group by子句中。 <br />
4、当使用分组函数时，在分组函数中可以指定all和distinct选项，其中all是默认选项，该选项表示统计所有行数据(包括重复行),distinc可以统计不同行数据。 <br />
</span><br />
示例如下： <br />
1、取得某列最小值、最大值、平均值、总和和总计行数 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357375#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>select&nbsp;max(id)&nbsp;as&nbsp;max_id,min(id)&nbsp;as&nbsp;min_id,avg(id)&nbsp;as&nbsp;avg_id,sum(id)&nbsp;as&nbsp;sum_id,count(*)&nbsp;as&nbsp;count&nbsp;from&nbsp;cip_temps;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">select max(id) as max_id,min(id) as min_id,avg(id) as avg_id,sum(id) as sum_id,count(*) as count from cip_temps;
</pre>
<br />
2、去除重复值 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357375#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>select&nbsp;count(distinct&nbsp;id)&nbsp;from&nbsp;cip_temps;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">select count(distinct id) from cip_temps;
</pre>
<br />
<strong>二、group by和having子句</strong> <br />
&nbsp;&nbsp; group by子句是对统计的结果进行分组统计，而having子句用于限制分组显示结果，语法如下： <br />
<span style="color: red">select column，group_function from table [where condition][group by group_by_experssion][having group_function];</span>如上所示，column用于指定列表中的列或表达式，group_function用于指定分组函数，condition用于指定条件子句，group_by_experssion用于指定分组表达式，group_function用于指定排除分组结果条件。 <br />
1、使用group by进行单列分组，如下： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357375#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>select&nbsp;id&nbsp;as&nbsp;id,min(age)&nbsp;max_age,max(age)&nbsp;max_age&nbsp;from&nbsp;cip_temps&nbsp;group&nbsp;by&nbsp;id;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">select id as id,min(age) max_age,max(age) max_age from cip_temps group by id;
</pre>
<br />
2、使用having子句限制分组显示结果，如下： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357375#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>select&nbsp;id&nbsp;as&nbsp;id,count(age)&nbsp;count&nbsp;from&nbsp;cip_temps&nbsp;group&nbsp;by&nbsp;id&nbsp;having&nbsp;count(age)=</span><span class="number">2</span><span>;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">select id as id,count(age) count from cip_temps group by id having count(age)=2;
</pre>
<br />
<strong>三、case表达式</strong> <br />
case格式如下： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357375#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>case&nbsp;when&nbsp;条件&nbsp;then&nbsp;返回值</span><span class="number">1</span><span>&nbsp;when&nbsp;条件</span><span class="number">2</span><span>&nbsp;then&nbsp;返回值</span><span class="number">2</span><span>&nbsp;else&nbsp;返回值</span><span class="number">3</span><span>&nbsp;end&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">case when 条件 then 返回值1 when 条件2 then 返回值2 else 返回值3 end</pre>
<br />
示例如下： <br />
<span style="color: red">select name,age,address,case when id=21 then 'abc' when id=22 then 'def' else 'hij' end alias from cip_temps;</span> <br />
<strong>四、Oracle常用统计函数</strong> <br />
1、数字函数 <br />
&nbsp; (1)、mod(m,n)该函数用于返回取得两个数字相除后的余数，如果数字为0，则返回结果为m。 <br />
&nbsp; (2)、round(n,[m]该函数用于取得四舍五入运算，如果省略m，则四舍五入至整数位；如果m是负数，则四舍五入到小数点前m位；如果m是正数，则四舍五入到小数点后m位。 <br />
&nbsp; (3)、trunc(n,[m])该函数用于截取数字，如果省略m，则将数字n的小数部门截取；如果m为正数，则将数字n截取至小数点后的第m位，如果m为负数，则将数字n截取小数点的前m为。 <br />
示例如下： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357375#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>select&nbsp;mod(</span><span class="number">10</span><span>,</span><span class="number">4</span><span>)&nbsp;from&nbsp;dual; &nbsp;&nbsp;</span></span></li>
    <li><span>select&nbsp;round(</span><span class="number">101234.567</span><span>,-</span><span class="number">4</span><span>)&nbsp;from&nbsp;dual; &nbsp;&nbsp;</span></span></li>
    <li><span>select&nbsp;round(</span><span class="number">101.234567</span><span>,</span><span class="number">4</span><span>)&nbsp;from&nbsp;dual; &nbsp;&nbsp;</span></span></li>
    <li><span>select&nbsp;trunc(</span><span class="number">101234.457</span><span>,</span><span class="number">2</span><span>)&nbsp;from&nbsp;dual; &nbsp;&nbsp;</span></span></li>
    <li><span>select&nbsp;trunc(</span><span class="number">101234.457</span><span>,-</span><span class="number">2</span><span>)&nbsp;from&nbsp;dual;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">select mod(10,4) from dual;
select round(101234.567,-4) from dual;
select round(101.234567,4) from dual;
select trunc(101234.457,2) from dual;
select trunc(101234.457,-2) from dual;
</pre>
<br />
2、日期函数 <br />
&nbsp;&nbsp; (1)、round(d,[fmt])该函数用于返回日期时间的四舍五入结果，如果fmt指定年度，则7月1日为分割线；如果fmt指定月，则16日为分割线；如果fmt指定为天，则中午12:00为分割线。 <br />
&nbsp;&nbsp; (2)、trunc(d,[fmt])该函数用于截取日期时间数据，如果fmt指定年度，则结果为本年度的1月1日，如果fmt指定月，则结果为本月1日。 <br />
示例如下： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357375#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>select&nbsp;round(sysdate,</span><span class="string">'yyyy'</span><span>)&nbsp;from&nbsp;dual; &nbsp;&nbsp;</span></span></li>
    <li><span>select&nbsp;round(sysdate,</span><span class="string">'mm'</span><span>)&nbsp;from&nbsp;dual; &nbsp;&nbsp;</span></span></li>
    <li><span>select&nbsp;round(sysdate,</span><span class="string">'dd'</span><span>)&nbsp;from&nbsp;dual; &nbsp;&nbsp;</span></span></li>
    <li><span>select&nbsp;trunc(sysdate,</span><span class="string">'yyyy'</span><span>)&nbsp;from&nbsp;dual; &nbsp;&nbsp;</span></span></li>
    <li><span>select&nbsp;trunc(sysdate,</span><span class="string">'mm'</span><span>)&nbsp;from&nbsp;dual; &nbsp;&nbsp;</span></span></li>
    <li><span>select&nbsp;trunc(sysdate,</span><span class="string">'dd'</span><span>)&nbsp;from&nbsp;dual;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">select round(sysdate,'yyyy') from dual;
select round(sysdate,'mm') from dual;
select round(sysdate,'dd') from dual;
select trunc(sysdate,'yyyy') from dual;
select trunc(sysdate,'mm') from dual;
select trunc(sysdate,'dd') from dual;
</pre>
<br />
&nbsp; 3、转换函数 <br />
&nbsp;&nbsp;&nbsp; (1)、to_char(date,fmt)该函数用于将日期类型转换为字符串类型，其中fmt用于指定日期格式。 <br />
&nbsp;&nbsp;&nbsp; (2)、to_date(char,fmt)该函数用于将符合特定日期格式的字符串转变为date类型的值。 <br />
&nbsp;&nbsp;&nbsp; (3)、to_number(char)该函数用于将符合特定数字格式的字符串转换为数字类型。 <br />
示例如下： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357375#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>select&nbsp;to_date(</span><span class="string">'2009-3-1'</span><span>,</span><span class="string">'yyyy-mm-dd'</span><span>)&nbsp;from&nbsp;dual; &nbsp;&nbsp;</span></span></li>
    <li><span>select&nbsp;to_char(sysdate,</span><span class="string">'YYYY-MM-DD&nbsp;HH24:MI:SS'</span><span>)&nbsp;from&nbsp;dual; &nbsp;&nbsp;</span></span></li>
    <li><span>select&nbsp;to_number(</span><span class="string">'10.123'</span><span>)&nbsp;from&nbsp;dual;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">select to_date('2009-3-1','yyyy-mm-dd') from dual;
select to_char(sysdate,'YYYY-MM-DD HH24:MI:SS') from dual;
select to_number('10.123') from dual;
</pre>
<br />
4、其他单行函数 <br />
&nbsp;&nbsp;&nbsp; (1)、decode(expr,search1,result1[,search2,result2,...],default)该函数用于返回匹配于特定表达式结果，如果search1匹配与expr，则返回结果result1，如果search2匹配expr，则返回结果result2，以此类推，如果没有任何匹配关系，则返回默认default。 <br />
示例如下： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357375#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>select&nbsp;name,decode(age,</span><span class="string">'bb21'</span><span>,id*</span><span class="number">10</span><span>,</span><span class="string">'bb22'</span><span>,id*</span><span class="number">20</span><span>,</span><span class="number">1000</span><span>)&nbsp;as&nbsp;decodee&nbsp;from&nbsp;cip_temps;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">select name,decode(age,'bb21',id*10,'bb22',id*20,1000) as decodee from cip_temps;
</pre>
<br />
注意：decode函数和case表达式的用法基本相似，但是case表达式可以多个条件进行判断，从而返回结果。 <br />
示例如下： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357375#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>select&nbsp;name,case&nbsp;when&nbsp;( &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(age=</span><span class="string">'bb21'</span><span>&nbsp;and&nbsp;address=</span><span class="string">'cc21'</span><span>)&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;or&nbsp;(age=</span><span class="string">'bb22'</span><span>&nbsp;and&nbsp;address=</span><span class="string">'cc22'</span><span>)&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;or&nbsp;(age=</span><span class="string">'bb23'</span><span>&nbsp;and&nbsp;address=</span><span class="string">'cc23'</span><span>)&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)&nbsp;then&nbsp;</span><span class="number">1</span><span>&nbsp;else&nbsp;</span><span class="number">0</span><span>&nbsp;end&nbsp;as&nbsp;cases&nbsp;from&nbsp;cip_temps&nbsp;&nbsp;</span></span></li>
</ol>
</div>
</div>
<img src ="http://www.blogjava.net/caizh2009/aggbug/291996.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-08-20 20:30 <a href="http://www.blogjava.net/caizh2009/articles/291996.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle_学习使用控制结构</title><link>http://www.blogjava.net/caizh2009/articles/291995.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 20 Aug 2009 12:29:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/291995.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/291995.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/291995.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/291995.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/291995.html</trackback:ping><description><![CDATA[<div class="blog_content"><strong>一、条件分支语句</strong> <br />
条件分支语句用于依据特定的情况选择要执行的操作，PL/SQL提供了三种条件分支语句：if-then， if-then-else，if-then-elsif。 <br />
语法如下： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357790#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>if&nbsp;conditions&nbsp;then &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;statements; &nbsp;&nbsp;</span></li>
    <li><span>[elseif&nbsp;conditions&nbsp;then&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;statements;] &nbsp;&nbsp;</span></li>
    <li><span>[else&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;statements;] &nbsp;&nbsp;</span></li>
    <li><span>end&nbsp;if;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">if conditions then
statements;
[elseif conditions then
statements;]
[else
statements;]
end if;</pre>
<br />
&nbsp;&nbsp; <strong>1、if-then示例</strong> <br />
&nbsp;&nbsp;&nbsp; 用于执行单一条件判断，如果满足特定条件则会执行相应操作，如果不满足特定条件则退出条件分支语句。 <br />
&nbsp;&nbsp;
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357790#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;declare &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;v_count&nbsp;number; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;begin &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;select&nbsp;count(*)&nbsp;into&nbsp;v_count&nbsp;from&nbsp;cip_temps; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;if(v_count&gt;</span><span class="number">0</span><span>)&nbsp;then &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;dbms_output.put_line(</span><span class="string">'v_cont的值:'</span><span>||&nbsp;v_count); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;end&nbsp;if; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;end; &nbsp;&nbsp;</span></li>
    <li><span>/ &nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">
declare
v_count number;
begin
select count(*) into v_count from cip_temps;
if(v_count&gt;0) then
dbms_output.put_line('v_cont的值:'|| v_count);
end if;
end;
/
</pre>
<br />
&nbsp;&nbsp;&nbsp; <strong>2、if-then-else示例</strong> <br />
&nbsp;&nbsp;&nbsp;&nbsp; 用于执行二重条件判断，如果满足特定条件则执行一组操作，如果不满足则执行另一组操作。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357790#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>&nbsp;declare &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;v_count&nbsp;number; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;begin &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;select&nbsp;count(*)&nbsp;into&nbsp;v_count&nbsp;from&nbsp;cip_temps; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(v_count&gt;</span><span class="number">11</span><span>)&nbsp;then &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;dbms_output.put_line(</span><span class="string">'v_cont的值:'</span><span>||&nbsp;v_count); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dbms_output.put_line(</span><span class="string">'v_count的值:'</span><span>||&nbsp;v_count); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;end&nbsp;if; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;end; &nbsp;&nbsp;</span></li>
    <li><span>/ &nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">      declare
v_count number;
begin
select count(*) into v_count from cip_temps;
if(v_count&gt;11) then
dbms_output.put_line('v_cont的值:'|| v_count);
else
dbms_output.put_line('v_count的值:'|| v_count);
end if;
end;
/
</pre>
<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <strong>3、if-then-elsif示例</strong> <br />
&nbsp;&nbsp;&nbsp;&nbsp; 用于执行多重条件判断，如果满足特定条件1则执行第一组操作，如果满足特定条件2则执行第二组操作，以此类推，如果都不满足特定条件则执行不满足条件的操作。 <br />
&nbsp;&nbsp;&nbsp;
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357790#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>declare &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;v_count&nbsp;number; &nbsp;&nbsp;</span></li>
    <li><span>begin &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;select&nbsp;count(*)&nbsp;into&nbsp;v_count&nbsp;from&nbsp;cip_temps; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;if(v_count&gt;</span><span class="number">10</span><span>)&nbsp;then &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;dbms_output.put_line(</span><span class="string">'if操作___v_cont的值:'</span><span>||&nbsp;v_count); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;elsif&nbsp;(v_count=</span><span class="number">10</span><span>)&nbsp;then &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;dbms_output.put_line(</span><span class="string">'elsif操作____v_count的值:'</span><span>||&nbsp;v_count); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;else &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;dbms_output.put_line(</span><span class="string">'else操作____v_cout的值:'</span><span>||v_count); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;end&nbsp;if; &nbsp;&nbsp;</span></li>
    <li><span>end; &nbsp;&nbsp;</span></li>
    <li><span>/&nbsp; &nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">
declare
v_count number;
begin
select count(*) into v_count from cip_temps;
if(v_count&gt;10) then
dbms_output.put_line('if操作___v_cont的值:'|| v_count);
elsif (v_count=10) then
dbms_output.put_line('elsif操作____v_count的值:'|| v_count);
else
dbms_output.put_line('else操作____v_cout的值:'||v_count);
end if;
end;
/
</pre>
<br />
<strong>二、case语句</strong> <br />
当执行多重条件分支语句时，使用case语句更加简洁、而且效率也更好。case语句处理多重条件分支语句有两种方法，第一种方法是使用单一选择符进行等值比较。第二种方法是使用多种条件进行非等值比较。 <br />
&nbsp;&nbsp; 1、使用单一选择符进行等值比较 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当执行case语句执行多重条件分支时，如果条件选择符完全相同，并且条件表达式为相同条件选择，那么可以选择单一选择符进行等值比较，语法如下： <br />
&nbsp;&nbsp;
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357790#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>case&nbsp;&nbsp;条件选择符 &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;when&nbsp;&nbsp;&nbsp;条件值表达式</span><span class="number">1</span><span>&nbsp;then&nbsp;要执行的操作</span><span class="number">1</span><span>； &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;when&nbsp;&nbsp;&nbsp;条件值表达式</span><span class="number">2</span><span>&nbsp;then&nbsp;要执行的操作</span><span class="number">2</span><span>； &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;。。。。。。。 &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;else&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;要执行的操作。 &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;end&nbsp;case; &nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">   case  条件选择符
when   条件值表达式1 then 要执行的操作1；
when   条件值表达式2 then 要执行的操作2；
。。。。。。。
else
要执行的操作。
end case;
</pre>
<br />
&nbsp; 示例如下： <br />
&nbsp;&nbsp;&nbsp;
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357790#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>declare &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;v_count&nbsp;number; &nbsp;&nbsp;</span></li>
    <li><span>begi &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;select&nbsp;count(*)&nbsp;into&nbsp;v_count&nbsp;from&nbsp;cip_temps; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;case&nbsp;v_count &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;when&nbsp;</span><span class="number">1</span><span>&nbsp;then &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dbms_output.put_line(</span><span class="string">'when&nbsp;1操作___v_cont的值:'</span><span>||&nbsp;v_count); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;when&nbsp;</span><span class="number">5</span><span>&nbsp;then &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dbms_output.put_line(</span><span class="string">'when&nbsp;5操作___v_count的值:'</span><span>||&nbsp;v_count); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;when&nbsp;</span><span class="number">10</span><span>&nbsp;then &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dbms_output.put_line(</span><span class="string">'when&nbsp;10操作____v_count的值:'</span><span>||&nbsp;v_count); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;else &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;dbms_output.put_line(</span><span class="string">'else操作____v_cout的值:'</span><span>||v_count); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;end&nbsp;case; &nbsp;&nbsp;</span></li>
    <li><span>end; &nbsp;&nbsp;</span></li>
    <li><span>/&nbsp; &nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">    declare
v_count number;
begi
select count(*) into v_count from cip_temps;
case v_count
when 1 then
dbms_output.put_line('when 1操作___v_cont的值:'|| v_count);
when 5 then
dbms_output.put_line('when 5操作___v_count的值:'|| v_count);
when 10 then
dbms_output.put_line('when 10操作____v_count的值:'|| v_count);
else
dbms_output.put_line('else操作____v_cout的值:'||v_count);
end case;
end;
/
</pre>
<br />
&nbsp;&nbsp; 2、case使用多种条件进行比较 <br />
&nbsp;&nbsp; 如果选择多个条件进行不同比较时，那么必须在when子句中指定比较条件，语法如下： <br />
&nbsp;&nbsp;&nbsp;&nbsp;
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357790#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>case&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;when&nbsp;&nbsp;&nbsp;条件值表达式</span><span class="number">1</span><span>&nbsp;then&nbsp;要执行的操作</span><span class="number">1</span><span>； &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;when&nbsp;&nbsp;&nbsp;条件值表达式</span><span class="number">2</span><span>&nbsp;then&nbsp;要执行的操作</span><span class="number">2</span><span>； &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;。。。。。。。 &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;else&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;要执行的操作。 &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;end&nbsp;case; &nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">   case
when   条件值表达式1 then 要执行的操作1；
when   条件值表达式2 then 要执行的操作2；
。。。。。。。
else
要执行的操作。
end case;
</pre>
<br />
&nbsp; 示例如下： <br />
&nbsp;&nbsp;
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357790#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>declare &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;v_count&nbsp;number; &nbsp;&nbsp;</span></li>
    <li><span>begin &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;select&nbsp;count(*)&nbsp;into&nbsp;v_count&nbsp;from&nbsp;cip_temps; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;case&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;when&nbsp;v_count&gt;</span><span class="number">10</span><span>&nbsp;then &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dbms_output.put_line(</span><span class="string">'when&nbsp;1操作___v_cont的值:'</span><span>||&nbsp;v_count); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;when&nbsp;v_count&gt;</span><span class="number">5</span><span>&nbsp;then &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dbms_output.put_line(</span><span class="string">'when&nbsp;5操作___v_count的值:'</span><span>||&nbsp;v_count); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;when&nbsp;v_count&gt;</span><span class="number">4</span><span>&nbsp;then &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dbms_output.put_line(</span><span class="string">'when&nbsp;10操作____v_count的值:'</span><span>||&nbsp;v_count); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;dbms_output.put_line(</span><span class="string">'else操作____v_cout的值:'</span><span>||v_count); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;end&nbsp;case; &nbsp;&nbsp;</span></li>
    <li><span>end; &nbsp;&nbsp;</span></li>
    <li><span>/&nbsp; &nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">    declare
v_count number;
begin
select count(*) into v_count from cip_temps;
case
when v_count&gt;10 then
dbms_output.put_line('when 1操作___v_cont的值:'|| v_count);
when v_count&gt;5 then
dbms_output.put_line('when 5操作___v_count的值:'|| v_count);
when v_count&gt;4 then
dbms_output.put_line('when 10操作____v_count的值:'|| v_count);
else
dbms_output.put_line('else操作____v_cout的值:'||v_count);
end case;
end;
/
</pre>
<br />
<strong>三、循环语句</strong> <br />
&nbsp; 三种循环：基本循环、while循环、for循环语句。 <br />
1、基本循环 <br />
循环语句以loop开始，以end loop结束，其语法如下： <br />
&nbsp; loop <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; statement1； <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 。。。。。。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit[when condition]; <br />
&nbsp;&nbsp;&nbsp; end loop; <br />
注意：当执行基本循环语句时，无论是否满足条件，语句至少会被执行一次，当condition为true时，会推出循环。并执行end loop后的相应操作。当编写基本循环语句时，一定要有exit语句，否则会出现死循环，另外还要定义循环控制变量。 <br />
&nbsp; 示例如下： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357790#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>&nbsp;declare &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;i&nbsp;int:=</span><span class="number">1</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;begin &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;loop&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>dbms_output.put_line(i); &nbsp;&nbsp;</span></li>
    <li><span>exit&nbsp;when&nbsp;i=</span><span class="number">10</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>i:=i+</span><span class="number">1</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>nd&nbsp;loop; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;end; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;/ &nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">    declare
i int:=1;
begin
loop
dbms_output.put_line(i);
exit when i=10;
i:=i+1;
end loop;
end;
/
</pre>
<br />
2、while循环 <br />
对于while循环，只要条件为true时，才执行循环体内语句。while循环以while...loop开始，以end loop结束。其语法如下： <br />
<span style="color: red"><br />
while 条件 loop <br />
语句1； <br />
语法2； <br />
end loop; <br />
</span><br />
当条件为true执行循环体内语句，当条件为false或full时，则跳出循环执行end loop以后的语句，另外还要定义循环控制变量。 <br />
示例如下： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357790#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>&nbsp;&nbsp;declare &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;i&nbsp;int:=</span><span class="number">1</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;begin &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;while&nbsp;i&lt;=</span><span class="number">10</span><span>&nbsp;loop&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;dbms_output.put_line(i); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;i:=i+</span><span class="number">1</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>end&nbsp;loop; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;end; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;/ &nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">    declare
i int:=1;
begin
while i&lt;=10 loop
dbms_output.put_line(i);
i:=i+1;
end loop;
end;
/
</pre>
<br />
<strong>3、for循环</strong> <br />
当使用for循环时，oracle会隐藏定义循环控制变量(即不需要人工定义循环控制变量),语法如下： <br />
<span style="color: red"><br />
for counter in[reverse] <br />
lower_bound..upper_bound loop <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; statement1; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; statement2; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .......... <br />
end loop; <br />
</span><br />
注意：counter循环控制变量，oracle会隐藏定义，lower_bound和upper_bound分别对应于循环变量的下界值和上界值，默认情况下，当使用for循环时，每次循环时循环控制变量会自动增一；如果指定reverse选项，那么每次循环时循环变量会自动减一。示例如下： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Oracle代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://shawnfree.javaeye.com/blog/357790#"><img alt="复制代码" src="http://shawnfree.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-default">
    <li><span><span>declare &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;begin &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;for&nbsp;i&nbsp;in&nbsp;reverse&nbsp;&nbsp;</span><span class="number">1</span><span>..</span><span class="number">10</span><span>&nbsp;loop &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;dbms_output.put_line(i); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;end&nbsp;loop; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;end; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;/&nbsp; &nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="Oracle" style="display: none" name="code">   declare
begin
for i in reverse  1..10 loop
dbms_output.put_line(i);
end loop;
end;
/
</pre>
</div>
<img src ="http://www.blogjava.net/caizh2009/aggbug/291995.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-08-20 20:29 <a href="http://www.blogjava.net/caizh2009/articles/291995.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ORACLE函数大全</title><link>http://www.blogjava.net/caizh2009/articles/290663.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Tue, 11 Aug 2009 03:31:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/290663.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/290663.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/290663.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/290663.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/290663.html</trackback:ping><description><![CDATA[<p>ORACLE函数大全&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;<br />
常用oracle函数 <br />
SQL中的单记录函数<br />
1.ASCII<br />
返回与指定的字符对应的十进制数;<br />
SQL&gt; select ascii('A') A,ascii('a') a,ascii('0') zero,ascii(' ') space from dual; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ZERO&nbsp;&nbsp;&nbsp;&nbsp; SPACE<br />
--------- --------- --------- ---------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 65&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 97&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 48&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 32<br />
&nbsp;</p>
<p>2.CHR<br />
给出整数,返回对应的字符;<br />
SQL&gt; select chr(54740) zhao,chr(65) chr65 from dual;<br />
&nbsp;<br />
ZH C<br />
-- -<br />
赵 A<br />
&nbsp;<br />
3.CONCAT<br />
连接两个字符串;<br />
SQL&gt; select concat('010-','88888888')||'转23'&nbsp; 高乾竞电话 from dual;<br />
&nbsp;<br />
高乾竞电话<br />
----------------<br />
010-88888888转23<br />
&nbsp;<br />
4.INITCAP<br />
返回字符串并将字符串的第一个字母变为大写;<br />
SQL&gt; select initcap('smith') upp from dual;<br />
&nbsp;<br />
UPP<br />
-----<br />
Smith<br />
&nbsp;</p>
<p>5.INSTR(C1,C2,I,J)<br />
在一个字符串中搜索指定的字符,返回发现指定的字符的位置;<br />
C1&nbsp;&nbsp;&nbsp; 被搜索的字符串<br />
C2&nbsp;&nbsp;&nbsp; 希望搜索的字符串<br />
I&nbsp;&nbsp;&nbsp;&nbsp; 搜索的开始位置,默认为1<br />
J&nbsp;&nbsp;&nbsp;&nbsp; 出现的位置,默认为1<br />
SQL&gt; select instr('oracle traning','ra',1,2) instring from dual;<br />
&nbsp;<br />
&nbsp;INSTRING<br />
---------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9<br />
&nbsp;</p>
<p>6.LENGTH<br />
返回字符串的长度;<br />
SQL&gt; select name,length(name),addr,length(addr),sal,length(to_char(sal)) from gao.nchar_tst;<br />
&nbsp;<br />
NAME&nbsp;&nbsp; LENGTH(NAME) ADDR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LENGTH(ADDR)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SAL LENGTH(TO_CHAR(SAL))<br />
------ ------------ ---------------- ------------ --------- --------------------<br />
高乾竞&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3 北京市海锭区&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp; 9999.99&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
7.LOWER<br />
返回字符串,并将所有的字符小写<br />
SQL&gt; select lower('AaBbCcDd')AaBbCcDd from dual;<br />
&nbsp;<br />
AABBCCDD<br />
--------<br />
aabbccdd<br />
&nbsp;</p>
<p>8.UPPER<br />
返回字符串,并将所有的字符大写<br />
SQL&gt; select upper('AaBbCcDd') upper from dual;<br />
&nbsp;<br />
UPPER<br />
--------<br />
AABBCCDD<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
9.RPAD和LPAD(粘贴字符)<br />
RPAD&nbsp; 在列的右边粘贴字符<br />
LPAD&nbsp; 在列的左边粘贴字符<br />
SQL&gt; select lpad(rpad('gao',10,'*'),17,'*')from dual;<br />
&nbsp;<br />
LPAD(RPAD('GAO',1<br />
-----------------<br />
*******gao*******<br />
不够字符则用*来填满<br />
&nbsp;</p>
<p>10.LTRIM和RTRIM<br />
LTRIM&nbsp; 删除左边出现的字符串<br />
RTRIM&nbsp; 删除右边出现的字符串<br />
SQL&gt; select ltrim(rtrim('&nbsp;&nbsp; gao qian jing&nbsp;&nbsp; ',' '),' ') from dual;<br />
&nbsp;<br />
LTRIM(RTRIM('<br />
-------------<br />
gao qian jing<br />
&nbsp;</p>
<p>11.SUBSTR(string,start,count)<br />
取子字符串,从start开始,取count个<br />
SQL&gt; select substr('13088888888',3,8) from dual;<br />
&nbsp;<br />
SUBSTR('<br />
--------<br />
08888888<br />
&nbsp;</p>
<p>12.REPLACE('string','s1','s2')<br />
string&nbsp;&nbsp; 希望被替换的字符或变量 <br />
s1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 被替换的字符串<br />
s2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 要替换的字符串<br />
SQL&gt; select replace('he love you','he','i') from dual;<br />
&nbsp;<br />
REPLACE('H<br />
----------<br />
i love you<br />
&nbsp;</p>
<p>13.SOUNDEX<br />
返回一个与给定的字符串读音相同的字符串<br />
SQL&gt; create table table1(xm varchar(8));<br />
SQL&gt; insert into table1 values('weather');<br />
SQL&gt; insert into table1 values('wether');<br />
SQL&gt; insert into table1 values('gao');<br />
&nbsp;<br />
SQL&gt; select xm from table1 where soundex(xm)=soundex('weather');<br />
&nbsp;<br />
XM<br />
--------<br />
weather<br />
wether<br />
&nbsp;</p>
<p>14.TRIM('s' from 'string')<br />
LEADING&nbsp;&nbsp; 剪掉前面的字符<br />
TRAILING&nbsp; 剪掉后面的字符<br />
如果不指定,默认为空格符 <br />
&nbsp;<br />
15.ABS<br />
返回指定值的绝对值<br />
SQL&gt; select abs(100),abs(-100) from dual;<br />
&nbsp;<br />
&nbsp;ABS(100) ABS(-100)<br />
--------- ---------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 100<br />
&nbsp;</p>
<p>16.ACOS<br />
给出反余弦的值<br />
SQL&gt; select acos(-1) from dual;<br />
&nbsp;<br />
&nbsp;ACOS(-1)<br />
---------<br />
3.1415927<br />
&nbsp;</p>
<p>17.ASIN<br />
给出反正弦的值<br />
SQL&gt; select asin(0.5) from dual;<br />
&nbsp;<br />
ASIN(0.5)<br />
---------<br />
.52359878<br />
&nbsp;</p>
<p>18.ATAN<br />
返回一个数字的反正切值<br />
SQL&gt; select atan(1) from dual;<br />
&nbsp;<br />
&nbsp; ATAN(1)<br />
---------<br />
.78539816<br />
&nbsp;</p>
<p>19.CEIL<br />
返回大于或等于给出数字的最小整数<br />
SQL&gt; select ceil(3.1415927) from dual;<br />
&nbsp;<br />
CEIL(3.1415927)<br />
---------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4<br />
&nbsp;</p>
<p>20.COS<br />
返回一个给定数字的余弦<br />
SQL&gt; select cos(-3.1415927) from dual;<br />
&nbsp;<br />
COS(-3.1415927)<br />
---------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -1<br />
&nbsp;</p>
<p>21.COSH<br />
返回一个数字反余弦值<br />
SQL&gt; select cosh(20) from dual;<br />
&nbsp;<br />
&nbsp;COSH(20)<br />
---------<br />
242582598<br />
&nbsp;</p>
<p>22.EXP<br />
返回一个数字e的n次方根<br />
SQL&gt; select exp(2),exp(1) from dual;<br />
&nbsp;<br />
&nbsp;&nbsp; EXP(2)&nbsp;&nbsp;&nbsp; EXP(1)<br />
--------- ---------<br />
7.3890561 2.7182818<br />
&nbsp;</p>
<p>23.FLOOR<br />
对给定的数字取整数<br />
SQL&gt; select floor(2345.67) from dual;<br />
&nbsp;<br />
FLOOR(2345.67)<br />
--------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2345<br />
&nbsp;</p>
<p>24.LN<br />
返回一个数字的对数值<br />
SQL&gt; select ln(1),ln(2),ln(2.7182818) from dual;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp; LN(1)&nbsp;&nbsp;&nbsp;&nbsp; LN(2) LN(2.7182818)<br />
--------- --------- -------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 .69314718&nbsp;&nbsp;&nbsp;&nbsp; .99999999<br />
&nbsp;</p>
<p>25.LOG(n1,n2)<br />
返回一个以n1为底n2的对数 <br />
SQL&gt; select log(2,1),log(2,4) from dual;<br />
&nbsp;<br />
&nbsp;LOG(2,1)&nbsp; LOG(2,4)<br />
--------- ---------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<br />
&nbsp;</p>
<p>26.MOD(n1,n2)<br />
返回一个n1除以n2的余数<br />
SQL&gt; select mod(10,3),mod(3,3),mod(2,3) from dual;<br />
&nbsp;<br />
MOD(10,3)&nbsp; MOD(3,3)&nbsp; MOD(2,3)<br />
--------- --------- ---------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<br />
&nbsp;</p>
<p>27.POWER<br />
返回n1的n2次方根<br />
SQL&gt; select power(2,10),power(3,3) from dual;<br />
&nbsp;<br />
POWER(2,10) POWER(3,3)<br />
----------- ----------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1024&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 27<br />
&nbsp;</p>
<p>28.ROUND和TRUNC<br />
按照指定的精度进行舍入<br />
SQL&gt; select round(55.5),round(-55.4),trunc(55.5),trunc(-55.5) from dual;<br />
&nbsp;<br />
ROUND(55.5) ROUND(-55.4) TRUNC(55.5) TRUNC(-55.5)<br />
----------- ------------ ----------- ------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 56&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -55<br />
&nbsp;</p>
<p>29.SIGN<br />
取数字n的符号,大于0返回1,小于0返回-1,等于0返回0<br />
SQL&gt; select sign(123),sign(-100),sign(0) from dual;<br />
&nbsp;<br />
SIGN(123) SIGN(-100)&nbsp;&nbsp; SIGN(0)<br />
--------- ---------- ---------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0<br />
&nbsp;</p>
<p>30.SIN<br />
返回一个数字的正弦值<br />
SQL&gt; select sin(1.57079) from dual;<br />
&nbsp;<br />
SIN(1.57079)<br />
------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<br />
&nbsp;</p>
<p>31.SIGH<br />
返回双曲正弦的值<br />
SQL&gt; select sin(20),sinh(20) from dual;<br />
&nbsp;<br />
&nbsp; SIN(20)&nbsp; SINH(20)<br />
--------- ---------<br />
.91294525 242582598<br />
&nbsp;</p>
<p>32.SQRT<br />
返回数字n的根<br />
SQL&gt; select sqrt(64),sqrt(10) from dual;<br />
&nbsp;<br />
&nbsp;SQRT(64)&nbsp; SQRT(10)<br />
--------- ---------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8 3.1622777<br />
&nbsp;</p>
<p>33.TAN<br />
返回数字的正切值<br />
SQL&gt; select tan(20),tan(10) from dual;<br />
&nbsp;<br />
&nbsp; TAN(20)&nbsp;&nbsp; TAN(10)<br />
--------- ---------<br />
2.2371609 .64836083<br />
&nbsp;</p>
<p>34.TANH<br />
返回数字n的双曲正切值<br />
SQL&gt; select tanh(20),tan(20) from dual;<br />
&nbsp;<br />
&nbsp;TANH(20)&nbsp;&nbsp; TAN(20)<br />
--------- ---------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 2.2371609<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
35.TRUNC<br />
按照指定的精度截取一个数<br />
SQL&gt; select trunc(124.1666,-2) trunc1,trunc(124.16666,2) from dual;<br />
&nbsp;<br />
&nbsp;&nbsp; TRUNC1 TRUNC(124.16666,2)<br />
--------- ------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 124.16<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
36.ADD_MONTHS<br />
增加或减去月份<br />
SQL&gt; select to_char(add_months(to_date('199912','yyyymm'),2),'yyyymm') from dual;<br />
&nbsp;<br />
TO_CHA<br />
------<br />
200002<br />
SQL&gt; select to_char(add_months(to_date('199912','yyyymm'),-2),'yyyymm') from dual;<br />
&nbsp;<br />
TO_CHA<br />
------<br />
199910<br />
&nbsp;</p>
<p>37.LAST_DAY<br />
返回日期的最后一天<br />
SQL&gt; select to_char(sysdate,'yyyy.mm.dd'),to_char((sysdate)+1,'yyyy.mm.dd') from dual;<br />
&nbsp;<br />
TO_CHAR(SY TO_CHAR((S<br />
---------- ----------<br />
2004.05.09 2004.05.10<br />
SQL&gt; select last_day(sysdate) from dual;<br />
&nbsp;<br />
LAST_DAY(S<br />
----------<br />
31-5月 -04<br />
&nbsp;</p>
<p>38.MONTHS_BETWEEN(date2,date1)<br />
给出date2-date1的月份<br />
SQL&gt; select months_between('19-12月-1999','19-3月-1999') mon_between from dual;<br />
&nbsp;<br />
MON_BETWEEN<br />
-----------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9<br />
SQL&gt;selectmonths_between(to_date('2000.05.20','yyyy.mm.dd'),to_date('2005.05.20','yyyy.mm.dd')) mon_betw from dual;<br />
&nbsp;<br />
&nbsp;MON_BETW<br />
---------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -60<br />
&nbsp;</p>
<p>39.NEW_TIME(date,'this','that')<br />
给出在this时区=other时区的日期和时间<br />
SQL&gt; select to_char(sysdate,'yyyy.mm.dd hh24:mi:ss') bj_time,to_char(new_time<br />
&nbsp; 2&nbsp; (sysdate,'PDT','GMT'),'yyyy.mm.dd hh24:mi:ss') los_angles from dual;<br />
&nbsp;<br />
BJ_TIME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOS_ANGLES<br />
------------------- -------------------<br />
2004.05.09 11:05:32 2004.05.09 18:05:32<br />
&nbsp;</p>
<p>40.NEXT_DAY(date,'day')<br />
给出日期date和星期x之后计算下一个星期的日期<br />
SQL&gt; select next_day('18-5月-2001','星期五') next_day from dual;<br />
&nbsp;<br />
NEXT_DAY<br />
----------<br />
25-5月 -01<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
41.SYSDATE<br />
用来得到系统的当前日期<br />
SQL&gt; select to_char(sysdate,'dd-mm-yyyy day') from dual;<br />
&nbsp;<br />
TO_CHAR(SYSDATE,'<br />
-----------------<br />
09-05-2004 星期日<br />
trunc(date,fmt)按照给出的要求将日期截断,如果fmt='mi'表示保留分,截断秒<br />
SQL&gt; select to_char(trunc(sysdate,'hh'),'yyyy.mm.dd hh24:mi:ss') hh,<br />
&nbsp; 2&nbsp; to_char(trunc(sysdate,'mi'),'yyyy.mm.dd hh24:mi:ss') hhmm from dual;<br />
&nbsp;<br />
HH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HHMM<br />
------------------- -------------------<br />
2004.05.09 11:00:00 2004.05.09 11:17:00<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
42.CHARTOROWID<br />
将字符数据类型转换为ROWID类型<br />
SQL&gt; select rowid,rowidtochar(rowid),ename from scott.emp;<br />
&nbsp;<br />
ROWID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ROWIDTOCHAR(ROWID) ENAME<br />
------------------ ------------------ ----------<br />
AAAAfKAACAAAAEqAAA AAAAfKAACAAAAEqAAA SMITH<br />
AAAAfKAACAAAAEqAAB AAAAfKAACAAAAEqAAB ALLEN<br />
AAAAfKAACAAAAEqAAC AAAAfKAACAAAAEqAAC WARD<br />
AAAAfKAACAAAAEqAAD AAAAfKAACAAAAEqAAD JONES<br />
&nbsp;</p>
<p>43.CONVERT(c,dset,sset)<br />
将源字符串 sset从一个语言字符集转换到另一个目的dset字符集<br />
SQL&gt; select convert('strutz','we8hp','f7dec') "conversion" from dual;<br />
&nbsp;<br />
conver<br />
------<br />
strutz<br />
&nbsp;</p>
<p>44.HEXTORAW<br />
将一个十六进制构成的字符串转换为二进制<br />
&nbsp;</p>
<p>45.RAWTOHEXT<br />
将一个二进制构成的字符串转换为十六进制<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
46.ROWIDTOCHAR<br />
将ROWID数据类型转换为字符类型<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
47.TO_CHAR(date,'format')<br />
SQL&gt; select to_char(sysdate,'yyyy/mm/dd hh24:mi:ss') from dual;<br />
&nbsp;<br />
TO_CHAR(SYSDATE,'YY<br />
-------------------<br />
2004/05/09 21:14:41<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
48.TO_DATE(string,'format')<br />
将字符串转化为ORACLE中的一个日期<br />
&nbsp;</p>
<p>49.TO_MULTI_BYTE<br />
将字符串中的单字节字符转化为多字节字符<br />
SQL&gt;&nbsp; select to_multi_byte('高') from dual;<br />
&nbsp;<br />
TO<br />
--<br />
高<br />
&nbsp;</p>
<p>50.TO_NUMBER<br />
将给出的字符转换为数字<br />
SQL&gt; select to_number('1999') year from dual;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; YEAR<br />
---------<br />
&nbsp;&nbsp;&nbsp;&nbsp; 1999<br />
&nbsp;</p>
<p>51.BFILENAME(dir,file)<br />
指定一个外部二进制文件<br />
SQL&gt;insert into file_tb1 values(bfilename('lob_dir1','image1.gif'));<br />
&nbsp;</p>
<p>52.CONVERT('x','desc','source')<br />
将x字段或变量的源source转换为desc<br />
SQL&gt; select sid,serial#,username,decode(command,<br />
&nbsp; 2&nbsp; 0,'none',<br />
&nbsp; 3&nbsp; 2,'insert',<br />
&nbsp; 4&nbsp; 3,<br />
&nbsp; 5&nbsp; 'select',<br />
&nbsp; 6&nbsp; 6,'update',<br />
&nbsp; 7&nbsp; 7,'delete',<br />
&nbsp; 8&nbsp; 8,'drop',<br />
&nbsp; 9&nbsp; 'other') cmd&nbsp; from v$session where type!='background';<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SID&nbsp;&nbsp; SERIAL# USERNAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CMD<br />
--------- --------- ------------------------------ ------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; none<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; none<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; none<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; none<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; none<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; none<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1275&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; none<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1275&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; none<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20 GAO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 40 GAO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; none<br />
&nbsp;</p>
<p>53.DUMP(s,fmt,start,length)<br />
DUMP函数以fmt指定的内部数字格式返回一个VARCHAR2类型的值<br />
SQL&gt; col global_name for a30<br />
SQL&gt; col dump_string for a50<br />
SQL&gt; set lin 200<br />
SQL&gt; select global_name,dump(global_name,1017,8,5) dump_string from global_name;<br />
&nbsp;<br />
GLOBAL_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DUMP_STRING<br />
------------------------------ --------------------------------------------------<br />
ORACLE.WORLD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Typ=1 Len=12 CharacterSet=ZHS16GBK: W,O,R,L,D<br />
&nbsp;</p>
<p>54.EMPTY_BLOB()和EMPTY_CLOB()<br />
这两个函数都是用来对大数据类型字段进行初始化操作的函数<br />
&nbsp;<br />
55.GREATEST<br />
返回一组表达式中的最大值,即比较字符的编码大小.<br />
SQL&gt; select greatest('AA','AB','AC') from dual;<br />
&nbsp;<br />
GR<br />
--<br />
AC<br />
SQL&gt; select greatest('啊','安','天') from dual;<br />
&nbsp;<br />
GR<br />
--<br />
天<br />
&nbsp;</p>
<p>56.LEAST<br />
返回一组表达式中的最小值 <br />
SQL&gt; select least('啊','安','天') from dual;<br />
&nbsp;<br />
LE<br />
--<br />
啊<br />
&nbsp;</p>
<p>57.UID<br />
返回标识当前用户的唯一整数<br />
SQL&gt; show user<br />
USER 为"GAO"<br />
SQL&gt; select username,user_id from dba_users where user_id=uid;<br />
&nbsp;<br />
USERNAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; USER_ID<br />
------------------------------ ---------<br />
GAO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 25<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
58.USER<br />
返回当前用户的名字<br />
SQL&gt; select user from&nbsp; dual;<br />
&nbsp;<br />
USER<br />
------------------------------<br />
GAO<br />
&nbsp;</p>
<p>59.USEREVN<br />
返回当前用户环境的信息,opt可以是:<br />
ENTRYID,SESSIONID,TERMINAL,ISDBA,LABLE,LANGUAGE,CLIENT_INFO,LANG,VSIZE<br />
ISDBA&nbsp; 查看当前用户是否是DBA如果是则返回true<br />
SQL&gt; select userenv('isdba') from dual;<br />
&nbsp;<br />
USEREN<br />
------<br />
FALSE<br />
SQL&gt; select userenv('isdba') from dual;<br />
&nbsp;<br />
USEREN<br />
------<br />
TRUE<br />
SESSION<br />
返回会话标志<br />
SQL&gt; select userenv('sessionid') from dual;<br />
&nbsp;<br />
USERENV('SESSIONID')<br />
--------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 152<br />
ENTRYID<br />
返回会话人口标志<br />
SQL&gt; select userenv('entryid') from dual;<br />
&nbsp;<br />
USERENV('ENTRYID')<br />
------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0<br />
INSTANCE<br />
返回当前INSTANCE的标志<br />
SQL&gt; select userenv('instance') from dual;<br />
&nbsp;<br />
USERENV('INSTANCE')<br />
-------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<br />
LANGUAGE<br />
返回当前环境变量<br />
SQL&gt; select userenv('language') from dual;<br />
&nbsp;<br />
USERENV('LANGUAGE')<br />
----------------------------------------------------<br />
SIMPLIFIED CHINESE_CHINA.ZHS16GBK<br />
LANG<br />
返回当前环境的语言的缩写<br />
SQL&gt; select userenv('lang') from dual;<br />
&nbsp;<br />
USERENV('LANG')<br />
----------------------------------------------------<br />
ZHS<br />
TERMINAL<br />
返回用户的终端或机器的标志<br />
SQL&gt; select userenv('terminal') from dual;<br />
&nbsp;<br />
USERENV('TERMINA<br />
----------------<br />
GAO<br />
VSIZE(X)<br />
返回X的大小(字节)数<br />
SQL&gt; select vsize(user),user from dual;<br />
&nbsp;<br />
VSIZE(USER) USER<br />
----------- ------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6 SYSTEM<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
60.AVG(DISTINCT|ALL)<br />
all表示对所有的值求平均值,distinct只对不同的值求平均值<br />
SQLWKS&gt; create table table3(xm varchar(8),sal number(7,2));<br />
语句已处理。<br />
SQLWKS&gt;&nbsp; insert into table3 values('gao',1111.11);<br />
SQLWKS&gt;&nbsp; insert into table3 values('gao',1111.11);<br />
SQLWKS&gt;&nbsp; insert into table3 values('zhu',5555.55);<br />
SQLWKS&gt; commit;<br />
&nbsp;<br />
SQL&gt; select avg(distinct sal) from gao.table3;<br />
&nbsp;<br />
AVG(DISTINCTSAL)<br />
----------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3333.33<br />
&nbsp;<br />
SQL&gt; select avg(all sal) from gao.table3;<br />
&nbsp;<br />
AVG(ALLSAL)<br />
-----------<br />
&nbsp;&nbsp;&nbsp; 2592.59<br />
&nbsp;</p>
<p>61.MAX(DISTINCT|ALL)<br />
求最大值,ALL表示对所有的值求最大值,DISTINCT表示对不同的值求最大值,相同的只取一次<br />
SQL&gt; select max(distinct sal) from scott.emp;<br />
&nbsp;<br />
MAX(DISTINCTSAL)<br />
----------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5000<br />
&nbsp;</p>
<p>62.MIN(DISTINCT|ALL)<br />
求最小值,ALL表示对所有的值求最小值,DISTINCT表示对不同的值求最小值,相同的只取一次<br />
SQL&gt; select min(all sal) from gao.table3;<br />
&nbsp;<br />
MIN(ALLSAL)<br />
-----------<br />
&nbsp;&nbsp;&nbsp; 1111.11<br />
&nbsp;</p>
<p>63.STDDEV(distinct|all)<br />
求标准差,ALL表示对所有的值求标准差,DISTINCT表示只对不同的值求标准差<br />
SQL&gt; select stddev(sal) from scott.emp;<br />
&nbsp;<br />
STDDEV(SAL)<br />
-----------<br />
&nbsp; 1182.5032<br />
&nbsp;<br />
SQL&gt; select stddev(distinct sal) from scott.emp;<br />
&nbsp;<br />
STDDEV(DISTINCTSAL)<br />
-------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1229.951<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
64.VARIANCE(DISTINCT|ALL)<br />
求协方差 <br />
&nbsp;<br />
SQL&gt; select variance(sal) from scott.emp;<br />
&nbsp;<br />
VARIANCE(SAL)<br />
-------------<br />
&nbsp;&nbsp;&nbsp; 1398313.9<br />
&nbsp;</p>
<p>65.GROUP BY<br />
主要用来对一组数进行统计<br />
SQL&gt; select deptno,count(*),sum(sal) from scott.emp group by deptno;<br />
&nbsp;<br />
&nbsp;&nbsp; DEPTNO&nbsp; COUNT(*)&nbsp; SUM(SAL)<br />
--------- --------- ---------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8750<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp; 10875<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9400<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
66.HAVING<br />
对分组统计再加限制条件<br />
SQL&gt; select deptno,count(*),sum(sal) from scott.emp group by deptno having count(*)&gt;=5;<br />
&nbsp;<br />
&nbsp;&nbsp; DEPTNO&nbsp; COUNT(*)&nbsp; SUM(SAL)<br />
--------- --------- ---------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp; 10875<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9400<br />
SQL&gt; select deptno,count(*),sum(sal) from scott.emp having count(*)&gt;=5 group by deptno ;<br />
&nbsp;<br />
&nbsp;&nbsp; DEPTNO&nbsp; COUNT(*)&nbsp; SUM(SAL)<br />
--------- --------- ---------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp; 10875<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9400<br />
&nbsp;</p>
<p>67.ORDER BY<br />
用于对查询到的结果进行排序输出<br />
SQL&gt; select deptno,ename,sal from scott.emp order by deptno,sal desc;<br />
&nbsp;<br />
&nbsp;&nbsp; DEPTNO ENAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SAL<br />
--------- ---------- ---------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10 KING&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5000<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10 CLARK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2450<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10 MILLER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1300<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20 SCOTT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3000<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20 FORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3000<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20 JONES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2975<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20 ADAMS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1100<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20 SMITH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 800<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 BLAKE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2850<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 ALLEN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1600<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 TURNER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1500<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 WARD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1250<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 MARTIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1250<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 JAMES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 950<br />
&nbsp;</p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/290663.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-08-11 11:31 <a href="http://www.blogjava.net/caizh2009/articles/290663.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ORACLE SQL 索引 </title><link>http://www.blogjava.net/caizh2009/articles/288355.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Sat, 25 Jul 2009 08:32:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/288355.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/288355.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/288355.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/288355.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/288355.html</trackback:ping><description><![CDATA[<div>
<div>ORACLE SQL TUNING<br />
一．优化器模式<br />
&nbsp;&nbsp; ORACLE的优化器共有3种:<br />
&nbsp;&nbsp; a.&nbsp; RULE (基于规则)&nbsp;&nbsp; b. COST (基于成本)&nbsp; c. CHOOSE (选择性)<br />
&nbsp;&nbsp; 为了使用基于成本的优化器(CBO, Cost-Based Optimizer) , 你必须定期更新统计信息，以保证数据库中的对象统计信息(object statistics)的准确性.<br />
&nbsp;&nbsp; 如果数据库的优化器模式设置为选择性(CHOOSE),那么实际的优化器模式将和是否运行过analyze命令有关. 如果table已经被analyze过, 优化器模式将自动成为CBO , 反之,数据库将采用RULE形式的优化器。</div>
</div>
<div class="post_content">
<p>二．访问Table的方式<br />
ORACLE 采用两种访问表中记录的方式:<br />
a.&nbsp; 全表扫描 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 全表扫描就是顺序地访问表中每条记录. ORACLE采用一次读入多个数&nbsp;据块(database block)的方式优化全表扫描。<br />
&nbsp;&nbsp;&nbsp; <br />
b.&nbsp; 索引扫描<br />
&nbsp;&nbsp; 你可以采用基于ROWID的访问方式情况,提高访问表的效率, ROWID包含了表中记录的物理位置信息.ORACLE采用索引(INDEX)实现了数据和存放数据的物理位置(ROWID)之间的联系. 通常索引提供了快速访问ROWID的方法,因此那些基于索引列的查询就可以得到性能上的提高.</p>
<p>其中ORACLE对索引又有两种访问模式.<br />
a)索引唯一扫描 ( INDEX UNIQUE SCAN)<br />
大多数情况下, 优化器通过WHERE子句访问INDEX.<br />
例如:<br />
表LOADING有两个索引 : 建立在LOADING列上的唯一性索引LOADING_PK和建立在MANAGER列上的非唯一性索引IDX_MANAGER. <br />
SELECT loading&nbsp; <br />
FROM LOADING<br />
WHERE LOADING = &#8216;ROSE HILL&#8217;;<br />
&nbsp;&nbsp; 在内部 , 上述SQL将被分成两步执行, 首先 , LOADING_PK 索引将通过索引唯一扫描的方式被访问 , 获得相对应的ROWID, 通过ROWID访问表的方式执行下一步检索.<br />
&nbsp;&nbsp; 如果被检索返回的列包括在INDEX列中,ORACLE将不执行第二步的处理(通过ROWID访问表). 因为检索数据保存在索引中, 单单访问索引就可以完全满足查询结果. <br />
&nbsp;&nbsp; 下面SQL只需要INDEX UNIQUE SCAN 操作.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT LOADING<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM&nbsp; LOADING<br />
WHERE LOADING = &#8216;ROSE HILL&#8217;;<br />
&nbsp;<br />
&nbsp; b)索引范围查询(INDEX RANGE SCAN)<br />
&nbsp;&nbsp;&nbsp;&nbsp; 适用于两种情况:<br />
1. 基于一个范围的检索<br />
2. 基于非唯一性索引的检索<br />
&nbsp;例1:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT LOADING<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM&nbsp; LOADING<br />
WHERE LOADING LIKE &#8216;M%&#8217;;<br />
&nbsp;<br />
WHERE子句条件包括一系列值, ORACLE将通过索引范围查询的方式查询LODGING_PK . 由于索引范围查询将返回一组值, 它的效率就要比索引唯一扫描<br />
低一些.&nbsp; <br />
例2:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT LOADING<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM&nbsp; LOADING<br />
WHERE MANAGER = &#8216;BILL GATES&#8217;;<br />
&nbsp;这个SQL的执行分两步, IDX_MANAGER的索引范围查询(得到所有符合条件记录的ROWID) 和下一步同过ROWID访问表得到LOADING列的值. 由于IDX_MANAGER是一个非唯一性的索引,数据库不能对它执行索引唯一扫描. <br />
&nbsp;<br />
&nbsp; 由于SQL返回LOADING列,而它并不存在于IDX_MANAGER索引中, 所以在索引范围查询后会执行一个通过ROWID访问表的操作. <br />
&nbsp; WHERE子句中, 如果索引列所对应的值的第一个字符由通配符(WILDCARD)开始, 索引将不被采用.<br />
SELECT LOADING<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM&nbsp; LOADING<br />
WHERE MANAGER LIKE &#8216;％HANMAN&#8217;;<br />
在这种情况下，ORACLE将使用全表扫描.</p>
<p><br />
三．SQL调优的本质就是调整执行计划。<br />
&nbsp;在好多情况下，oracle自动选择的执行计划并不是最优的，这时需要我们人工去干预。(什么是执行计划?)<br />
&nbsp;</p>
<p>对SQL调优基本步骤：<br />
a)&nbsp;捕获SQL语句<br />
b)&nbsp;产生SQL语句的执行计划；<br />
c)&nbsp;验证统计信息(SQL语句涉及到的表格是否做过分析)，表格信息(结果集的记录数，索引)，字段上面数据分布特点<br />
d)&nbsp;通过手工收集到的信息，形成自己理想的执行计划。<br />
e)&nbsp;如果做过分析，则重新分析相关表格或者做柱状图分析。<br />
f)&nbsp;如果没有做过分析，则通过尝试不同的Hint，从而获得合适的执行计划。<br />
g)&nbsp;当我们正常无法调优到位时，可以打开10053事件打开优化器的跟踪，看看Oracle如何选择的.<br />
alter session set events='10053 trace name context forever,level 2';<br />
&nbsp;<br />
四．如何捕获SQL语句<br />
&nbsp;捕获SQL语句的方法有如下几种：<br />
&nbsp;&nbsp;1．SQL TRACE或10046跟踪某个模块。<br />
&nbsp;&nbsp;2．PERFSTAT性能统计包，使用方法见附录二。<br />
&nbsp;&nbsp;3．V$SQL，V$SESSION_WAIT，V$SQL_TEXT<br />
五．如何查看执行计划<br />
&nbsp;查看SQL语句的执行计划有以下几种：<br />
&nbsp;1．Set autotrace on(set autotrace traceonly exp)<br />
&nbsp;2．Explain plan for &#8230;..<br />
&nbsp;&nbsp;@?/rdbms/admin/utlxpls.sql<br />
&nbsp;3．V$SQL_PLAN视图<br />
&nbsp;&nbsp;column operation format a16 <br />
column "Query Plan" format a60 <br />
column options format a15 <br />
column object_name&nbsp; format a20 <br />
column id&nbsp; format 99 </p>
<p>select id,lpad(' ',2*(level-1))||operation||' '||options||' '||object_name||' ' <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ||decode(id,0,'Cost = '||position) "Query Plan" <br />
from (select * <br />
from v$sql_plan&nbsp; <br />
where address='&amp;a') sql_plan <br />
start with id = 0 <br />
connect by prior id = parent_id<br />
/</p>
<p>&nbsp;4．第三方工具，如pl/sql developer,TOAD<br />
&nbsp;<br />
六．SQL语句主要的连接方法</p>
<p>a)&nbsp;Nested-loop join<br />
适合于小表(几千条，几万条记录)与大表做联接<br />
在联接列上有索引。</p>
<p>&nbsp;分内表和外表(驱动表)，靠近from子句的是内表。从效率上讲，小表应该作外表，大表应该作内表，即大表查询时走索引。</p>
<p>COST= Access cost of A(驱动表) + (access cost of B * number of rows from A)</p>
<p>成本计算方法：<br />
&nbsp;设小表100行，大表100000行。</p>
<p>&nbsp;两表均有索引：<br />
&nbsp;如果小表在内，大表在外(驱动表)的话，则扫描次数为：<br />
&nbsp;&nbsp;100000+100000*2 (其中2表示IO次数，一次索引，一次数据)<br />
&nbsp;如果大表在内，小表在外(驱动表)的话，则扫描次数为：<br />
&nbsp;&nbsp;100+100*2.</p>
<p>&nbsp;两表均无索引：<br />
&nbsp;如果小表在内，大表在外的话，则扫描次数为：<br />
&nbsp;&nbsp;100000+100*100000<br />
&nbsp;如果大表在内，小表在外的话，则扫描次数为：<br />
&nbsp;&nbsp;100+100000*100</p>
<p>注意：如果一个表有索引，一个表没有索引，ORACLE会将没有索引的表作驱动表。如果两个表都有索引，则外表作驱动表。如果两个都没索引的话，则也是外表作驱动表。</p>
<p>&nbsp;基本的执行计划如下所示：<br />
&nbsp;&nbsp;NESTED LOOPS<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY ROWID)&nbsp; OF&nbsp; our_outer_table<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (..SCAN) OF outer_table_index(&#8230;.)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY ROWID)&nbsp; OF&nbsp; our_inner_table<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (..SCAN) OF inner_table_index(&#8230;.)</p>
<p>b)&nbsp;Hash join </p>
<p>适合于大表与大表，小表(几十万，几百万)与大表之间的联连。<br />
联接列上不需要索引。</p>
<p>基本执行计划如下：<br />
&nbsp;HASH JOIN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (&#8230;.)&nbsp; OF&nbsp; tableA<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (&#8230;.)&nbsp; OF&nbsp; tableB</p>
<p>cost= (access cost of A * number of hash partitions of B) + access cost of B</p>
<p>可以看出主要成本在于A表是否可以被Cache。Hash_area_size的大小将决定Hash Join的主要成本。可以看出Hash Join的成本和返回集合并没有直接的关系，所以当返回结果集比较大的时候一般具有较好的性能。</p>
<p>为了加快hash join的速度，可以调大hash_area_size和pga_aggregate_target（默认为25M）的值。</p>
<p><br />
c)&nbsp;Sort Merge join</p>
<p>每一个Row Source在Join列上均排序。<br />
&nbsp;然后两个排序后的Row Source合并后，作一个结果集返回。<br />
&nbsp;Sort/Merge Join仅仅对equal Join有效。</p>
<p>基本执行计划<br />
&nbsp;MERGE (JOIN)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SORT (JOIN) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (&#8230;.)&nbsp; OF&nbsp; tableA<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SORT (JOIN) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (&#8230;.)&nbsp; OF&nbsp; tableB</p>
<p>cost= access cost of A + access cost of B +(sort cost of A + sort cost of B)</p>
<p>可以看出Sort的成本是Merge Join的主要构成部分。这样sort_area_size的大小将很大程度决定Merge Join的大小。同样如果A表或者B表已经经过排序的，那么Merge Join往往具有很好的性能。其不会走索引。</p>
<p>没有驱动表的概念，即时响应能力较差。</p>
<p>&nbsp;</p>
<p>七．一般情况下最常见的5种问题</p>
<p>1. Statement not written for indexes&nbsp;25%<br />
2. Indexes are missing or inappropriate&nbsp;16%<br />
3. Use of single-column index merge&nbsp;15%<br />
4. Misuse of nested loop, sort merge, or hash join&nbsp;12%<br />
5. Misuse of IN, EXISTS, NOT IN, NOT EXISTS, or table joins&nbsp;8%<br />
&nbsp;<br />
&nbsp;不过在我们这里，最常见的问题是在第2条，第3条，第4条。</p>
<p>1．&nbsp;Statement not written for indexes<br />
类似于这样的：<br />
SELECT account_name, trans_date, amount <br />
FROM transaction <br />
WHERE SUBSTR(account_name,1,7) = ' CAPITAL'; </p>
<p>WHERE account_name LIKE 'CAPITAL%'; </p>
<p>Account_date 日期</p>
<p>To_char(Account_date,&#8217;YYYY-MM-DD:HH24:MI:SS&#8217;)=&#8217;200508XXX&#8217;;</p>
<p>Account_date=to_date(&#8216;200508&#8230;.&#8217;,&#8217;yyyy-mm-dd);</p>
<p><br />
2．Indexes are missing or inappropriate<br />
&nbsp;<br />
&nbsp;例如REP_C021中有这样一句：<br />
select SUBSIDIARYID,260,'&nbsp;&nbsp;&nbsp; 300电话卡',<br />
&nbsp;&nbsp;&nbsp; sum(decode(feetype, 1, ceil(duration / 60))) +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sum(decode(feetype, 0, ceil(duration / 60))),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sum(decode(feetype, 1, ceil(duration / 60))),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sum(decode(feetype, 0, ceil(duration / 60))),0<br />
&nbsp;&nbsp;&nbsp; from cardsusage200508 a, service b<br />
&nbsp;&nbsp; where a.caller = b.servicecode and<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (b.property = i_property or i_property is null) and <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.cdrtype = 102<br />
&nbsp;&nbsp; group by SUBSIDIARYID, 260, '&nbsp;&nbsp;&nbsp; 300电话卡';</p>
<p>Execution Plan<br />
----------------------------------------------------------<br />
&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT STATEMENT Optimizer=RULE<br />
&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; SORT (GROUP BY)<br />
&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; NESTED LOOPS<br />
&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'CARDSUSAGE200508'<br />
&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'SERVICE'<br />
&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (UNIQUE SCAN) OF 'SERVICE_CODE'<br />
&nbsp;<br />
我们取其中的select语句进行调优。在调整之前，原select语句需要6分钟左右。</p>
<p>12:19:20 SQL&gt; select cdrtype,count(*) from cardsusage200508<br />
12:20:12&nbsp;&nbsp; 2&nbsp; group by cdrtype;</p>
<p>CDRT&nbsp;&nbsp; COUNT(*)<br />
---- ----------<br />
102&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 637<br />
106&nbsp;&nbsp;&nbsp;&nbsp; 1973757<br />
107&nbsp;&nbsp;&nbsp;&nbsp; 2390097<br />
112&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 46016<br />
113&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20</p>
<p>针对cardsuage200508表格的特性，我们在CDRTYPE字段上建立一个位图索引CARDSUSAGE_CDRTYPE_BTIDX。<br />
将SQL语句加上以下Hint：<br />
&nbsp; select /*+&nbsp; INDEX(A, CARDSUSAGE_CDRTYPE_BTIDX)*/<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUBSIDIARYID,260,'&nbsp;&nbsp;&nbsp; 300电话卡',<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sum(decode(feetype, 1, ceil(duration / 60))) +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sum(decode(feetype, 0, ceil(duration / 60))),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sum(decode(feetype, 1, ceil(duration / 60))),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sum(decode(feetype, 0, ceil(duration / 60))),0<br />
&nbsp;&nbsp;&nbsp; from cardsusage200508&nbsp; a, service b<br />
&nbsp;&nbsp; where a.caller = b.servicecode and<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (b.property = i_property or i_property is null) and <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.cdrtype = 102<br />
&nbsp;&nbsp; group by SUBSIDIARYID, 260, '&nbsp;&nbsp;&nbsp; 300电话卡';<br />
&nbsp;这样调整后，只需要几秒钟即可出来。</p>
<p>3.&nbsp; Use of single-column index merge<br />
&nbsp;复合索引有的时候比单列索引效率更高。根据where子句中的具体情况，有&nbsp;时可以建立复合索引。例如：<br />
&nbsp;select a.AccountNum,a.ChargeID,a.Total,b.ItemID,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b.Amount,c.billingcycle<br />
&nbsp; from charge_bill a, chargedetail_bill b, Account c<br />
&nbsp;where a.AccountNum &gt; 1 and a.AccountNum &lt;= 1969618 and<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.status = '0' and a.InvoiceID is null and c.paymentmethod != '7' and<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.Total &gt; 0 and a.AccountNum = c.AccountNum and<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.ChargeID = b.ChargeID<br />
&nbsp;order by a.AccountNum, a.ChargeID, b.ItemID;<br />
这样的SQL语句执行需要3分27秒。</p>
<p>我们做了以下优化：<br />
在charge_bill表格的accountnum,status,total,invoiceid列上建立一个复合索引。这样上述SQL语句需要40秒左右。</p>
<p>&nbsp;Resume Service过程中有这么一句：<br />
&nbsp;SELECT NVL(SUM(A.FEE),0)&nbsp;&nbsp; <br />
FROM ACCOUNTBALANCE A,INVOICE B&nbsp; <br />
WHERE A.OBJECTID = B.INVOICEID&nbsp; AND A.ACCOUNTNUM = :b1 <br />
AND B.BILLINGBEGINDATE &lt; TO_DATE(:b2,'yyyymmdd');<br />
该语句需要执行大概72000次。整个过程执行大概需要100分钟左右。</p>
<p>将:b1以具体的值代替，这条SQL语句执行很快，大概0.1秒左右。</p>
<p>我们做了以下优化：<br />
在invoiceid,billingbegindate列上创建了一个索引idx_invoice_hc。<br />
将上述SQL语句改成：<br />
select /*+ use_nl(a,b) index(b,IDX_INVOICE_HC)*/&nbsp; nvl(sum(a.fee),0)<br />
from accountbalance a,invoice b<br />
where a.objectid=b.invoiceid&nbsp; and a.accountnum=m_accountnum<br />
and b.billingbegindate</p>
<p>这样一来，该过程的执行时间快的时候大概在10分钟左右，慢的时候(IO异常紧张的时)大概在30分钟左右。</p>
<p><br />
4.&nbsp;Misuse of nested loop, sort merge, or hash join<br />
&nbsp;表格之间的连接方式和连接顺序都将极大的影响SQL语句的性能。这种问&nbsp;&nbsp;题在平时最常见。ORACLE在处理5张或5张以上的表格的连接时候，很容&nbsp;易出问题。一般情况下，谨记前面表格之间的连接原则，即可以处理此类问&nbsp;题。<br />
&nbsp;<br />
&nbsp;&nbsp; 例如：<br />
&nbsp;&nbsp;select b.SUBSIDIARYID,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.paymentmethod || ':' || nvl(subscribertype, '9999999'),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'gsm',count(*),sum(decode(untelLOCALCHARGE,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0,decode(duration,0,1,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; decode(sign(duration - 1800),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1, 2 + trunc((duration - 1201) / 600),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2)), trunc((duration + 599) / 600))),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sum(nvl(GSMCHARGE, 0)),nvl(property, '0'),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM(trunc((duration + 599) / 600))<br />
&nbsp; from&nbsp; rt_untelecomusage a ,service b, account c <br />
&nbsp;where a.starttime &gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to_date(to_char(add_months(to_date('200508 ', 'YYYYMM'), -1),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'YYYYMM') || '20235959',<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'YYYYMMDDHH24MISS') and<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.starttime &lt; to_date('200508 ' || '21', 'YYYYMMdd') and<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gsmcharge &gt; 0 and a.serviceid = b.serviceid and<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b.accountnum = c.accountnum<br />
&nbsp;group by b.SUBSIDIARYID,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.paymentmethod || ':' || nvl(subscribertype, '9999999'),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'gsm',nvl(property, '0'); <br />
&nbsp;该语句原先需要4，5个小时左右。</p>
<p>优化：<br />
alter session set hash_area_size=300000000;</p>
<p>select /*+ use_hash(b,c) ordered NO_EXPAND full(a) use_hash(a)*/&nbsp; b.SUBSIDIARYID,c.paymentmethod || ':' || nvl(subscribertype, '9999999'),<br />
&nbsp;&nbsp;&nbsp;&nbsp; 'gsm',count(*), sum(decode(untelLOCALCHARGE,0,decode(duration,0, 1,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; decode(sign(duration - 1800), 1,2 + trunc((duration - 1201) / 600), 2)),<br />
&nbsp;&nbsp;&nbsp; &nbsp;trunc((duration + 599) / 600))),sum(nvl(GSMCHARGE, 0)),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nvl(property, '0'),SUM(trunc((duration + 599) / 600))<br />
&nbsp; from service b, account c,untelecomusage_200508&nbsp; a <br />
&nbsp;where a.starttime &gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to_date(to_char(add_months(to_date('200508', 'YYYYMM'), -1),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'YYYYMM') || '20235959',<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'YYYYMMDDHH24MISS') and<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.starttime &lt; to_date('200508' || '21', 'YYYYMMdd') and<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gsmcharge &gt; 0 and a.serviceid = b.serviceid and<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b.accountnum = c.accountnum<br />
&nbsp;group by b.SUBSIDIARYID,c.paymentmethod || ':' || nvl(subscribertype, '9999999'),'gsm',nvl(property, '0');&nbsp; </p>
<p>&nbsp;这样优化后，只需要40分钟左右即可。</p>
<p>八．案例<br />
1．&nbsp;循环Update操作<br />
&nbsp;<br />
&nbsp; 以下过程太慢了， 半个小时连5000条记录都未处理，总 共有7万多条。<br />
declare<br />
&nbsp;&nbsp;&nbsp; cursor c1 is <br />
&nbsp;&nbsp;&nbsp; select caller <br />
&nbsp;&nbsp;&nbsp; from zxx_sms_step where chargemonth=200504 and fee is null;<br />
&nbsp;&nbsp;&nbsp; icnt number;<br />
begin<br />
&nbsp;icnt:=0;<br />
&nbsp;for m_c1 in c1 loop<br />
&nbsp;&nbsp;update zxx_sms_step a set fee=<br />
&nbsp;&nbsp;&nbsp;(select nvl(sum(pascharge),0) from ipasimport_200504 where caller=m_c1.caller and pastag in (1243,1251))<br />
&nbsp;&nbsp;&nbsp;where caller=m_c1.caller and chargemonth=200504;<br />
&nbsp;&nbsp;icnt:=icnt+1;<br />
&nbsp;&nbsp;if icnt=500 then<br />
&nbsp;&nbsp;&nbsp;exit;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;end if;<br />
&nbsp;end loop;<br />
end;</p>
<p>&nbsp;&nbsp; 这样的SQL语句，建议先将update中的子查询生成一张中间表，然后再update。<br />
alter session set hash_area_size=400000000 ;</p>
<p>select /*+use_hash(a,b)*/ b.caller,nvl(sum(a.pascharge),0) from ipasimport_200504 a,zxx_sms_step b <br />
where b.chargemonth=200504 and b.fee is null <br />
and a.caller=b.caller and a.pastag in (1243,1251) <br />
group by b.caller;<br />
&nbsp;这样10分钟不到就可产生中间表，然后再update只需几分钟即可。</p>
<p><br />
2．&nbsp;部分表格未做统计信息分析<br />
&nbsp;<br />
&nbsp;网通OA系统自从oracle服务器从pc服务器上迁到小型机上后，其CPU利用率经常冲到很高。而其中每一个进程在某个瞬间将占用40%左右的CPU。这些进程都是通过jdbc thin client 连过来的。</p>
<p>通过抓取其sql_text，发现以下两条SQL语句不正常。<br />
1.<br />
&nbsp;SQL&gt;&nbsp; select D.flow_inid,D.step_inco,D.deal_man,D.agen_men,D.time_set,D.peri_man,<br />
&nbsp; 2&nbsp;&nbsp; S2.fsub_set,S2.fsub_id,F.mtbl_stru,F.doc_name,F.svr_name <br />
&nbsp; 3&nbsp;&nbsp; from deal_info D,step_inst S1,step_def S2,flow_inst F <br />
&nbsp; 4&nbsp;&nbsp; where D.step_inco=S1.step_inco and S1.flow_id=S2.flow_id <br />
&nbsp; 5&nbsp;&nbsp; and S1.step_code=S2.step_code and S1.flow_inid=F.flow_inid and D.step_type=5<br />
&nbsp; 6&nbsp;&nbsp; and D.fsub_flag is not null and D.fsub_flag=1 and rownum&lt;=1;</p>
<p>其执行计划和统计信息如下：</p>
<p>Execution Plan<br />
----------------------------------------------------------<br />
&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT STATEMENT Optimizer=CHOOSE (Cost=22 Card=1 Bytes=1077)<br />
&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; COUNT (STOPKEY)<br />
&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; NESTED LOOPS (Cost=22 Card=1 Bytes=1077)<br />
&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NESTED LOOPS (Cost=21 Card=1 Bytes=360)<br />
&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NESTED LOOPS (Cost=20 Card=1 Bytes=150)<br />
&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'STEP_INST' (Cost=2 Card=9&nbsp; Bytes=153)<br />
&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'DEAL_INFO' (Cost=2 Card=1 Bytes=133)<br />
&nbsp;&nbsp; 7&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'DEAL_INFO_STEP_INCO' (NON-UNIQUE) (Cost=2 <br />
&nbsp;&nbsp; 8&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'FLOW_INST' (Cost=1 Card=1 Bytes=210)<br />
&nbsp;&nbsp; 9&nbsp;&nbsp;&nbsp; 8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (UNIQUE SCAN) OF 'PK_FLOW_INST' (UNIQUE)<br />
&nbsp; 10&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'STEP_DEF' (Cost=1 Card=1 Bytes=717)<br />
&nbsp; 11&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (UNIQUE SCAN) OF 'STEP_DEF_PK11119358638593' (UNIQUE)</p>
<p>Statistics<br />
----------------------------------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; recursive calls<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; db block gets<br />
&nbsp;&nbsp;&nbsp;&nbsp; 270626&nbsp; consistent gets<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 273&nbsp; physical reads<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; redo size<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1079&nbsp; bytes sent via SQL*Net to client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 655&nbsp; bytes received via SQL*Net from client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp; SQL*Net roundtrips to/from client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; sorts (memory)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; sorts (disk)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; rows processed</p>
<p>这条SQL语句执行的时间也不长，就几秒钟，但是我们看到consistent gets很高有27万多，这个操作就是消耗CPU的祸首。从执行计划来看，其执行计划显然不可理，问题出在表格的连接顺序上面，应该是deal_info表格做为驱动表先访问。</p>
<p>检查这些表格的统计分析，发现step_def表格未做分析，对该表格做统计信息分析，并对deal_info表做柱状图分析后：<br />
analyze table deal_info compute statistics for all indexed columns;</p>
<p>其执行计划正是我们所想要的，同时consistent gets也只有200左右，该操作所消耗的CPU也下降到了1%。</p>
<p>2.表格的柱状图信息没有分析：<br />
SELECT SO.SO_NBR, so_type.name,STATUS.STS_WORDS, SO.REMARKS, SO.CHECK_TYPE,CTRL_ASGN.DISPATCHED_DATE, <br />
CTRL_ASGN.PRE_ALARM_DATE, CTRL_ASGN.ALARM_DATE<br />
from SO,SO_HANDLE, CTRL_ASGN,so_type,status <br />
WHERE&nbsp;SO_HANDLE.SO_NBR=SO.SO_NBR AND SO.SO_NBR=CTRL_ASGN.SO_NBR <br />
AND SO_HANDLE.HANDLE_TYPE_ID=1017<br />
and so.so_type_id=so_type.so_type_id and so.PRIORITY=status.sts_id and status.table_name='SO'<br />
&nbsp;AND STATUS.column_name ='PRIORITY' AND SO_HANDLE.WORK_AREA_ID= 300101<br />
AND SO.STATE= 'B' AND SO.HALT ='N'<br />
AND CTRL_ASGN.STATE = 'B'<br />
AND CTRL_ASGN.STS = 'D';</p>
<p>该SQL语句执行时间要2分钟左右。<br />
执行计划如下：<br />
Execution Plan<br />
----------------------------------------------------------<br />
&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT STATEMENT Optimizer=HINT: RULE<br />
&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; NESTED LOOPS<br />
&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; NESTED LOOPS<br />
&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NESTED LOOPS<br />
&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NESTED LOOPS<br />
&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'STATUS'<br />
&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'PK_STATUS' (UNIQUE)<br />
&nbsp;&nbsp; 7&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'CTRL_ASGN'<br />
&nbsp;&nbsp; 8&nbsp;&nbsp;&nbsp; 7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'CTRL_ASGN_0002'<br />
&nbsp;&nbsp; 9&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'SO'<br />
&nbsp; 10&nbsp;&nbsp;&nbsp; 9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (UNIQUE SCAN) OF 'PK_SO' (UNIQUE)<br />
&nbsp; 11&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'SO_TYPE'<br />
&nbsp; 12&nbsp;&nbsp; 11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (UNIQUE SCAN) OF 'PK_SO_TYPE' (UNIQUE)<br />
&nbsp; 13&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'SO_HANDLE'<br />
&nbsp; 14&nbsp;&nbsp; 13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'PK_SO_HANDLE' (UNIQUE)</p>
<p>我们收集表格信息和结果集的信息:<br />
SQL&gt; select count(*) from CTRL_ASGN;<br />
&nbsp; COUNT(*)<br />
----------<br />
&nbsp;&nbsp; 1832469<br />
SQL&gt; select count(*) from status;<br />
&nbsp; COUNT(*)<br />
----------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1718</p>
<p>SQL&gt; select count(*) from so;<br />
&nbsp; COUNT(*)<br />
----------<br />
&nbsp;&nbsp;&nbsp; 300296</p>
<p>SQL&gt; select count(*) from so_type;<br />
&nbsp; COUNT(*)<br />
----------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 265</p>
<p>SQL&gt; select count(*) from so_handle;<br />
&nbsp; COUNT(*)<br />
----------<br />
&nbsp;&nbsp; 1296263&nbsp;&nbsp; </p>
<p>select count(*) from ctrl_asgn where&nbsp; CTRL_ASGN.STATE = 'B' AND CTRL_ASGN.STS = 'D';<br />
&nbsp; COUNT(*)<br />
----------<br />
&nbsp;&nbsp;&nbsp; 331490<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
select count(*) from so where SO.STATE= 'B' AND SO.HALT ='N';<br />
&nbsp; COUNT(*)<br />
----------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 361<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
select count(*) from so_handle where SO_HANDLE.HANDLE_TYPE_ID=1017 and SO_HANDLE.WORK_AREA_ID= 300101;<br />
&nbsp; COUNT(*)<br />
----------<br />
&nbsp;&nbsp;&nbsp;&nbsp; 30086</p>
<p>通过对上面这些信息进行分析，我们可以发现这个问题也可以归结为表格之间的连接顺序上面。通过将SO表做柱状图分析后，该SQL语句只需1秒钟即可出来。<br />
Analyze table so compute statistics for all indexed columns;</p>
<p>执行计划变成如下：<br />
Execution Plan<br />
----------------------------------------------------------<br />
&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT STATEMENT Optimizer=CHOOSE (Cost=273 Card=32 Bytes=3936)<br />
&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; NESTED LOOPS (Cost=273 Card=32 Bytes=3936)<br />
&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; NESTED LOOPS (Cost=153 Card=30 Bytes=2730)<br />
&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HASH JOIN (Cost=33 Card=30 Bytes=2130)<br />
&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NESTED LOOPS (Cost=31 Card=30 Bytes=1620)<br />
&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'STATUS' (Cost=2 Card=1 Bytes=25)<br />
&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'SO' (Cost=29 Card=59 Bytes=1711)<br />
&nbsp;&nbsp; 7&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'SO_0003' (NON-UNIQUE) (Cost=2 Card=59)<br />
&nbsp;&nbsp; 8&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'SO_TYPE' (Cost=1 Card=128 Bytes=2176)<br />
&nbsp;&nbsp; 9&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'SO_HANDLE' (Cost=4 Card=280 Bytes=5600)<br />
&nbsp; 10&nbsp;&nbsp;&nbsp; 9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'PK_SO_HANDLE' (UNIQUE) (Cost=3 Card=280)<br />
&nbsp; 11&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'CTRL_ASGN' (Cost=4 Card=13620 Bytes=435840)<br />
&nbsp; 12&nbsp;&nbsp; 11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'CTRL_ASGN_0003' (NON-UNIQUE) (Cost=2 Card=13620)</p>
<p>&nbsp;</p>
<p>3．&nbsp;Not exists的使用<br />
--停机保号用户数(除欠费)<br />
select 'XJ'||1||'180','停机保号用户数',count(distinct serviceid),1,'200509',groupid from cbq_lch_usage0 <br />
where subsidiaryid=1 and subid&lt;&gt;'02'&nbsp; and subid&lt;&gt;'06' and status='7' and <br />
serviceid not in (select serviceorderid from cbq_qf_usage1&nbsp; where status&lt;&gt;'3' and status &lt;&gt; '8') <br />
group by 'XJ'||1||'180','停机保号用户数',1,'200509',groupid ;</p>
<p>Execution Plan<br />
----------------------------------------------------------<br />
&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT STATEMENT Optimizer=RULE<br />
&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; SORT (GROUP BY)<br />
&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; FILTER<br />
&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'CBQ_LCH_USAGE0'<br />
&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'CBQ_QF_USAGE1'</p>
<p>Elapsed: 13:48:26.85</p>
<p>调整：<br />
not in 改成not exists<br />
create index idx_serviceorderid on cbq_qf_usage1(serviceorderid) nologging;</p>
<p>select 'XJ'||1||'180','停机保号用户数',count(distinct serviceid),1,'200509',a.groupid <br />
from cbq_lch_usage0 a<br />
where a.subsidiaryid=1 and a.subid&lt;&gt;'02'&nbsp; and a.subid&lt;&gt;'06' and a.status='7' <br />
and not exists(select 1 from cbq_qf_usage1 b where status&lt;&gt;'3' and status&lt;&gt;'8' and a.serviceid=b.serviceorderid)<br />
group by 'XJ'||1||'180','停机保号用户数',1,'200509',a.groupid;</p>
<p>Execution Plan<br />
----------------------------------------------------------<br />
&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT STATEMENT Optimizer=RULE<br />
&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; SORT (GROUP BY)<br />
&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; FILTER<br />
&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'CBQ_LCH_USAGE0'<br />
&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX) OF 'CBQ_QF_USAGE1'<br />
&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'IDX_SERVICEORDERID' </p>
<p>Elapsed: 00:00:01.36</p>
<p><br />
九．其他<br />
1．SELECT子句中避免使用 &#8216; * &#8216;<br />
当你想在SELECT子句中列出所有的COLUMN时,使用动态 SQL列引用 &#8216;*&#8217; 是一个方便的方法.不幸的是,这是一个非常低效的方法. 实际上,ORACLE在解析的过程中, 会将&#8217;*&#8217; 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间. <br />
2．用TRUNCATE替代DELETE<br />
3．使用表的别名(Alias)<br />
当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误.</p>
<p><br />
4.索引的等级<br />
&nbsp;一般情况索引等级如下：<br />
&nbsp;a) 等式比较比范围比较要高。<br />
&nbsp;b) 唯一性索引比非唯一性索引要高。<br />
&nbsp;c) 一般情况下单列索引等级要比复合索引高，但如果where子句中包含所&nbsp;&nbsp;有复合索引的字段，则复合索引等级高。<br />
&nbsp;例如：<br />
SELECT col1, ... <br />
FROM emp <br />
WHERE emp_name = 'GURRY' <br />
AND emp_no = 127 <br />
AND dept_no = 12 </p>
<p>Index1 (emp_name) <br />
Index2 (emp_no, dept_no, emp_name) <br />
ORACLE将使用索引Index2。</p>
<p>5.统计信息分析<br />
在现实当中，有关analyze分析有以下两种误区：</p>
<p>a) 只要对主要的或者关键的表格做分析即可。其实正确的应该是需要对所有涉及到的表格都做过分析。</p>
<p>b) 做一次分析后即可高枕无忧。事实上，一旦做过分析后，就应该定期更新这些统计信息，以保证统计信息的正确性。</p>
<p>6．Exists总比In快<br />
&nbsp;有许多人认为用Exists总比用In要快,这也是一个误区。有时用in反而比用Exists快。<br />
他们之间的区别如下：<br />
&nbsp;&nbsp;IN subquery，首先执行subquery，由subquery来驱动父查询。而Exists子查询则由父查询来驱动子查询。这就是两者之间的区别。<br />
&nbsp;所以如果子查询小的话，则可以采用in会快一些，如果子查询大的话，则采用exists会快一些。</p>
<p>7．&gt;与&gt;=<br />
&nbsp;大于或小于操作符一般情况下是不用调整的，因为它有索引就会采用索引查找，但有的情况下可以对它进行优化，如一个表有100万记录，一个数值型字段A，<br />
30万记录的A=0，30万记录的A=1，39万记录的A=2，1万记录的A=3。<br />
&nbsp;那么执行A&gt;2与A&gt;=3的效果就有很大的区别了，因为A&gt;2时ORACLE会先找出<br />
为2的记录索引再进行比较，而A&gt;=3时ORACLE则直接找到=3的记录索引。</p>
<p>8. 使用索引来避免排序<br />
&nbsp; 索引是排好序的，在某些情况下可以使用索引来避免排序。<br />
&nbsp; SELECT acc_name,&nbsp;acc_surname<br />
&nbsp; FROM account acct<br />
&nbsp; ORDER BY 1;</p>
<p>&nbsp; SELECT /*+ INDEX_ASC(acct acc_ndx1) */ acc_name,acc_surname<br />
&nbsp; FROM account acct;</p>
<p><br />
9.大对象操作<br />
&nbsp;<br />
a)Big Insert<br />
(1)direct insert(serial and parallel) <br />
insert /*+append*/into tab1 select * from tab2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Insert /*+append parallel(emp,8)*/ into emp&nbsp; select * from emp_bak;<br />
(2)nologging<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; insert into tab1 nologging select * from tab2;<br />
&nbsp;&nbsp;&nbsp; (3)Large extent size<br />
&nbsp;&nbsp; &nbsp;&nbsp;更大的extent可以获得更好的insert性能。<br />
&nbsp;(5)Large rollback segment</p>
<p>b)Large Index Create<br />
&nbsp; 大的索引extent size值<br />
&nbsp;&nbsp;&nbsp; 大的Sort_area_size值<br />
&nbsp; 采用nologging<br />
&nbsp; 采用parallel <br />
&nbsp; 大的临时表空间</p>
<p>alter session sort_area_size=100000000;<br />
create index xxx on aa(ab) nologging parallel 2;</p>
<p>&nbsp;c)Large Delete<br />
分几次delete。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><br />
附录一<br />
Hint全集<br />
174. /*+ALL_ROWS*/</p>
<p>　　表明对语句块选择基于开销的优化方法,并获得最佳吞吐量,使资源消耗最小化.例如:<br />
SELECT /*+ALL+_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='CCBZZP';</p>
<p>　　175. /*+FIRST_ROWS*/</p>
<p>　　表明对语句块选择基于开销的优化方法,并获得最佳响应时间,使资源消耗最小化.例如:<br />
SELECT /*+FIRST_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='CCBZZP';</p>
<p>　　176. /*+CHOOSE*/</p>
<p>　　表明如果数据字典中有访问表的统计信息,将基于开销的优化方法,并获得最佳的吞吐量;表明如果数据字典中没有访问表的统计信息,将基于规则开销的优化方法;例如:<br />
SELECT /*+CHOOSE*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='CCBZZP';</p>
<p>　　177. /*+ RULE*/</p>
<p>　　表明对语句块选择基于规则的优化方法.例如:<br />
SELECT /*+ RULE */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='CCBZZP';&nbsp; </p>
<p>　　178. /*+ FULL(TABLE)*/</p>
<p>　　表明对表选择全局扫描的方法.例如:<br />
SELECT /*+FULL(A)*/ EMP_NO,EMP_NAM FROM BSEMPMS A WHERE EMP_NO='CCBZZP';</p>
<p>　　179. /*+ROWID(TABLE)*/</p>
<p>　　提示明确表明对指定表根据ROWID进行访问.例如:<br />
SELECT /*+ROWID(BSEMPMS)*/ * FROM BSEMPMS WHERE ROWID&gt;='AAAAAAAAAAAAAA'<br />
AND EMP_NO='CCBZZP';</p>
<p>　　180. /*+CLUSTER(TABLE)*/ <br />
　<br />
　　提示明确表明对指定表选择簇扫描的访问方法,它只对簇对象有效.例如:<br />
SELECT /*+CLUSTER */ BSEMPMS.EMP_NO,DPT_NO FROM BSEMPMS,BSDPTMS<br />
WHERE DPT_NO='TEC304' AND BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;</p>
<p>181. /*+ INDEX(TABLE&nbsp;&nbsp; INDEX_NAME)*/<br />
/*+index(table ind_name) index(table ind_name)*/<br />
表明对表选择索引的扫描方法.例如:<br />
SELECT /*+INDEX(BSEMPMS SEX_INDEX) USE SEX_INDEX BECAUSE THERE ARE FEWMALE BSEMPMS */ FROM BSEMPMS WHERE SEX='M';</p>
<p>　　182. /*+INDEX_ASC(TABLE INDEX_NAME)*/</p>
<p>　　表明对表选择索引升序的扫描方法.例如:<br />
SELECT /*+INDEX_ASC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS WHERE DPT_NO='CCBZZP';</p>
<p>　　183. /*+INDEX_COMBINE*/</p>
<p>　　为指定表选择位图访问路经,如果INDEX_COMBINE中没有提供作为参数的索引,将选择出位图索引的布尔组合方式.例如:<br />
SELECT /*+INDEX_COMBINE(BSEMPMS SAL_BMI HIREDATE_BMI)*/ * FROM BSEMPMS<br />
WHERE SAL&lt;5000000 AND HIREDATE</p>
<p>　　184. /*+INDEX_JOIN(TABLE INDEX_NAME)*/</p>
<p>　　提示明确命令优化器使用索引作为访问路径.例如:<br />
SELECT /*+INDEX_JOIN(BSEMPMS SAL_HMI HIREDATE_BMI)*/ SAL,HIREDATE<br />
FROM BSEMPMS WHERE SAL&lt;60000;</p>
<p>　　185. /*+INDEX_DESC(TABLE INDEX_NAME)*/</p>
<p>　　表明对表选择索引降序的扫描方法.例如:<br />
SELECT /*+INDEX_DESC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS WHERE DPT_NO='CCBZZP';</p>
<p>　　186. /*+INDEX_FFS(TABLE INDEX_NAME)*/</p>
<p>　　对指定的表执行快速全索引扫描,而不是全表扫描的办法.例如:<br />
SELECT /*+INDEX_FFS(BSEMPMS IN_EMPNAM)*/ * FROM BSEMPMS WHERE DPT_NO='TEC305';</p>
<p>　　187. /*+ADD_EQUAL TABLE INDEX_NAM1,INDEX_NAM2,...*/</p>
<p>　　提示明确进行执行规划的选择,将几个单列索引的扫描合起来.例如:<br />
SELECT /*+INDEX_FFS(BSEMPMS IN_DPTNO,IN_EMPNO,IN_SEX)*/ * FROM BSEMPMS WHERE EMP_NO='CCBZZP' AND DPT_NO='TDC306';</p>
<p>　　188. /*+USE_CONCAT*/</p>
<p>　　对查询中的WHERE后面的OR条件进行转换为UNION ALL的组合查询.例如:<br />
SELECT /*+USE_CONCAT*/ * FROM BSEMPMS WHERE DPT_NO='TDC506' AND SEX='M';</p>
<p>　　189. /*+NO_EXPAND*/</p>
<p>　　对于WHERE后面的OR 或者IN-LIST的查询语句,NO_EXPAND将阻止其基于优化器对其进行扩展.例如:<br />
SELECT /*+NO_EXPAND*/ * FROM BSEMPMS WHERE DPT_NO='TDC506' AND SEX='M';</p>
<p>　　190. /*+NOWRITE*/</p>
<p>　　禁止对查询块的查询重写操作.</p>
<p>191. /*+REWRITE*/</p>
<p>　　可以将视图作为参数.</p>
<p>　　192. /*+MERGE(TABLE)*/</p>
<p>　　能够对视图的各个查询进行相应的合并.例如:<br />
SELECT /*+MERGE(V) */ A.EMP_NO,A.EMP_NAM,B.DPT_NO FROM BSEMPMS A (SELET DPT_NO<br />
,AVG(SAL) AS AVG_SAL FROM BSEMPMS B GROUP BY DPT_NO) Va WHERE A.DPT_NO=V.DPT_NO<br />
AND A.SAL&gt;V.AVG_SAL;</p>
<p>　　193. /*+NO_MERGE(TABLE)*/</p>
<p>　　对于有可合并的视图不再合并.例如:<br />
SELECT /*+NO_MERGE(V) */ A.EMP_NO,A.EMP_NAM,B.DPT_NO FROM BSEMPMS A (SELET DPT_NO<br />
,AVG(SAL) AS AVG_SAL FROM BSEMPMS B GROUP BY DPT_NO) V WHERE A.DPT_NO=V.DPT_NO<br />
AND A.SAL&gt;V.AVG_SAL;</p>
<p>　　194. /*+ORDERED*/</p>
<p>　　根据表出现在FROM中的顺序,ORDERED使ORACLE依此顺序对其连接.例如:<br />
SELECT /*+ORDERED*/ A.COL1,B.COL2,C.COL3 FROM TABLE1 A,TABLE2 B,TABLE3 C<br />
WHERE A.COL1=B.COL1 AND B.COL1=C.COL1;</p>
<p>　　195. /*+USE_NL(TABLE)*/</p>
<p>　　将指定表与嵌套的连接的行源进行连接,并把指定表作为内部表.例如:<br />
SELECT /*+ORDERED USE_NL(BSEMPMS)*/ BSDPTMS.DPT_NO,BSEMPMS.EMP_NO,BSEMPMS.EMP_NAM FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;</p>
<p>　　196. /*+USE_MERGE(TABLE)*/</p>
<p>　　将指定的表与其他行源通过合并排序连接方式连接起来.例如:<br />
SELECT /*+USE_MERGE(BSEMPMS,BSDPTMS)*/ * FROM BSEMPMS,BSDPTMS WHERE<br />
BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;</p>
<p>　　197. /*+USE_HASH(TABLE)*/</p>
<p>　　将指定的表与其他行源通过哈希连接方式连接起来.例如:<br />
SELECT /*+USE_HASH(BSEMPMS,BSDPTMS)*/ * FROM BSEMPMS,BSDPTMS WHERE<br />
BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;</p>
<p>　　198. /*+DRIVING_SITE(TABLE)*/</p>
<p>　　强制与ORACLE所选择的位置不同的表进行查询执行.例如:<br />
SELECT /*+DRIVING_SITE(DEPT)*/ * FROM BSEMPMS,DEPT@BSDPTMS WHERE BSEMPMS.DPT_NO=DEPT.DPT_NO;</p>
<p>　　199. /*+LEADING(TABLE)*/</p>
<p>　　将指定的表作为连接次序中的首表.</p>
<p>200. /*+CACHE(TABLE)*/</p>
<p>　　当进行全表扫描时,CACHE提示能够将表的检索块放置在缓冲区缓存中最近最少列表LRU的最近使用端例如:<br />
SELECT /*+FULL(BSEMPMS) CAHE(BSEMPMS) */ EMP_NAM FROM BSEMPMS;</p>
<p>　　201. /*+NOCACHE(TABLE)*/</p>
<p>　　当进行全表扫描时,CACHE提示能够将表的检索块放置在缓冲区缓存中最近最少列表LRU的最近使用端，例如:<br />
SELECT /*+FULL(BSEMPMS) NOCAHE(BSEMPMS) */ EMP_NAM FROM BSEMPMS;</p>
<p>　　202. /*+APPEND*/</p>
<p>　　直接插入到表的最后,可以提高速度.<br />
insert /*+append*/ into test1 select * from test4 ;</p>
<p>　　203. /*+NOAPPEND*/</p>
<p>　　通过在插入语句生存期内停止并行模式来启动常规插入.<br />
insert /*+noappend*/ into test1 select * from test4;</p>
<p>附录二<br />
STATSPACK包的使用指南<br />
1.oracle8.1.6开始引进statspack，statspack是诊断oracle性能的强有力的工具。<br />
2.安装前准备<br />
&nbsp;A.首先是系统参数的确认：<br />
job_query_processes：为了建立自动任务，执行数据收集，该参数要大于0<br />
time_statistics：为了收集操作系统计时信息等，需要将其设置为TRUE</p>
<p>B.建议最好是单独的为perfstat用户（即安装statspack要建的用户）单独建立数据表空间和临时表空间，数据表空间至少要有100M的空闲空间，否则创建statspack对象会失败，如果打算长期使用statspack，可以考虑建稍大些的数据表空间。<br />
3.安装 <br />
A.安装脚本<br />
安装的脚本所在目录是$ORACLE_HOME/rdbms/admin，在oracle8.1.6版本安装脚本是statscre.sql，之后 8.1.7版本开始就是spcreate.sql，安装所需用户在9i之前的需要internal或者拥有sysdba权限的用户，9i需要的用户是 sys（9i已经不存在internal用户了）<br />
执行安装脚本如下：<br />
SQL&gt; @$ORACLE_HOME/rdbms/admin/spcreate<br />
&nbsp;<br />
B. 在安装过程中，需要填写perfstat用户的密码，并且选择perfstat用户的数据表空间和临时表空间，安装完成之后，察看相应的.lis文件检查安装是否正确无误，有问题可以通过spdrop.sql完成statspack的卸载，重新运行spcreate.sql完成statspack的安装。</p>
<p>4.&nbsp; 测试<br />
最简单的statspack报告生成，运行两次statspack.snap，然后运行spreport.sql生成一个基于两个时间点的报告。如果是8.1.7.3之前版本的Oracle，需要修改spcpkg.sql，要将substr修改为substrb，如下位置：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select l_snap_id<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , p_dbid<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , p_instance_number<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , substr(sql_text,1,31) ? substrb(sql_text,1,31)<br />
&nbsp;<br />
建立简单的statspack报告过程如下：<br />
SQL&gt; execute statspack.snap (i_snap_level=&gt;10)<br />
PL/SQL procedure successfully completed.<br />
SQL&gt; execute statspack.snap<br />
PL/SQL procedure successfully completed.<br />
SQL&gt; @$ORACLE_HOME/rdbms/admin/spreport<br />
&nbsp;<br />
Spreport的执行过程中会列出需要选择的快照，你需要填写该报告描述的开始和结束的快照序号，并填写报告的文件名，当然可以不填，使用默认的报告文件名，默认的会生成在目录$ORACLE_HOME/rdbms/admin中<br />
这样就可以验证statspack已经正确的安装完成了<br />
&nbsp;<br />
自动收集statspack快照<br />
正常在真正的环境下，我们是需要连续的采样一段时间，这样生成的statspack才能更好的反映系统的现状，我们是可以通过spauto.sql来自动收集数据的。<br />
&nbsp;<br />
主要可能会设计到修改如下部分的内容<br />
variable jobno number;<br />
variable instno number;<br />
begin<br />
&nbsp; select instance_number into :instno from v$instance;<br />
&nbsp; dbms_job.submit(:jobno, 'statspack.snap;', trunc(sysdate+1/24,'HH'), 'trunc(SYSDATE+1/24,''HH'')', TRUE, :instno);<br />
&nbsp; commit;<br />
end;<br />
/<br />
主要是修改1/24这个值，目前是一个小时自动收集一次数据，如果要改动为半个小时收集一次数据就修改为1/48,同理，进行或大或小的修改。<br />
&nbsp;<br />
执行后，可以在spauto.lis文件中看到当前自动收集数据的job号等信息。当想要生成statspack报告的时候，只要选择任何两个不跨越停机时间的快照序号就可以了。注意，statspack是不能跨越停机的。</p>
</div>
<img src ="http://www.blogjava.net/caizh2009/aggbug/288355.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-07-25 16:32 <a href="http://www.blogjava.net/caizh2009/articles/288355.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle中视图的创建和处理方法</title><link>http://www.blogjava.net/caizh2009/articles/287787.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Tue, 21 Jul 2009 15:13:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/287787.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/287787.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/287787.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/287787.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/287787.html</trackback:ping><description><![CDATA[图是基于一个表或多个表或视图的逻辑表，本身不包含数据，通过它可以对表里面的数据进行查询和修改。视图基于的表称为基表，Oracle的数据库对象分为五种：表，视图，序列，索引和同义词。
<p>视图是存储在数据字典里的一条select语句。通过创建视图可以提取数据的逻辑上的集合或组合。</p>
<p><strong>视图的优点：</strong></p>
<p>1.对数据库的访问，因为视图可以有选择性的选取数据库里的一部分。</p>
<p>2.用户通过简单的查询可以从复杂查询中得到结果。</p>
<p>3.维护数据的独立性，试图可从多个表检索数据。</p>
<p>4.对于相同的数据可产生不同的视图。</p>
<p><strong>视图分为简单视图和复杂视图：</strong></p>
<p>1、简单视图只从单表里获取数据，复杂视图从多表；</p>
<p>2、简单视图不包含函数和数据组，复杂视图包含；</p>
<p>3、简单视图可以实现DML操作，复杂视图不可以。</p>
<p><strong>视图的创建：</strong></p>
<p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#999999" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre>CREATE [OR REPLACE] [FORCE|NOFORCE] VIEW view_name
            <p>&nbsp;</p>
            <p>[(alias[, alias]...)]</p>
            <p>AS subquery<br />
            [WITH CHECK OPTION [CONSTRAINT constraint]]<br />
            [WITH READ ONLY]</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>其中：OR REPLACE&nbsp;&nbsp;&nbsp; ：若所创建的试图已经存在，ORACLE自动重建该视图；</p>
<p>FORCE：不管基表是否存在ORACLE都会自动创建该视图；</p>
<p>NOFORCE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：只有基表都存在ORACLE才会创建该视图：</p>
<p>alias：为视图产生的列定义的别名；</p>
<p>subquery&nbsp; ：一条完整的SELECT语句，可以在该语句中定义别名；</p>
<p>WITH CHECK OPTION&nbsp; ：插入或修改的数据行必须满足视图定义的约束；</p>
<p>WITH READ ONLY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：该视图上不能进行任何DML操作。</p>
<p>例如：
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#999999" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><br />
            CREATE OR REPLACE VIEW dept_sum_vw(name,minsal,maxsal,avgsal)<br />
            AS SELECT d.dname,min(e.sal),max(e.sal),avg(e.sal)<br />
            FROM&nbsp;&nbsp;&nbsp; emp e,dept d<br />
            WHERE e.deptno=d.deptno<br />
            GROUP BY d.dname;</pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p><strong>视图的定义原则：</strong></p>
<p>1.视图的查询可以使用复杂的SELECT语法，包括连接/分组查询和子查询；</p>
<p>2.在没有WITH CHECK OPTION和 READ ONLY 的情况下，查询中不能使用ORDER BY 子句；</p>
<p>3.如果没有为CHECK OPTION约束命名，系统会自动为之命名，形式为SYS_Cn；</p>
<p>4.OR REPLACE选项可以不删除原视图便可更改其定义并重建，或重新授予对象权限。</p>
<p><strong>视图的查询：</strong></p>
<p>视图创建成功后，可以从视图中检索数据，这点和从表中检索数据一样。</p>
<p>还可以查询视图的全部信息和指定的数据行和列。 如：检索数据：</p>
<p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#999999" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre>SQL&gt;SELECT * FROM dept_sum_vw；</pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p><strong>查询视图定义：</strong></p>
<p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#999999" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre>SELECT view_name,text from user_views;</pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>其中text显示的内容为视图定义的SELECT语句，可通过DESC USER_VIEWS 得到相关信息。</p>
<p><strong>修改视图：</strong></p>
<p>通过OR REPLACE 重新创建同名视图即可。</p>
<p><strong>视图上的DML 操作：</strong></p>
<p><strong>DML操作应遵循的原则：</strong></p>
<p>1.简单视图可以执行DML操作；</p>
<p>2.在视图包含GROUP 函数，GROUP BY子句，DISTINCT关键字时不能</p>
<p>删除数据行；</p>
<p>3.在视图不出现下列情况时可通过视图修改基表数据或插入数据：</p>
<p>a.视图中包含GROUP 函数，GROUP BY子句，DISTINCT关键字；</p>
<p>b.使用表达式定义的列；</p>
<p>c.ROWNUM伪列。</p>
<p>d.基表中未在视图中选择的其他列定义为非空且无默认值。</p>
<p>视图可用于保持数据库的完整性，但作用有限。</p>
<p>通过视图执行引用完整性约束可在数据库级执行约束。</p>
<p><strong>WITH CHECK OPTION 子句限定：</strong></p>
<p>通过视图执行的INSERTS和UPDATES操作不能创建该视图检索不到的数据行，因为它会对插入或修改的数据行执行完整性约束和数据有效性检查。</p>
<p>例如：
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#999999" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><br />
            CREATE OR REPLACE VIEW vw_emp20<br />
            AS SELECT * FROM emp<br />
            WHERE deptno=20<br />
            WITH CHECK OPTION constraint vw_emp20_ck;</pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>视图 已建立。</p>
<p>查询结果：</p>
<p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#999999" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre>SELECT empno,ename,job FROM vw_emp20;<br />
            <br />
            EMPNO&nbsp;&nbsp;&nbsp; ENAME&nbsp;&nbsp;&nbsp; JOB<br />
            ---------------------&nbsp; -------------- -------------<br />
            7369&nbsp;&nbsp;&nbsp;&nbsp; SMITH&nbsp;&nbsp;&nbsp; CLERK<br />
            7566&nbsp;&nbsp;&nbsp;&nbsp; JONES&nbsp;&nbsp; MANAGER<br />
            7902&nbsp;&nbsp;&nbsp;&nbsp; FORD&nbsp;&nbsp;&nbsp; ANALYST</pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>修改：</p>
<p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#999999" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><br />
            UPDATE vw_emp20<br />
            SET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; deptno=20<br />
            WHERE&nbsp;&nbsp; empno=7902;<br />
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>将产生错误：</p>
<p>UPDATE vw_emp20</p>
<p>*</p>
<p>ERROR 位于第一行：</p>
<p>ORA-01402：视图WITH CHECK OPTION 违反WHERE 子句</p>
<p>视图的删除：DROP VIEW VIEW_NAME语句删除视图。删除视图的定义不影响基表中的数据。只有视图所有者和具备DROP VIEW权限的用户可以删除视图。视图被删除后，基于被删除视图的其他视图或应用将无效。</p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/287787.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-07-21 23:13 <a href="http://www.blogjava.net/caizh2009/articles/287787.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle中的Union、Union All、Intersect、Minus </title><link>http://www.blogjava.net/caizh2009/articles/287782.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Tue, 21 Jul 2009 14:16:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/287782.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/287782.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/287782.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/287782.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/287782.html</trackback:ping><description><![CDATA[<p>众所周知的几个结果集集合操作命令，今天详细地测试了一下，发现一些问题，记录备考。</p>
<p>假设我们有一个表Student，包括以下字段与数据：</p>
<p>drop table student;</p>
<p>create table student<br />
(<br />
id int primary key,<br />
name nvarchar2(50) not null,<br />
score number not null<br />
);</p>
<p>insert into student values(1,'Aaron',78);<br />
insert into student values(2,'Bill',76);<br />
insert into student values(3,'Cindy',89);<br />
insert into student values(4,'Damon',90);<br />
insert into student values(5,'Ella',73);<br />
insert into student values(6,'Frado',61);<br />
insert into student values(7,'Gill',99);<br />
insert into student values(8,'Hellen',56);<br />
insert into student values(9,'Ivan',93);<br />
insert into student values(10,'Jay',90);</p>
<p>commit;</p>
<ul>
    <li><strong>Union和Union All的区别。</strong> </li>
</ul>
<p>select *<br />
from student<br />
where id &lt; 4</p>
<p>union</p>
<p>select *<br />
from student<br />
where id &gt; 2 and id &lt; 6</p>
<p>结果将是</p>
<p>1&nbsp;&nbsp;&nbsp; Aaron&nbsp;&nbsp;&nbsp; 78<br />
2&nbsp;&nbsp;&nbsp; Bill&nbsp;&nbsp;&nbsp; 76<br />
3&nbsp;&nbsp;&nbsp; Cindy&nbsp;&nbsp;&nbsp; 89<br />
4&nbsp;&nbsp;&nbsp; Damon&nbsp;&nbsp;&nbsp; 90<br />
5&nbsp;&nbsp;&nbsp; Ella&nbsp;&nbsp;&nbsp; 73</p>
<p>如果换成Union All连接两个结果集，则返回结果是：</p>
<p>1&nbsp;&nbsp;&nbsp; Aaron&nbsp;&nbsp;&nbsp; 78<br />
2&nbsp;&nbsp;&nbsp; Bill&nbsp;&nbsp;&nbsp; 76<br />
3&nbsp;&nbsp;&nbsp; Cindy&nbsp;&nbsp;&nbsp; 89<br />
3&nbsp;&nbsp;&nbsp; Cindy&nbsp;&nbsp;&nbsp; 89<br />
4&nbsp;&nbsp;&nbsp; Damon&nbsp;&nbsp;&nbsp; 90<br />
5&nbsp;&nbsp;&nbsp; Ella&nbsp;&nbsp;&nbsp; 73</p>
<p>可以看到，<strong>Union和Union All的区别之一在于对重复结果的处理。</strong></p>
<p>接下来我们将两个子查询的顺序调整一下，改为</p>
<p>--Union</p>
<p>select *<br />
from student<br />
where id &gt; 2 and id &lt; 6</p>
<p>union</p>
<p>select *<br />
from student<br />
where id &lt; 4</p>
<p>看看执行结果是否和你期望的一致？</p>
<p>--Union All</p>
<p>select *<br />
from student<br />
where id &gt; 2 and id &lt; 6</p>
<p>union all</p>
<p>select *<br />
from student<br />
where id &lt; 4</p>
<p>那么这个呢？</p>
<p>据此我们可知，<strong>区别之二在于对排序的处理。</strong>Union All将按照关联的次序组织数据，而Union将进行依据一定规则进行排序。那么这个规则是？我们换个查询方式看看：</p>
<p>select score,id,name<br />
from student<br />
where id &gt; 2 and id &lt; 6</p>
<p>union</p>
<p>select score,id,name<br />
from student<br />
where id &lt; 4</p>
<p>结果如下：</p>
<p>73&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp; Ella<br />
76&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; Bill<br />
78&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; Aaron<br />
89&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; Cindy<br />
90&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; Damon</p>
<p>和我们预料的一致：将会按照字段的顺序进行排序。之前我们的查询是基于id,name,score的字段顺序，那么结果集将按照id优先进行排序；而现在新的字段顺序也改变了查询结果的排序。并且，是按照给定字段a,b,c...的顺序进行的order by。即结果是order by a,b,c...........的。我们看下一个查询：</p>
<p>select score,id,name<br />
from student<br />
where id &gt; 2</p>
<p>union</p>
<p>select score,id,name<br />
from student<br />
where id &lt; 4</p>
<p>结果如下：</p>
<p>56&nbsp;&nbsp;&nbsp; 8&nbsp;&nbsp;&nbsp; Hellen<br />
61&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp; Frado<br />
73&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp; Ella<br />
76&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; Bill<br />
78&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; Aaron<br />
89&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; Cindy<br />
90&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; Damon<br />
90&nbsp;&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp; Jay<br />
93&nbsp;&nbsp;&nbsp; 9&nbsp;&nbsp;&nbsp; Ivan<br />
99&nbsp;&nbsp;&nbsp; 7&nbsp;&nbsp;&nbsp; Gill</p>
<p>可以看到，对于score相同的记录，将按照下一个字段id进行排序。如果我们想自行控制排序，是不是用order by指定就可以了呢？答案是肯定的，不过在写法上有需要注意的地方：</p>
<p>select score,id,name<br />
from student<br />
where id &gt; 2 and id &lt; 7</p>
<p>union</p>
<p>select score,id,name<br />
from student<br />
where id &lt; 4</p>
<p>union</p>
<p>select score,id,name<br />
from student<br />
where id &gt; 8<br />
order by id desc</p>
<p><strong>order by子句必须写在最后一个结果集里，并且其排序规则将改变操作后的排序结果。对于Union、Union All、Intersect、Minus都有效。</strong></p>
<p><strong>=================================================================================================================</strong></p>
<p>Intersect和Minus的操作和Union基本一致，这里一起总结一下：</p>
<p>Union，对两个结果集进行并集操作，不包括重复行，同时进行默认规则的排序；</p>
<p>Union All，对两个结果集进行并集操作，<strong>包括重复行</strong>，<strong>不进行排序</strong>；</p>
<p>Intersect，对两个结果集进行交集操作，不包括重复行，同时进行默认规则的排序；</p>
<p>Minus，对两个结果集进行差操作，不包括重复行，同时进行默认规则的排序。</p>
<p>可以在最后一个结果集中指定Order by子句改变排序方式。</p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/287782.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-07-21 22:16 <a href="http://www.blogjava.net/caizh2009/articles/287782.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle PL-SQL中左右连接--详解</title><link>http://www.blogjava.net/caizh2009/articles/287780.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Tue, 21 Jul 2009 14:05:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/287780.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/287780.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/287780.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/287780.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/287780.html</trackback:ping><description><![CDATA[<p>数据表的连接有: <br />
1、内连接(自然连接): 只有两个表相匹配的行才能在结果集中出现 <br />
2、外连接: 包括 <br />
（1）左外连接(左边的表不加限制) <br />
（2）右外连接(右边的表不加限制) <br />
（3）全外连接(左右两表都不加限制) <br />
3、自连接(连接发生在一张基表内) <br />
select a.studentno, a.studentname, b.classname<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from students a, classes b<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where a.classid(+) = b.classid;<br />
（另外一种写法：<br />
select a.studentno,a.studentname,b.classname<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from students&nbsp;right join class on students.classid=class.classid<br />
）<br />
STUDENTNO STUDENTNAM CLASSNAME<br />
---------- ---------- ------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 周虎&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一年级一班<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 周林&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一年级二班<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一年级三班<br />
以上语句是右连接：<br />
即"(+)"所在位置的另一侧为连接的方向，右连接说明等号右侧的所有<br />
记录均会被显示，无论其在左侧是否得到匹配。也就是说上例中，无<br />
论会不会出现某个班级没有一个学生的情况，这个班级的名字都会在<br />
查询结构中出现。<br />
即是右连接是以右边这个表为基准，左表不足的地方用NULL填充</p>
<p><br />
反之： <br />
select a.studentno, a.studentname, b.classname<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from students a, classes b<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where a.classid = b.classid(+);<br />
</p>
<p>（另外一种写法：<br />
select a.studentno,a.studentname,b.classname<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from students&nbsp;left join class on students.classid=class.classid<br />
）<br />
<br />
STUDENTNO STUDENTNAM CLASSNAME<br />
---------- ---------- ------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 周虎&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一年级一班<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 周林&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一年级二班<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3 钟林达</p>
<p>则是左连接，无论这个学生有没有一个能在一个班级中得到匹配的部门号，<br />
这个学生的记录都会被显示。<br />
</p>
<p>即是左连接是以左边这个表为基准，右表表不足的地方用NULL填充<br />
<br />
select a.studentno, a.studentname, b.classname<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from students a, classes b<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where a.classid = b.classid;<br />
（另外一种写法：<br />
select a.studentno,a.studentname,b.classname<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from students&nbsp;inner join class on students.classid=class.classid<br />
）</p>
<p>这个则是通常用到的内连接,显示两表都符合条件的记录</p>
<p>总之,</p>
<p>左连接显示左边全部的和右边与左边相同的 <br />
右连接显示右边全部的和左边与右边相同的 <br />
内连接是只显示满足条件的!</p>
<p>&nbsp;</p>
顺便问下：有谁知道oracle左连接的两种写法的差异？<br />
<br />
<div class="t_msgfont" id="message6158053">有两个表T1和T2，两个表除了主键索引外均无其他索引，这两个表由T1.F1(主键)，T2.F2(主键)进行左连接，SQL语句有两种写法：<br />
1. SELECT * FROM T1,T2 WHERE T1.F1=T2.F2(+)<br />
2. SELECT * FROM T1 LEFT JOIN T2 ON T1.F1=T2.F2<br />
<br />
当查看1的执行计划时发现T1为全表扫描，T2为索引扫描。<br />
当查看2的执行计划时发现两个表均为全表扫描。<br />
</div>
<img src ="http://www.blogjava.net/caizh2009/aggbug/287780.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-07-21 22:05 <a href="http://www.blogjava.net/caizh2009/articles/287780.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用DB Link两步搞定Oracle两个数据库间的表同步</title><link>http://www.blogjava.net/caizh2009/articles/282042.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Sat, 13 Jun 2009 07:57:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/282042.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/282042.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/282042.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/282042.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/282042.html</trackback:ping><description><![CDATA[1，在目标机上建立Oracle DB Link：<br />
A，在network/admin/tnsname.ora文件中加入源库的连接信息，如：<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #000000">AAA</span><span style="color: #000000">=</span><span style="color: #000000"><br />
&nbsp;&nbsp;(DESCRIPTION&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;(ADDRESS&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(PROTOCOL&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;TCP)(HOST&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">10.5.1.3</span><span style="color: #000000">)(PORT&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">1521</span><span style="color: #000000">))<br />
&nbsp;&nbsp;&nbsp;&nbsp;(CONNECT_DATA&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(SERVER&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;DEDICATED)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(SERVICE_NAME&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;AAA)<br />
&nbsp;&nbsp;&nbsp;&nbsp;)<br />
&nbsp;&nbsp;)</span></div>
<br />
B，在目标机上用sqlplus user/pwd登录。<br />
C，用如下命令建立DB Link:<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #000000">create&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;database&nbsp;link&nbsp;AAA_LINK&nbsp;connect&nbsp;to&nbsp;user&nbsp;identified&nbsp;by&nbsp;pwd&nbsp;using&nbsp;</span><span style="color: #000000">'</span><span style="color: #000000">AAA</span><span style="color: #000000">'</span><span style="color: #000000">;<br />
</span></div>
命令说明：<br />
CREATE PUBLIC DATABASE LINK 数据库链接名 CONNECT TO 用户名 IDENTIFIED BY 密码 USING &#8216;本地配置的数据的实例名&#8217;;<br />
如果建立成功，会提示：Database link created.<br />
<br />
2，使用如下脚本，即可同步数据表：<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #008000">#</span><span style="color: #008000">!/bin/sh<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top"  alt="" />#&nbsp;to&nbsp;sync&nbsp;table&nbsp;A&nbsp;to&nbsp;BBB&nbsp;database&nbsp;from&nbsp;AAA&nbsp;database</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000">sqlplus&nbsp;user</span><span style="color: #000000">/</span><span style="color: #000000">pwd</span><span style="color: #800080">@BBB</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #0000ff">EOF</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">#</span><span style="color: #008000">这里是BBB上的数据库和密码还有实例名，请按照实际情况修改</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">truncate</span><span style="color: #000000">&nbsp;table&nbsp;A;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top"  alt="" />insert&nbsp;into&nbsp;A&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">select</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;from&nbsp;b_schema</span><span style="color: #000000">.</span><span style="color: #000000">A</span><span style="color: #800080">@AAA_LINK</span><span style="color: #000000">;&nbsp;</span><span style="color: #008000">#</span><span style="color: #008000">这里是指向要同步的来源表,表名必须是&lt;表所有者&gt;.&lt;表名&gt;@&lt;dblink&nbsp;name&gt;</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000">commit;</span></div>
<br />
<br />
PS：需要DB支持Advanced replication功能，是否支持，可用如下SQL查看：<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #0000ff">select</span><span style="color: #000000">&nbsp;</span><span style="color: #808080">*</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">from</span><span style="color: #000000">&nbsp;v$</span><span style="color: #0000ff">option</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">where</span><span style="color: #000000">&nbsp;PARAMETER</span><span style="color: #808080">=</span><span style="color: #ff0000">'</span><span style="color: #ff0000">Advanced&nbsp;replication</span><span style="color: #ff0000">'</span><span style="color: #000000">;</span></div>
如果是返回True就表示支持。<br />
<br />
<br />
<img src ="http://www.blogjava.net/caizh2009/aggbug/282042.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-06-13 15:57 <a href="http://www.blogjava.net/caizh2009/articles/282042.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle 查找表外键</title><link>http://www.blogjava.net/caizh2009/articles/280069.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 04 Jun 2009 12:49:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/280069.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/280069.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/280069.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/280069.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/280069.html</trackback:ping><description><![CDATA[有一个表A,如果想知道这个表的主键被哪些表作为外键，则使用下面语句 <br />
<br />
select * from <span class="hilite2">user_constraints</span> t where t.r_constraint_name = 'PK_PM_PRD' <br />
<br />
其中 'PK_PM_PRD' 是你这个表的主键的名称 <br />
<br />
<br />
<br />
select <br />
a.owner 外键拥有者, <br />
a.table_name 外键表, <br />
substr(c.column_name,1,127) 外键列, <br />
b.owner 主键拥有者, <br />
b.table_name 主键表, <br />
substr(d.column_name,1,127) 主键列 <br />
from <br />
<span class="hilite2">user_constraints</span> a, <br />
<span class="hilite2">user_constraints</span> b, <br />
user_cons_columns c, <br />
user_cons_columns d <br />
where <br />
&nbsp;&nbsp;&nbsp; a.r_constraint_name=b.constraint_name <br />
and a.constraint_type='R' <br />
and b.constraint_type='P' <br />
and a.r_owner=b.owner <br />
and a.constraint_name=c.constraint_name <br />
and b.constraint_name=d.constraint_name <br />
and a.owner=c.owner <br />
and a.table_name=c.table_name <br />
and b.owner=d.owner <br />
and b.table_name=d.table_name <br />
<img src ="http://www.blogjava.net/caizh2009/aggbug/280069.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-06-04 20:49 <a href="http://www.blogjava.net/caizh2009/articles/280069.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle Exception</title><link>http://www.blogjava.net/caizh2009/articles/271956.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 21 May 2009 05:53:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/271956.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/271956.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/271956.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/271956.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/271956.html</trackback:ping><description><![CDATA[<p>BEGIN<br />
　　SELECT ...<br />
　　SELECT ...<br />
　　SELECT ...<br />
　　...<br />
　　EXCEPTION<br />
　　WHEN NO_DATA_FOUND THEN -- catches all &#8217;no data found&#8217; errors<br />
　　<br />
　　2、异常的分类<br />
　　<br />
　　有两种类型的异常，一种为内部异常，一种为用户自定义异常，内部异常是执行期间返回到PL/SQL块的ORACLE错误或由PL/SQL代码的某操作引起的错误，如除数为零或内存溢出的情况。用户自定义异常由开发者显示定义，在PL/SQL块中传递信息以控制对于应用的错误处理。<br />
　　<br />
　　每当PL/SQL违背了ORACLE原则或超越了系统依赖的原则就会隐式的产生内部异常。因为每个ORACLE错误都有一个号码并且在PL/SQL中异常通过名字处理，ORACLE提供了预定义的内部异常。如SELECT INTO 语句不返回行时产生的ORACLE异常NO_DATA_FOUND。对于预定义异常，现将最常用的异常列举如下：<br />
　　exception　 oracle error　 sqlcode value　 condition<br />
　　no_data_found　　　　　　　　　　　　　 ora-01403　 +100　 select into 语句没有符合条件的记录返回<br />
　　too_many_rows　 ora-01422　 -1422　 select into 语句符合条件的记录有多条返回<br />
　　dup_val_on_index　 ora-00001　 -1　 对于数据库表中的某一列，该列已经被限制为唯一索引，程序试图存储两个重复的值<br />
　　value_error　 ora-06502　 -6502　 在转换字符类型，截取或长度受限时，会发生该异常，如一个字符分配给一个变量，而该变量声明的长度比该字符短，就会引发该异常<br />
　　storage_error　 ora-06500　 -6500　 内存溢出<br />
　　zero_divide　 ora-01476　 -1476　 除数为零<br />
　　case_not_found　 ora-06592　 -6530　 对于选择case语句，没有与之相匹配的条件，同时，也没有else语句捕获其他的条件<br />
　　cursor_already_open　 ora-06511　 -6511　 程序试图打开一个已经打开的游标<br />
　　timeout_on_resource　 ora-00051　 -51　 系统在等待某一资源，时间超时<br />
　　<br />
　　如果要处理未命名的内部异常，必须使用OTHERS异常处理器或PRAGMA EXCEPTION_INIT 。PRAGMA由编译器控制，或者是对于编译器的注释。PRAGMA在编译时处理，而不是在运行时处理。EXCEPTION_INIT告诉编译器将异常名与ORACLE错误码结合起来，这样可以通过名字引用任意的内部异常，并且可以通过名字为异常编写一适当的异常处理器。<br />
　　<br />
　　在子程序中使用EXCEPTION_INIT的语法如下：<br />
　　PRAGMA EXCEPTION_INIT(exception_name, -Oracle_error_number);<br />
　　<br />
　　在该语法中，异常名是声明的异常，下例是其用法：<br />
　　DECLARE<br />
　　deadlock_detected EXCEPTION;<br />
　　PRAGMA EXCEPTION_INIT(deadlock_detected, -60);<br />
　　BEGIN<br />
　　... -- Some operation that causes an ORA-00060 error<br />
　　EXCEPTION<br />
　　WHEN deadlock_detected THEN<br />
　　-- handle the error<br />
　　END;<br />
　　<br />
　　对于用户自定义异常，只能在PL/SQL块中的声明部分声明异常，异常的名字由EXCEPTION关键字引入：<br />
　　reserved_loaned Exception<br />
　　<br />
　　产生异常后，控制传给了子程序的异常部分，将异常转向各自异常控制块，必须在代码中使用如下的结构处理错误：<br />
　　Exception<br />
　　When exception1 then<br />
　　Sequence of statements;<br />
　　When exception2 then<br />
　　Sequence of statements;<br />
　　When others then<br />
　　<br />
　　3、异常的抛出<br />
　　<br />
　　由三种方式抛出异常<br />
　　<br />
　　1． 通过PL/SQL运行时引擎<br />
　　<br />
　　2. 使用RAISE语句<br />
　　<br />
　　3. 调用RAISE_APPLICATION_ERROR存储过程<br />
　　<br />
　　当数据库或PL/SQL在运行时发生错误时，一个异常被PL/SQL运行时引擎自动抛出。异常也可以通过RAISE语句抛出<br />
　　RAISE exception_name;<br />
　　<br />
　　显式抛出异常是程序员处理声明的异常的习惯用法，但RAISE不限于声明了的异常，它可以抛出任何任何异常。例如，你希望用TIMEOUT_ON_RESOURCE错误检测新的运行时异常处理器，你只需简单的在程序中使用下面的语句：<br />
　　RAISE TIMEOUT_ON_RESOUCE;<br />
　　<br />
　　比如下面一个订单输入的例子，若当订单小于库存数量，则抛出异常，并且捕获该异常，处理异常<br />
　　DECLARE<br />
　　inventory_too_low EXCEPTION;<br />
　　<br />
　　---其他声明语句<br />
　　BEGIN<br />
　　IF order_rec.qty&gt;inventory_rec.qty THEN<br />
　　RAISE inventory_too_low;<br />
　　END IF<br />
　　EXCEPTION<br />
　　WHEN inventory_too_low THEN<br />
　　order_rec.staus:='backordered';<br />
　　END;<br />
　　<br />
　　RAISE_APPLICATION_ERROR内建函数用于抛出一个异常并给异常赋予一个错误号以及错误信息。自定义异常的缺省错误号是+1,缺省信息是User_Defined_Exception。RAISE_APPLICATION_ERROR函数能够在pl/sql程序块的执行部分和异常部分调用，显式抛出带特殊错误号的命名异常。　 Raise_application_error(error_number,message[,true,false]))<br />
　　<br />
　　错误号的范围是-20,000到-20,999。错误信息是文本字符串，最多为2048字节。TRUE和FALSE表示是添加(TRUE)进错误堆(ERROR STACK)还是覆盖(overwrite)错误堆(FALSE)。缺省情况下是FALSE。<br />
　　<br />
　　如下代码所示：<br />
　　IF product_not_found THEN<br />
　　RAISE_APPLICATION_ERROR(-20123,'Invald product code' TRUE);<br />
　　END IF;<br />
　　<br />
　　4、异常的处理<br />
　　<br />
　　PL/SQL程序块的异常部分包含了程序处理错误的代码，当异常被抛出时，一个异常陷阱就自动发生，程序控制离开执行部分转入异常部分,一旦程序进入异常部分就不能再回到同一块的执行部分。下面是异常部分的一般语法：<br />
　　EXCEPTION<br />
　　WHEN exception_name THEN<br />
　　Code for handing exception_name<br />
　　[WHEN another_exception THEN<br />
　　Code for handing another_exception]<br />
　　[WHEN others THEN<br />
　　code for handing any other exception.]<br />
　　<br />
　　用户必须在独立的WHEN子串中为每个异常设计异常处理代码，WHEN OTHERS子串必须放置在最后面作为缺省处理器处理没有显式处理的异常。当异常发生时，控制转到异常部分，ORACLE查找当前异常相应的WHEN..THEN语句，捕捉异常，THEN之后的代码被执行，如果错误陷阱代码只是退出相应的嵌套块，那么程序将继续执行内部块 END后面的语句。如果没有找到相应的异常陷阱，那么将执行WHEN OTHERS。在异常部分WHEN 子串没有数量限制。<br />
　　EXCEPTION<br />
　　WHEN inventory_too_low THEN<br />
　　order_rec.staus:='backordered';<br />
　　replenish_inventory(inventory_nbr=&gt;<br />
　　inventory_rec.sku,min_amount=&gt;order_rec.qty-inventory_rec.qty);<br />
　　WHEN discontinued_item THEN<br />
　　--code for discontinued_item processing<br />
　　WHEN zero_divide THEN<br />
　　--code for zero_divide<br />
　　WHEN OTHERS THEN<br />
　　--code for any other exception<br />
　　END;<br />
　　<br />
　　当异常抛出后，控制无条件转到异常部分，这就意味着控制不能回到异常发生的位置，当异常被处理和解决后，控制返回到上一层执行部分的下一条语句。<br />
　　BEGIN<br />
　　DECLARE<br />
　　bad_credit exception;<br />
　　BEGIN<br />
　　RAISE bad_credit;<br />
　　--发生异常，控制转向；<br />
　　EXCEPTION<br />
　　WHEN bad_credit THEN<br />
　　dbms_output.put_line('bad_credit');<br />
　　END;<br />
　　--bad_credit异常处理后，</p>
<p>文章出处：http://www.diybl.com/course/7_databases/oracle/Oracleshl/200869/123806.html</p>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/271956.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-05-21 13:53 <a href="http://www.blogjava.net/caizh2009/articles/271956.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>数据结构</title><link>http://www.blogjava.net/caizh2009/articles/270625.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 14 May 2009 07:52:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/270625.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/270625.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/270625.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/270625.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/270625.html</trackback:ping><description><![CDATA[<font style="font-size: 14pt" color="#295200"><strong>B树、B-树、B+树、B*树都是什么</strong></font> 
<img src ="http://www.blogjava.net/caizh2009/aggbug/270625.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-05-14 15:52 <a href="http://www.blogjava.net/caizh2009/articles/270625.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ORACLE索引与高性能SQL介绍</title><link>http://www.blogjava.net/caizh2009/articles/270620.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 14 May 2009 07:46:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/270620.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/270620.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/270620.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/270620.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/270620.html</trackback:ping><description><![CDATA[<strong>什么是索引</strong><br />
　　<br />
　　索引是建立在表的一列或多个列上的辅助对象，目的是加快访问表中的数据；<br />
　　<br />
　　<a class="channel_keylink" href="http://oracle.chinaitlab.com/" target="_blank">Oracle</a><a class="channel_keylink" href="http://www.storworld.com/" target="_blank">存储</a>索引的数据结构是B*树，位图索引也是如此，只不过是叶子节点不同B*数索引；<br />
　　<br />
　　索引由根节点、分支节点和叶子节点组成，上级索引块包含下级索引块的索引数据，叶节点包含索引数据和确定行实际位置的rowid。<br />
　　<br />
　　使用索引的目的<br />
　　加快查询速度<br />
　　减少I/O操作<br />
　　消除磁盘排序<br />
　　<br />
　　何时使用索引<br />
　　查询返回的记录数<br />
　　排序表&lt;40%<br />
　　非排序表 &lt;7%<br />
　　表的碎片较多（频繁增加、删除）<br />
　　<br />
　　索引的种类<br />
　　非唯一索引（最常用）<br />
　　唯一索引<br />
　　位图索引<br />
　　局部有前缀分区索引<br />
　　局部无前缀分区索引<br />
　　全局有前缀分区索引<br />
　　散列分区索引<br />
　　基于函数的索引<br />
　　<br />
　　<strong>管理索引的准则<br />
　　<br />
　　在表中插入数据后创建索引<br />
　　</strong><br />
　　。在用SQL*Loader或import工具插入或装载数据后，建立索引比较有效；<br />
　　<br />
　　<strong>索引正确的表和列</strong><br />
　　<br />
　　。经常检索排序大表中40%或非排序表7%的行，建议建索引；<br />
　　。为了改善多表关联，索引列用于联结；<br />
　　。列中的值相对比较唯一；<br />
　　。取值范围（大：B*树索引，小：位图索引）；<br />
　　。Date型列一般适合基于函数的索引；<br />
　　。列中有许多空值，不适合建立索引<br />
　　<br />
　　<strong>为性能而安排索引列</strong><br />
　　<br />
　　。经常一起使用多个字段检索记录，组合索引比单索引更有效；<br />
　　。把最常用的列放在最前面，例：dx_groupid_serv_id(groupid,serv_id)，在where条件中使用groupid或groupid,serv_id，查询将使用索引，若仅用到serv_id字段，则索引无效；<br />
　　。合并/拆分不必要的索引。<br />
　　<br />
　　<strong>限制每个表索引的数量</strong><br />
　　<br />
　　。一个表可以有几百个索引（你会这样做吗？），但是对于频繁插入和更新表，索引越多系统CPU，I/O负担就越重；<br />
　　。建议每张表不超过5个索引。<br />
　　<br />
　　<strong>删除不再需要的索引</strong><br />
　　<br />
　　。索引无效，集中表现在该使用基于函数的索引或位图索引，而使用了B*树索引；<br />
　　。应用中的查询不使用索引；<br />
　　。重建索引之前必须先删除索引，若用alter index &#8230; rebuild重建索引，则不必删除索引。<br />
　　<br />
　　<strong>索引数据块空间使用</strong><br />
　　<br />
　　。创建索引时指定表空间，特别是在建立主键时，应明确指定表空间；<br />
　　。合理设定pctfress，注意：不能给索引指定pctused；<br />
　　。估计索引的大小和合理地设置<a class="channel_keylink" href="http://www.storworld.com/" target="_blank">存储</a>参数，默认为表空间大小，或initial与next设置成一样大。<br />
　　<br />
　　<strong>考虑并行创建索引</strong><br />
　　<br />
　　。对大表可以采用并行创建索引，在并行创建索引时，存储参数被每个查询<a class="channel_keylink" href="http://server.chinaitlab.com/" target="_blank">服务器</a>进程分别使用，例如：initial为1M，并行度为8，则创建索引期间至少要消耗8M空间；<br />
　　<br />
　　<strong>考虑用nologging创建索引</strong><br />
　　<br />
　　。对大表创建索引可以使用nologging来减少重做日志；<br />
　　。节省重做日志文件的空间；<br />
　　。缩短创建索引的时间；<br />
　　。改善了并行创建大索引时的性能。<br />
　　<br />
　　<strong>怎样建立最佳索引</strong><br />
　　<br />
　　明确地创建索引<br />
　　create index index_name on table_name(field_name)<br />
　　tablespace tablespace_name<br />
　　pctfree 5<br />
　　initrans 2<br />
　　maxtrans 255<br />
　　storage<br />
　　(<br />
　　minextents 1<br />
　　maxextents 16382<br />
　　pctincrease 0<br />
　　);<br />
　　<br />
　　<strong>创建基于函数的索引</strong><br />
　　<br />
　　。常用与UPPER、LOWER、TO_CHAR(date)等函数分类上，例：<br />
　　create index idx_func on emp (UPPER(ename)) tablespace tablespace_name;<br />
　　<br />
　　<strong>创建位图索引</strong><br />
　　<br />
　　。对基数较小，且基数相对稳定的列建立索引时，首先应该考虑位图索引，例：<br />
　　create bitmap index idx_bitm on class (classno) tablespace tablespace_name;<br />
　　<br />
　　<strong>明确地创建唯一索引</strong><br />
　　<br />
　　。可以用create unique index语句来创建唯一索引，例：<br />
　　create unique index dept_unique_idx on dept(dept_no) tablespace idx_1;<br />
　　<br />
　　<strong>创建与约束相关的索引</strong><br />
　　<br />
　　。可以用using index字句，为与unique和primary key约束相关的索引，例如：<br />
　　alter table table_name<br />
　　add constraint PK_primary_keyname primary key (field_name)<br />
　　using index tablespace tablespace_name；<br />
　　<br />
　　<strong>如何创建局部分区索引</strong><br />
　　<br />
　　。基础表必须是分区表；<br />
　　。分区数量与基础表相同；<br />
　　。每个索引分区的子分区数量与相应的基础表分区相同；<br />
　　。基础表的子分区中的行的索引项，被存储在该索引的相应的子分区中,例如:<br />
　　Create Index TG_CDR04_SERV_ID_IDX On TG_CDR04(SERV_ID)<br />
　　Pctfree 5<br />
　　Tablespace TBS_AK01_IDX<br />
　　Storage (<br />
　　MaxExtents 32768<br />
　　PctIncrease 0<br />
　　FreeLists 1<br />
　　FreeList Groups 1<br />
　　)<br />
　　local<br />
　　/<br />
　　<br />
　　<strong>如何创建范围分区的全局索引</strong><br />
　　<br />
　　。基础表可以是全局表和分区表。<br />
　　create index idx_start_date on tg_cdr01(start_date)<br />
　　global partition by range(start_date)<br />
　　(partition p01_idx vlaues less than (&#8216;0106&#8217;)<br />
　　partition p01_idx vlaues less than (&#8216;0111&#8217;)<br />
　　&#8230;<br />
　　partition p01_idx vlaues less than (&#8216;0401&#8217; ))<br />
　　/<br />
　　<br />
　　<strong>重建现存的索引</strong><br />
　　<br />
　　重建现存的索引的当前时刻不会影响查询；<br />
　　<br />
　　重建索引可以删除额外的数据块；<br />
　　<br />
　　提高索引查询效率；<br />
　　alter index idx_name rebuild nologging;<br />
　　<br />
　　对于分区索引：<br />
　　alter index idx_name rebuild partition partiton_name nologging;<br />
　　<br />
　　<strong>要删除索引的原因</strong><br />
　　<br />
　　。不再需要的索引；<br />
　　。索引没有针对其相关的表所发布的查询提供所期望的性能改善；<br />
　　。应用没有用该索引来查询数据；<br />
　　。该索引无效，必须在重建之前删除该索引；<br />
　　。该索引已经变的太碎了，必须在重建之前删除该索引；<br />
　　。语句：drop index idx_name;drop index idx_name drop partition partition_name;<br />
　　<br />
　　<strong>建立索引的代价</strong><br />
　　<br />
　　基础表维护时，系统要同时维护索引，不合理的索引将严重影响系统资源，主要表现在CPU和I/O上；<br />
　　<br />
　　插入、更新、删除数据产生大量db file sequential read锁等待；<br />
　　<br />
　　<strong>SQL优化器简介<br />
　　<br />
　　基于规则的优化器</strong><br />
　　<br />
　　。总是使用索引<br />
　　。总是从驱动表开始（from子句最右边的表）<br />
　　。只有在不可避免的情况下，才使用全表扫描<br />
　　。任何索引都可以<br />
　　<br />
　　<strong>基于成本的优化器</strong><br />
　　<br />
　　。需要表、索引的统计资料<br />
　　Analyze table customer compute statistics;<br />
　　Analyze table customer estimate statistics sample 5000 rows;<br />
　　。表中设置并行度、表分区<br />
　　<br />
　　优化器模式<br />
　　<br />
　　rule模式<br />
　　<br />
　　。总忽略CBO和统计信息而基于规则<br />
　　choose模式<br />
　　<br />
　　。<a class="channel_keylink" href="http://oracle.chinaitlab.com/" target="_blank">Oracle</a>根据情况选择rule or first_rows or all_rows<br />
　　first_rows 模式<br />
　　<br />
　　。基于成本，以最快的速度返回记录，会造成总体查询速度的下降或消耗更多的资源，倾向索引扫描，适合OLTP系统<br />
　　all_rows模式<br />
　　<br />
　　。基于成本，确保总体查询时间最短，倾向并行全表扫描<br />
　　<br />
　　例如：<br />
　　Select last_name from customer order by last_name;用first_rows时，迅速返回记录，但I/O量大，用all_rows时，返回记录慢，但使用资源少。<br />
　　<br />
　　<strong>调整SQL表访问</strong><br />
　　<br />
　　全表扫描<br />
　　<br />
　　。返回记录：未排序表&gt;40%，排序表&gt;7%，建议采用并行机制来提高访问速度，DDS；<br />
　　<br />
　　索引访问<br />
　　<br />
　　。最常用的方法，包括索引唯一扫描和索引范围扫描，OLTP；<br />
　　<br />
　　快速完全索引扫描<br />
　　<br />
　　。访问索引中所有数据块，结果相当于全表扫描，可以用索引扫描代替全表扫描，例如：<br />
　　<br />
　　Select serv_id,count(* ) from tg_cdr01 group by serv_id;<br />
　　<br />
　　评估全表扫描的合法性<br />
　　<br />
　　如何实现并行扫描<br />
　　<br />
　　。永久并行化（不推荐）<br />
　　alter table customer parallel degree 8;<br />
　　<br />
　　。单个查询并行化<br />
　　select /*+ full(emp) parallel(emp,8)*/ * from emp;<br />
　　<br />
　　分区表效果明显<br />
　　<br />
　　优化SQL语句排序<br />
　　<br />
　　排序的操作：<br />
　　<br />
　　。order by 子句<br />
　　。group by 子句<br />
　　。select distinct子句<br />
　　。创建索引时<br />
　　。union或minus<br />
　　。排序合并连接<br />
　　<br />
　　如何避免排序<br />
　　<br />
　　。添加索引<br />
　　。在索引中使用distinct子句<br />
　　。避免排序合并连接<br />
　　<br />
　　<strong>使用提示进行调整</strong><br />
　　<br />
　　使用提示的原则<br />
　　<br />
　　。语法：/*+ hint */<br />
　　。使用表别名:select /*+ index(e dept_idx)*/ * from emp e<br />
　　。检验提示<br />
　　<br />
　　常用的提示<br />
　　<br />
　　。rule<br />
　　。all_rows<br />
　　。first_rows<br />
　　。use_nl<br />
　　。use_hash<br />
　　。use_merge<br />
　　。index<br />
　　。index_asc<br />
　　。no_index<br />
　　。index_desc（常用于使用max内置函数）<br />
　　。index_combine(强制使用位图索引)<br />
　　。index_ffs（索引快速完全扫描）<br />
　　。use_concat(将查询中所有or条件使用union all)<br />
　　。parallel<br />
　　。noparallel<br />
　　。full<br />
　　。ordered（基于成本）<br />
　　<br />
　　<strong>调整表连接</strong><br />
　　<br />
　　表连接的类型<br />
　　<br />
　　。等连接<br />
　　where 条件中用等式连接；<br />
　　。外部连接（左、右连接）<br />
　　<br />
　　在where条件子句的等式谓词放置一个(+)来实现，例如：<br />
　　select a.ename,b.comm from emp a,bonus b where a.ename=b.ename(+);<br />
　　<br />
　　该语句返回所有emp表的记录；<br />
　　。自连接<br />
　　　Select a.value total, B.value hard, (A.value - b.value) soft ,<br />
　　Round((b.value/a.value)*100,1) perc<br />
　　From v$sysstat a,v$sysstat b<br />
　　Where a.statistic# = 179<br />
　　and B.statistic# = 180;<br />
　　<br />
　　反连接<br />
　　<br />
　　反连接常用于not in or not exists中，是指在查询中找到的任何记录都不包含在结果集中的子查询；不建议使用not in or not exists;<br />
　　<br />
　　。半连接<br />
　　<br />
　　查询中使用exists，含义：即使在子查询中返回多条重复的记录，外部查询也只返回一条记录。<br />
　　<br />
　　嵌套循环连接<br />
　　<br />
　　。被连接表中存在索引的情况下使用；<br />
　　。使用use_nl。<br />
　　<br />
　　hash连接<br />
　　<br />
　　。Hash连接将驱动表加载在内存中，并使用hash技术连接第二个表，提高等连接速度。<br />
　　。适合于大表和小表连接；<br />
　　。使用use_hash。<br />
　　<br />
　　排序合并连接<br />
　　<br />
　　。排序合并连接不使用索引<br />
　　。使用原则：<br />
　　<br />
　　连接表子段中不存在可用索引；<br />
　　<br />
　　查询返回两个表中大部分的数据快；<br />
　　<br />
　　CBO认为全表扫描比索引扫描执行的更快。<br />
　　<br />
　　。使用use_merge<br />
　　<br />
　　<strong>使用临时/中间表</strong><br />
　　<br />
　　多个大表关联时，可以分别把满足条件的结果集存放到中间表，然后用中间表关联；<br />
　　<br />
　　<strong>SQL子查询的调整</strong><br />
　　<br />
　　关联与非关联子查询<br />
　　<br />
　　。关联：子查询的内部引用的是外部表，每行执行一次；<br />
　　。非关联：子查询只执行一次，存放在内存中。<br />
　　<br />
　　调整not in 和not exists语句<br />
　　<br />
　　。可以使用外部连接优化not in子句，例如：<br />
　　select ename from emp where dept_no not in<br />
　　(select dept_no from dept where dept_name =&#8216;Math&#8217;);<br />
　　<br />
　　改为：<br />
　　select ename from emp,dept<br />
　　where emp.dept_no=dept.dept_no<br />
　　and dept.dept_name is null;<br />
　　<br />
　　使用索引调整SQL<br />
　　<br />
　　Oracle 为什么不使用索引<br />
　　<br />
　　。检查被索引的列或组合索引的首列是否出现在PL/SQL语句的WHERE子句中，这是&#8220;执行计划&#8221;能用到相关索引的必要条件。<br />
　　<br />
　　。看采用了哪种类型的连接方式。ORACLE的共有Sort Merge Join（SMJ）、Hash Join（HJ）和Nested Loop Join（NL）。在两张表连接，且内表的目标列上建有索引时，只有Nested Loop才能有效地利用到该索引。SMJ即使相关列上建有索引，最多只能因索引的存在，避免数据排序过程。HJ由于须做HASH运算，索引的存在对数据查询速度几乎没有影响。<br />
　　<br />
　　。看连接顺序是否允许使用相关索引。假设表emp的deptno列上有索引，表dept的列deptno上无索引，WHERE语句有emp.deptno=dept.deptno条件。在做NL连接时，emp做为外表，先被访问，由于连接机制原因，外表的数据访问方式是全表扫描，emp.deptno上的索引显然是用不上，最多在其上做索引全扫描或索引快速全扫描。<br />
　　<br />
　　。是否用到系统数据字典表或视图。由于系统数据字典表都未被分析过，可能导致极差的&#8220;执行计划&#8221;。但是不要擅自对数据字典表做分析，否则可能导致死锁，或系统性能下降。<br />
　　<br />
　　。索引列是否函数的参数。如是，索引在查询时用不上。<br />
　　<br />
　　。是否存在潜在的数据类型转换。如将字符型数据与数值型数据比较，ORACLE会自动将字符型用to_number()函数进行转换，从而导致上一种现象的发生。<br />
　　<br />
　　。是否为表和相关的索引搜集足够的统计数据。对数据经常有增、删、改的表最好定期对表和索引进行分析，可用SQL语句&#8220;analyze table xxxx compute statistics for all indexes;&#8221;。ORACLE掌握了充分反映实际的统计数据，才有可能做出正确的选择。<br />
　　<br />
　　。索引列的选择性不高。 　　我们假设典型情况，有表emp，共有一百万行数据，但其中的emp.deptno列，数据只有4种不同的值，如10、20、30、40。虽然emp数据行有很多，ORACLE缺省认定表中列的值是在所有数据行均匀分布的，也就是说每种deptno值各有25万数据行与之对应。假设SQL搜索条件DEPTNO=10，利用deptno列上的索引进行数据搜索效率，往往不比全表扫描的高。<br />
　　<br />
　　。索引列值是否可为空（NULL）。如果索引列值可以是空值，在SQL语句中那些要返回NULL值的操作，将不会用到索引，如COUNT（*），而是用全表扫描。这是因为索引中存储值不能为全空。<br />
　　<br />
　　。看是否有用到并行查询（PQO）。并行查询将不会用到索引。<br />
　　<br />
　　。如果从以上几个方面都查不出原因的话，我们只好用采用在语句中加hint的方式强制ORACLE使用最优的&#8220;执行计划&#8221;。 　hint采用注释的方式，有行注释和段注释两种方式。 　如我们想要用到A表的IND_COL1索引的话，可采用以下方式： 　&#8220;SELECT /*+ INDEX（A IND_COL1）*/ * FROM A WHERE COL1 = XXX;"<br />
　　<br />
　　<strong>如何屏蔽索引</strong><br />
　　<br />
　　语句的执行计划中有不良索引时，可以人为地屏蔽该索引，方法：<br />
　　<br />
　　。数值型：在索引字段上加0，例如<br />
　　select * from emp where emp_no+0 = v_emp_no;<br />
　　<br />
　　。字符型：在索引字段上加&#8216;&#8217;，例如<br />
　　select * from tg_cdr01 where msisdn||&#8217;&#8217;=v_msisdn; 
<img src ="http://www.blogjava.net/caizh2009/aggbug/270620.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-05-14 15:46 <a href="http://www.blogjava.net/caizh2009/articles/270620.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>