﻿<?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-CONAN ZONE-文章分类-SQL</title><link>http://www.blogjava.net/conans/category/32376.html</link><description>你越挣扎我就越兴奋</description><language>zh-cn</language><lastBuildDate>Mon, 22 Nov 2010 01:03:02 GMT</lastBuildDate><pubDate>Mon, 22 Nov 2010 01:03:02 GMT</pubDate><ttl>60</ttl><item><title>Oracle 常用SQL技巧收藏</title><link>http://www.blogjava.net/conans/articles/338235.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Wed, 17 Nov 2010 03:12:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/338235.html</guid><description><![CDATA[<strong>转自：</strong>http://www.javaeye.com/topic/805815<br />
<strong><br />
1. SELECT子句中避免使用 &#8220;*&#8221;</strong>
<br />
&nbsp;&nbsp;&nbsp; 当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用 &#8216;*&#8217;
是一个方便的方法.不幸的是,这是一个非常低效的方法. 实际上,ORACLE在解析的过程中, 会将&#8220;*&#8221; 依次转换成所有的列名,
这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间.
<br />
<br />
<strong>2.使用DECODE函数来减少处理时间</strong>
<br />
&nbsp;&nbsp;&nbsp; 使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表. 例如:
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>SELECT&nbsp;COUNT(*)，SUM(SAL)&nbsp;FROM&nbsp;EMP&nbsp;WHERE&nbsp;DEPT_NO&nbsp;=&nbsp;0020&nbsp;AND&nbsp;&nbsp;ENAME&nbsp;LIKE&nbsp;&#8216;SMITH%&#8217;;&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;COUNT(*)，SUM(SAL)&nbsp;FROM&nbsp;EMP&nbsp;WHERE&nbsp;DEPT_NO&nbsp;=&nbsp;0030&nbsp;AND&nbsp;ENAME&nbsp;LIKE&nbsp;&#8216;SMITH%&#8217;;&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">SELECT COUNT(*)，SUM(SAL) FROM EMP WHERE DEPT_NO = 0020 AND  ENAME LIKE &#8216;SMITH%&#8217;;
SELECT COUNT(*)，SUM(SAL) FROM EMP WHERE DEPT_NO = 0030 AND ENAME LIKE &#8216;SMITH%&#8217;;
</pre>
&nbsp;&nbsp;&nbsp; 你可以用DECODE函数高效地得到相同结果:
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>SELECT&nbsp;COUNT(DECODE(DEPT_NO,0020,&#8217;X&#8217;,NULL))&nbsp;D0020_COUNT,&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;COUNT(DECODE(DEPT_NO,0030,&#8217;X&#8217;,NULL))&nbsp;D0030_COUNT,&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SUM(DECODE(DEPT_NO,0020,SAL,NULL))&nbsp;D0020_SAL,&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SUM(DECODE(DEPT_NO,0030,SAL,NULL))&nbsp;D0030_SAL&nbsp;&nbsp;</li>
    <li>FROM&nbsp;EMP&nbsp;WHERE&nbsp;ENAME&nbsp;LIKE&nbsp;&#8216;SMITH%&#8217;;&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">SELECT COUNT(DECODE(DEPT_NO,0020,&#8217;X&#8217;,NULL)) D0020_COUNT,
COUNT(DECODE(DEPT_NO,0030,&#8217;X&#8217;,NULL)) D0030_COUNT,
SUM(DECODE(DEPT_NO,0020,SAL,NULL)) D0020_SAL,
SUM(DECODE(DEPT_NO,0030,SAL,NULL)) D0030_SAL
FROM EMP WHERE ENAME LIKE &#8216;SMITH%&#8217;;
</pre>
&nbsp;&nbsp;&nbsp; 类似的,DECODE函数也可以运用于GROUP BY 和ORDER BY子句中.
<br />
<br />
<strong>3.删除重复记录</strong>
<br />
&nbsp;&nbsp; 最高效的删除重复记录方法 ( 因为使用了ROWID)
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>DELETE&nbsp;FROM&nbsp;EMP&nbsp;E&nbsp;WHERE&nbsp;E.ROWID&nbsp;&gt;&nbsp;(SELECT&nbsp;MIN(X.ROWID)&nbsp;FROM&nbsp;EMP&nbsp;X&nbsp;WHERE&nbsp;X.EMP_NO&nbsp;=&nbsp;E.EMP_NO);&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">DELETE FROM EMP E WHERE E.ROWID &gt; (SELECT MIN(X.ROWID) FROM EMP X WHERE X.EMP_NO = E.EMP_NO);
</pre>
<br />
<br />
<strong>4. 用TRUNCATE替代DELETE</strong>
<br />
&nbsp;&nbsp;&nbsp; 当删除表中的记录时，在通常情况下，回滚段(rollback segments )
用来存放可以被恢复的信息，如果你没有COMMIT事务，ORACLE会将数据恢复到删除之前的状态(准确地说是恢复到执行删除命令之前的状况)，而当运
用TRUNCATE时, 回滚段不再存放任何可被恢复的信息.当命令运行后,数据不能被恢复.因此很少的资源被调用,执行时间也会很短.
<br />
<br />
<strong>5.计算记录条数</strong>
<br />
&nbsp;&nbsp;&nbsp; 和一般的观点相反, count(*) 比count(1)稍快 ，当然如果可以通过索引检索，对索引列的计数仍旧是最快的. 例如 COUNT(EMPNO)
<br />
<br />
<strong>6.用Where子句替换HAVING子句</strong>
<br />
&nbsp;&nbsp;&nbsp; 避免使用HAVING子句，HAVING 只会在检索出所有记录之后才对结果集进行过滤，这个处理需要排序、总计等操作，如果能通过WHERE子句限制记录的数目，那就能减少这方面的开销, 例如:
<br />
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>--低效&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;REGION，AVG(LOG_SIZE)&nbsp;FROM&nbsp;LOCATION&nbsp;GROUP&nbsp;BY&nbsp;REGION&nbsp;HAVING&nbsp;REGION&nbsp;REGION&nbsp;!=&nbsp;&#8216;SYDNEY&#8217;&nbsp;AND&nbsp;REGION&nbsp;!=&nbsp;&#8216;PERTH&#8217;&nbsp;&nbsp;</li>
    <li>--高效&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;REGION，AVG(LOG_SIZE)&nbsp;&nbsp;FROM&nbsp;&nbsp;LOCATION&nbsp;WHERE&nbsp;REGION&nbsp;REGION&nbsp;!=&nbsp;&#8216;SYDNEY&#8217;&nbsp;ND&nbsp;REGION&nbsp;!=&nbsp;&#8216;PERTH&#8217;&nbsp;GROUP&nbsp;BY&nbsp;REGION&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">--低效
SELECT REGION，AVG(LOG_SIZE) FROM LOCATION GROUP BY REGION HAVING REGION REGION != &#8216;SYDNEY&#8217; AND REGION != &#8216;PERTH&#8217;
--高效
SELECT REGION，AVG(LOG_SIZE)  FROM  LOCATION WHERE REGION REGION != &#8216;SYDNEY&#8217; ND REGION != &#8216;PERTH&#8217; GROUP BY REGION
</pre>
<br />
<br />
<strong>7. 用EXISTS替代IN</strong>
<br />
&nbsp;&nbsp; 在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下, 使用EXISTS(或NOT EXISTS)通常将提高查询的效率.
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>--低效&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;*&nbsp;FROM&nbsp;EMP&nbsp;WHERE&nbsp;EMPNO&nbsp;&gt;&nbsp;0&nbsp;AND&nbsp;DEPTNO&nbsp;IN&nbsp;(SELECT&nbsp;DEPTNO&nbsp;FROM&nbsp;DEPT&nbsp;WHERE&nbsp;LOC&nbsp;=&nbsp;&#8216;MELB&#8217;)&nbsp;&nbsp;</li>
    <li>--高效:&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;*&nbsp;FROM&nbsp;EMP&nbsp;WHERE&nbsp;EMPNO&nbsp;&gt;&nbsp;0&nbsp;AND&nbsp;EXISTS&nbsp;(SELECT&nbsp;&#8216;X&#8217;&nbsp;&nbsp;FROM&nbsp;DEPT&nbsp;WHERE&nbsp;DEPT.DEPTNO&nbsp;=&nbsp;EMP.DEPTNO&nbsp;AND&nbsp;LOC&nbsp;=&nbsp;&#8216;MELB&#8217;)&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">--低效
SELECT * FROM EMP WHERE EMPNO &gt; 0 AND DEPTNO IN (SELECT DEPTNO FROM DEPT WHERE LOC = &#8216;MELB&#8217;)
--高效:
SELECT * FROM EMP WHERE EMPNO &gt; 0 AND EXISTS (SELECT &#8216;X&#8217;  FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = &#8216;MELB&#8217;)
</pre>
<br />
<br />
<strong>8.用NOT EXISTS替代NOT IN</strong>
<br />
&nbsp;&nbsp; 在子查询中，NOT IN子句将执行一个内部的排序和合并. 无论在哪种情况下，NOT IN都是最低效的
(因为它对子查询中的表执行了一个全表遍历).&nbsp; 为了避免使用NOT IN，我们可以把它改写成外连接(Outer Joins)或NOT
EXISTS. 例如:
<br />
SELECT &#8230;FROM EMP&nbsp; WHERE DEPT_NO NOT IN (SELECT DEPT_NO FROM DEPT WHERE DEPT_CAT=&#8217;A&#8217;);
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>--为了提高效率改写为:&nbsp;(方法一:&nbsp;高效)&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;&#8230;.FROM&nbsp;EMP&nbsp;A,DEPT&nbsp;B&nbsp;WHERE&nbsp;A.DEPT_NO&nbsp;=&nbsp;B.DEPT(+)&nbsp;AND&nbsp;B.DEPT_NO&nbsp;IS&nbsp;NULL&nbsp;AND&nbsp;B.DEPT_CAT(+)&nbsp;=&nbsp;&#8216;A&#8217;&nbsp;&nbsp;</li>
    <li>--&nbsp;(方法二:&nbsp;最高效)&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;&#8230;.FROM&nbsp;EMP&nbsp;E&nbsp;WHERE&nbsp;NOT&nbsp;EXISTS&nbsp;(SELECT&nbsp;&#8216;X&#8217;&nbsp;&nbsp;FROM&nbsp;DEPT&nbsp;D&nbsp;WHERE&nbsp;D.DEPT_NO&nbsp;=&nbsp;E.DEPT_NO&nbsp;AND&nbsp;DEPT_CAT&nbsp;=&nbsp;&#8216;A&#8217;);&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">--为了提高效率改写为: (方法一: 高效)
SELECT &#8230;.FROM EMP A,DEPT B WHERE A.DEPT_NO = B.DEPT(+) AND B.DEPT_NO IS NULL AND B.DEPT_CAT(+) = &#8216;A&#8217;
-- (方法二: 最高效)
SELECT &#8230;.FROM EMP E WHERE NOT EXISTS (SELECT &#8216;X&#8217;  FROM DEPT D WHERE D.DEPT_NO = E.DEPT_NO AND DEPT_CAT = &#8216;A&#8217;);
</pre>
<br />
<br />
<strong>9.用EXISTS替换DISTINCT</strong>
<br />
&nbsp;&nbsp;&nbsp; 当提交一个包含一对多表信息(比如部门表和雇员表)的查询时,避免在SELECT子句中使用DISTINCT. 一般可以考虑用EXIST替换
<br />
例如:
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>--低效:&nbsp;&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;DISTINCT&nbsp;DEPT_NO,DEPT_NAME&nbsp;&nbsp;FROM&nbsp;DEPT&nbsp;D,EMP&nbsp;E&nbsp;WHERE&nbsp;D.DEPT_NO&nbsp;=&nbsp;E.DEPT_NO&nbsp;&nbsp;</li>
    <li>--高效:&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;DEPT_NO,DEPT_NAME&nbsp;&nbsp;FROM&nbsp;DEPT&nbsp;D&nbsp;WHERE&nbsp;EXISTS&nbsp;(&nbsp;SELECT&nbsp;&#8216;X&#8217;&nbsp;FROM&nbsp;EMP&nbsp;E&nbsp;WHERE&nbsp;E.DEPT_NO&nbsp;=&nbsp;D.DEPT_NO);&nbsp;&nbsp;</li>
    <li>--EXISTS&nbsp;使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果.&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">--低效:
SELECT DISTINCT DEPT_NO,DEPT_NAME  FROM DEPT D,EMP E WHERE D.DEPT_NO = E.DEPT_NO
--高效:
SELECT DEPT_NO,DEPT_NAME  FROM DEPT D WHERE EXISTS ( SELECT &#8216;X&#8217; FROM EMP E WHERE E.DEPT_NO = D.DEPT_NO);
--EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果.
</pre>
<br />
<br />
<strong>10. 用索引提高效率</strong>
<br />
&nbsp;&nbsp;
索引是表的一个概念部分，用来提高检索数据的效率，实际上ORACLE使用了一个复杂的自平衡B-tree结构，通常通过索引查询数据比全表扫描要快，当
ORACLE找出执行查询和Update语句的最佳路径时， ORACLE优化器将使用索引，
同样在联结多个表时使用索引也可以提高效率，另一个使用索引的好处是，它提供了主键(primary key)的唯一性验证，除了那些LONG或LONG
RAW数据类型, 你可以索引几乎所有的列. 通常, 在大型表中使用索引特别有效. 当然,你也会发现,
在扫描小表时,使用索引同样能提高效率，虽然使用索引能得到查询效率的提高,但是我们也必须注意到它的代价.
索引需要空间来存储，也需要定期维护，每当有记录在表中增减或索引列被修改时，索引本身也会被修改，这意味着每条记录的INSERT , DELETE ,
UPDATE将为此多付出4 , 5 次的磁盘I/O， 因为索引需要额外的存储空间和处理，那些不必要的索引反而会使查询反应时间变慢
<br />
<em>注：定期的重构索引是有必要的. </em>
<br />
<br />
<strong>11. 避免在索引列上使用计算</strong>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE子句中，如果索引列是函数的一部分，优化器将不使用索引而使用全表扫描. 举例：
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>--低效：&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;&#8230;FROM&nbsp;DEPT&nbsp;WHERE&nbsp;SAL&nbsp;*&nbsp;12&nbsp;&gt;&nbsp;25000;&nbsp;&nbsp;</li>
    <li>--高效:&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;&#8230;&nbsp;FROM&nbsp;DEPT&nbsp;WHERE&nbsp;SAL&nbsp;&nbsp;&gt;&nbsp;25000/12;&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">--低效：
SELECT &#8230;FROM DEPT WHERE SAL * 12 &gt; 25000;
--高效:
SELECT &#8230; FROM DEPT WHERE SAL  &gt; 25000/12;
</pre>
<br />
<br />
<strong>12. 用&gt;=替代&gt;</strong>
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>--如果DEPTNO上有一个索引&nbsp;&nbsp;</li>
    <li>--高效：&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;SELECT&nbsp;*&nbsp;&nbsp;FROM&nbsp;EMP&nbsp;&nbsp;WHERE&nbsp;DEPTNO&nbsp;&gt;=4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li>
    <li>--低效：&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;SELECT&nbsp;*&nbsp;&nbsp;FROM&nbsp;EMP&nbsp;&nbsp;&nbsp;WHERE&nbsp;DEPTNO&nbsp;&gt;3&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">--如果DEPTNO上有一个索引
--高效：
SELECT *  FROM EMP  WHERE DEPTNO &gt;=4
--低效：
SELECT *  FROM EMP   WHERE DEPTNO &gt;3
</pre>
&nbsp;&nbsp; 两者的区别在于, 前者DBMS将直接跳到第一个DEPT等于4的记录而后者将首先定位到DEPTNO=3的记录并且向前扫描到第一个DEPT大于3的记录.
<strong>1. SELECT子句中避免使用 &#8220;*&#8221;</strong>
<br />
&nbsp;&nbsp;&nbsp; 当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用 &#8216;*&#8217;
是一个方便的方法.不幸的是,这是一个非常低效的方法. 实际上,ORACLE在解析的过程中, 会将&#8220;*&#8221; 依次转换成所有的列名,
这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间.
<br />
<br />
<strong>2.使用DECODE函数来减少处理时间</strong>
<br />
&nbsp;&nbsp;&nbsp; 使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表. 例如:
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>SELECT&nbsp;COUNT(*)，SUM(SAL)&nbsp;FROM&nbsp;EMP&nbsp;WHERE&nbsp;DEPT_NO&nbsp;=&nbsp;0020&nbsp;AND&nbsp;&nbsp;ENAME&nbsp;LIKE&nbsp;&#8216;SMITH%&#8217;;&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;COUNT(*)，SUM(SAL)&nbsp;FROM&nbsp;EMP&nbsp;WHERE&nbsp;DEPT_NO&nbsp;=&nbsp;0030&nbsp;AND&nbsp;ENAME&nbsp;LIKE&nbsp;&#8216;SMITH%&#8217;;&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">SELECT COUNT(*)，SUM(SAL) FROM EMP WHERE DEPT_NO = 0020 AND  ENAME LIKE &#8216;SMITH%&#8217;;
SELECT COUNT(*)，SUM(SAL) FROM EMP WHERE DEPT_NO = 0030 AND ENAME LIKE &#8216;SMITH%&#8217;;
</pre>
&nbsp;&nbsp;&nbsp; 你可以用DECODE函数高效地得到相同结果:
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>SELECT&nbsp;COUNT(DECODE(DEPT_NO,0020,&#8217;X&#8217;,NULL))&nbsp;D0020_COUNT,&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;COUNT(DECODE(DEPT_NO,0030,&#8217;X&#8217;,NULL))&nbsp;D0030_COUNT,&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SUM(DECODE(DEPT_NO,0020,SAL,NULL))&nbsp;D0020_SAL,&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SUM(DECODE(DEPT_NO,0030,SAL,NULL))&nbsp;D0030_SAL&nbsp;&nbsp;</li>
    <li>FROM&nbsp;EMP&nbsp;WHERE&nbsp;ENAME&nbsp;LIKE&nbsp;&#8216;SMITH%&#8217;;&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">SELECT COUNT(DECODE(DEPT_NO,0020,&#8217;X&#8217;,NULL)) D0020_COUNT,
COUNT(DECODE(DEPT_NO,0030,&#8217;X&#8217;,NULL)) D0030_COUNT,
SUM(DECODE(DEPT_NO,0020,SAL,NULL)) D0020_SAL,
SUM(DECODE(DEPT_NO,0030,SAL,NULL)) D0030_SAL
FROM EMP WHERE ENAME LIKE &#8216;SMITH%&#8217;;
</pre>
&nbsp;&nbsp;&nbsp; 类似的,DECODE函数也可以运用于GROUP BY 和ORDER BY子句中.
<br />
<br />
<strong>3.删除重复记录</strong>
<br />
&nbsp;&nbsp; 最高效的删除重复记录方法 ( 因为使用了ROWID)
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>DELETE&nbsp;FROM&nbsp;EMP&nbsp;E&nbsp;WHERE&nbsp;E.ROWID&nbsp;&gt;&nbsp;(SELECT&nbsp;MIN(X.ROWID)&nbsp;FROM&nbsp;EMP&nbsp;X&nbsp;WHERE&nbsp;X.EMP_NO&nbsp;=&nbsp;E.EMP_NO);&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">DELETE FROM EMP E WHERE E.ROWID &gt; (SELECT MIN(X.ROWID) FROM EMP X WHERE X.EMP_NO = E.EMP_NO);
</pre>
<br />
<br />
<strong>4. 用TRUNCATE替代DELETE</strong>
<br />
&nbsp;&nbsp;&nbsp; 当删除表中的记录时，在通常情况下，回滚段(rollback segments )
用来存放可以被恢复的信息，如果你没有COMMIT事务，ORACLE会将数据恢复到删除之前的状态(准确地说是恢复到执行删除命令之前的状况)，而当运
用TRUNCATE时, 回滚段不再存放任何可被恢复的信息.当命令运行后,数据不能被恢复.因此很少的资源被调用,执行时间也会很短.
<br />
<br />
<strong>5.计算记录条数</strong>
<br />
&nbsp;&nbsp;&nbsp; 和一般的观点相反, count(*) 比count(1)稍快 ，当然如果可以通过索引检索，对索引列的计数仍旧是最快的. 例如 COUNT(EMPNO)
<br />
<br />
<strong>6.用Where子句替换HAVING子句</strong>
<br />
&nbsp;&nbsp;&nbsp; 避免使用HAVING子句，HAVING 只会在检索出所有记录之后才对结果集进行过滤，这个处理需要排序、总计等操作，如果能通过WHERE子句限制记录的数目，那就能减少这方面的开销, 例如:
<br />
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>--低效&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;REGION，AVG(LOG_SIZE)&nbsp;FROM&nbsp;LOCATION&nbsp;GROUP&nbsp;BY&nbsp;REGION&nbsp;HAVING&nbsp;REGION&nbsp;REGION&nbsp;!=&nbsp;&#8216;SYDNEY&#8217;&nbsp;AND&nbsp;REGION&nbsp;!=&nbsp;&#8216;PERTH&#8217;&nbsp;&nbsp;</li>
    <li>--高效&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;REGION，AVG(LOG_SIZE)&nbsp;&nbsp;FROM&nbsp;&nbsp;LOCATION&nbsp;WHERE&nbsp;REGION&nbsp;REGION&nbsp;!=&nbsp;&#8216;SYDNEY&#8217;&nbsp;ND&nbsp;REGION&nbsp;!=&nbsp;&#8216;PERTH&#8217;&nbsp;GROUP&nbsp;BY&nbsp;REGION&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">--低效
SELECT REGION，AVG(LOG_SIZE) FROM LOCATION GROUP BY REGION HAVING REGION REGION != &#8216;SYDNEY&#8217; AND REGION != &#8216;PERTH&#8217;
--高效
SELECT REGION，AVG(LOG_SIZE)  FROM  LOCATION WHERE REGION REGION != &#8216;SYDNEY&#8217; ND REGION != &#8216;PERTH&#8217; GROUP BY REGION
</pre>
<br />
<br />
<strong>7. 用EXISTS替代IN</strong>
<br />
&nbsp;&nbsp; 在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下, 使用EXISTS(或NOT EXISTS)通常将提高查询的效率.
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>--低效&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;*&nbsp;FROM&nbsp;EMP&nbsp;WHERE&nbsp;EMPNO&nbsp;&gt;&nbsp;0&nbsp;AND&nbsp;DEPTNO&nbsp;IN&nbsp;(SELECT&nbsp;DEPTNO&nbsp;FROM&nbsp;DEPT&nbsp;WHERE&nbsp;LOC&nbsp;=&nbsp;&#8216;MELB&#8217;)&nbsp;&nbsp;</li>
    <li>--高效:&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;*&nbsp;FROM&nbsp;EMP&nbsp;WHERE&nbsp;EMPNO&nbsp;&gt;&nbsp;0&nbsp;AND&nbsp;EXISTS&nbsp;(SELECT&nbsp;&#8216;X&#8217;&nbsp;&nbsp;FROM&nbsp;DEPT&nbsp;WHERE&nbsp;DEPT.DEPTNO&nbsp;=&nbsp;EMP.DEPTNO&nbsp;AND&nbsp;LOC&nbsp;=&nbsp;&#8216;MELB&#8217;)&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">--低效
SELECT * FROM EMP WHERE EMPNO &gt; 0 AND DEPTNO IN (SELECT DEPTNO FROM DEPT WHERE LOC = &#8216;MELB&#8217;)
--高效:
SELECT * FROM EMP WHERE EMPNO &gt; 0 AND EXISTS (SELECT &#8216;X&#8217;  FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = &#8216;MELB&#8217;)
</pre>
<br />
<br />
<strong>8.用NOT EXISTS替代NOT IN</strong>
<br />
&nbsp;&nbsp; 在子查询中，NOT IN子句将执行一个内部的排序和合并. 无论在哪种情况下，NOT IN都是最低效的
(因为它对子查询中的表执行了一个全表遍历).&nbsp; 为了避免使用NOT IN，我们可以把它改写成外连接(Outer Joins)或NOT
EXISTS. 例如:
<br />
SELECT &#8230;FROM EMP&nbsp; WHERE DEPT_NO NOT IN (SELECT DEPT_NO FROM DEPT WHERE DEPT_CAT=&#8217;A&#8217;);
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>--为了提高效率改写为:&nbsp;(方法一:&nbsp;高效)&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;&#8230;.FROM&nbsp;EMP&nbsp;A,DEPT&nbsp;B&nbsp;WHERE&nbsp;A.DEPT_NO&nbsp;=&nbsp;B.DEPT(+)&nbsp;AND&nbsp;B.DEPT_NO&nbsp;IS&nbsp;NULL&nbsp;AND&nbsp;B.DEPT_CAT(+)&nbsp;=&nbsp;&#8216;A&#8217;&nbsp;&nbsp;</li>
    <li>--&nbsp;(方法二:&nbsp;最高效)&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;&#8230;.FROM&nbsp;EMP&nbsp;E&nbsp;WHERE&nbsp;NOT&nbsp;EXISTS&nbsp;(SELECT&nbsp;&#8216;X&#8217;&nbsp;&nbsp;FROM&nbsp;DEPT&nbsp;D&nbsp;WHERE&nbsp;D.DEPT_NO&nbsp;=&nbsp;E.DEPT_NO&nbsp;AND&nbsp;DEPT_CAT&nbsp;=&nbsp;&#8216;A&#8217;);&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">--为了提高效率改写为: (方法一: 高效)
SELECT &#8230;.FROM EMP A,DEPT B WHERE A.DEPT_NO = B.DEPT(+) AND B.DEPT_NO IS NULL AND B.DEPT_CAT(+) = &#8216;A&#8217;
-- (方法二: 最高效)
SELECT &#8230;.FROM EMP E WHERE NOT EXISTS (SELECT &#8216;X&#8217;  FROM DEPT D WHERE D.DEPT_NO = E.DEPT_NO AND DEPT_CAT = &#8216;A&#8217;);
</pre>
<br />
<br />
<strong>9.用EXISTS替换DISTINCT</strong>
<br />
&nbsp;&nbsp;&nbsp; 当提交一个包含一对多表信息(比如部门表和雇员表)的查询时,避免在SELECT子句中使用DISTINCT. 一般可以考虑用EXIST替换
<br />
例如:
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>--低效:&nbsp;&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;DISTINCT&nbsp;DEPT_NO,DEPT_NAME&nbsp;&nbsp;FROM&nbsp;DEPT&nbsp;D,EMP&nbsp;E&nbsp;WHERE&nbsp;D.DEPT_NO&nbsp;=&nbsp;E.DEPT_NO&nbsp;&nbsp;</li>
    <li>--高效:&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;DEPT_NO,DEPT_NAME&nbsp;&nbsp;FROM&nbsp;DEPT&nbsp;D&nbsp;WHERE&nbsp;EXISTS&nbsp;(&nbsp;SELECT&nbsp;&#8216;X&#8217;&nbsp;FROM&nbsp;EMP&nbsp;E&nbsp;WHERE&nbsp;E.DEPT_NO&nbsp;=&nbsp;D.DEPT_NO);&nbsp;&nbsp;</li>
    <li>--EXISTS&nbsp;使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果.&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">--低效:
SELECT DISTINCT DEPT_NO,DEPT_NAME  FROM DEPT D,EMP E WHERE D.DEPT_NO = E.DEPT_NO
--高效:
SELECT DEPT_NO,DEPT_NAME  FROM DEPT D WHERE EXISTS ( SELECT &#8216;X&#8217; FROM EMP E WHERE E.DEPT_NO = D.DEPT_NO);
--EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果.
</pre>
<br />
<br />
<strong>10. 用索引提高效率</strong>
<br />
&nbsp;&nbsp;
索引是表的一个概念部分，用来提高检索数据的效率，实际上ORACLE使用了一个复杂的自平衡B-tree结构，通常通过索引查询数据比全表扫描要快，当
ORACLE找出执行查询和Update语句的最佳路径时， ORACLE优化器将使用索引，
同样在联结多个表时使用索引也可以提高效率，另一个使用索引的好处是，它提供了主键(primary key)的唯一性验证，除了那些LONG或LONG
RAW数据类型, 你可以索引几乎所有的列. 通常, 在大型表中使用索引特别有效. 当然,你也会发现,
在扫描小表时,使用索引同样能提高效率，虽然使用索引能得到查询效率的提高,但是我们也必须注意到它的代价.
索引需要空间来存储，也需要定期维护，每当有记录在表中增减或索引列被修改时，索引本身也会被修改，这意味着每条记录的INSERT , DELETE ,
UPDATE将为此多付出4 , 5 次的磁盘I/O， 因为索引需要额外的存储空间和处理，那些不必要的索引反而会使查询反应时间变慢
<br />
<em>注：定期的重构索引是有必要的. </em>
<br />
<br />
<strong>11. 避免在索引列上使用计算</strong>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE子句中，如果索引列是函数的一部分，优化器将不使用索引而使用全表扫描. 举例：
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>--低效：&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;&#8230;FROM&nbsp;DEPT&nbsp;WHERE&nbsp;SAL&nbsp;*&nbsp;12&nbsp;&gt;&nbsp;25000;&nbsp;&nbsp;</li>
    <li>--高效:&nbsp;&nbsp;</li>
    <li>SELECT&nbsp;&#8230;&nbsp;FROM&nbsp;DEPT&nbsp;WHERE&nbsp;SAL&nbsp;&nbsp;&gt;&nbsp;25000/12;&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">--低效：
SELECT &#8230;FROM DEPT WHERE SAL * 12 &gt; 25000;
--高效:
SELECT &#8230; FROM DEPT WHERE SAL  &gt; 25000/12;
</pre>
<br />
<br />
<strong>12. 用&gt;=替代&gt;</strong>
<br />
<div>
<div>
<div>Sql代码 </div>
</div>
<ol start="1">
    <li>--如果DEPTNO上有一个索引&nbsp;&nbsp;</li>
    <li>--高效：&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;SELECT&nbsp;*&nbsp;&nbsp;FROM&nbsp;EMP&nbsp;&nbsp;WHERE&nbsp;DEPTNO&nbsp;&gt;=4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li>
    <li>--低效：&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;SELECT&nbsp;*&nbsp;&nbsp;FROM&nbsp;EMP&nbsp;&nbsp;&nbsp;WHERE&nbsp;DEPTNO&nbsp;&gt;3&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">--如果DEPTNO上有一个索引
--高效：
SELECT *  FROM EMP  WHERE DEPTNO &gt;=4
--低效：
SELECT *  FROM EMP   WHERE DEPTNO &gt;3
</pre>
&nbsp;&nbsp; 两者的区别在于, 前者DBMS将直接跳到第一个DEPT等于4的记录而后者将首先定位到DEPTNO=3的记录并且向前扫描到第一个DEPT大于3的记录.
<img src ="http://www.blogjava.net/conans/aggbug/338235.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2010-11-17 11:12 <a href="http://www.blogjava.net/conans/articles/338235.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle的decode、sign、 trunc函数</title><link>http://www.blogjava.net/conans/articles/319966.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Mon, 03 May 2010 12:16:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/319966.html</guid><description><![CDATA[<span style="font-family: comic sans ms,sans-serif;">
<p><span style="font-size: small;"><strong>一、<span class="hilite2">decode</span></strong></span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;">在<span class="hilite1">Oracle</span>/PLSQL
中,&nbsp; <strong><span class="hilite2">decode</span></strong> 具有和
IF-THEN-ELSE 一样的功能。</span></p>
<p><span><span style="font-size: small;"><strong><span class="hilite2">decode</span></strong>
函数语法如下：</span></span></p>
<blockquote class="definition">
<p><span style="font-size: small;"><span class="hilite2">decode</span>(
expression , search , result [, search , result]... [, default] )</span></p>
</blockquote>
<p><span><span style="font-size: small;"><em>expression</em> 要比较的表达式.</span></span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span><span style="font-size: small;"><em>search</em> 要与<em>expression</em>
<em>比较的字段。</em>.</span></span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span><span style="font-size: small;"><em>result</em> 如果<em>expression</em>
与<em>search</em> 一样的话，返回该结果。.</span></span></p>
<p><span><span style="font-size: small;"><em>default</em> 此参数可选，如果没有与<em>expression</em>
匹配上的<em>search</em> .
就返回此结果，如果此参数没有设置，当没有与expression匹配上的search时，返回null。</span></span></p>
<p><span style="font-size: small;"><span>search&nbsp;和
result可成对出现多次，代表各种要匹配的情况。&nbsp;<br />
</span>&nbsp;</span></p>
<p class="example_heading"><span style="font-size: small;">应用于</span></p>
<ul>
    <li><span style="font-size: small;"><span class="hilite1">Oracle</span>
    9i, <span class="hilite1">Oracle</span> 10g, <span class="hilite1">Oracle</span>
    11g </span></li>
</ul>
<p><span style="font-size: small;">例如：</span></p>
<p><span style="font-size: small;">You could use the <span class="hilite2">decode</span> function in an SQL statement as follows:</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small; color: #ff00ff;">select
supplier_name,<span class="hilite2">decode</span>(supplier_id,1000,'IBM',10001,'Microsoft','1002','Hewlett
Packard','Gateway') result from suppliers;</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;">上面的sql语句相当于下面的IF-THEN-ELSE :</span></p>
<blockquote class="sql_command">
<p><span style="font-size: small;">IF supplier_id = 10000 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;
result := 'IBM';</span></p>
<p><span style="font-size: small;">ELSIF supplier_id = 10001 THEN<br />
&nbsp;&nbsp;&nbsp;
result := 'Microsoft';</span></p>
<p><span style="font-size: small;">ELSIF supplier_id = 10002 THEN<br />
&nbsp;&nbsp;&nbsp;
result := 'Hewlett Packard';</span></p>
<p><span style="font-size: small;">ELSE<br />
&nbsp;&nbsp;&nbsp; result := 'Gateway';</span></p>
<p><span style="font-size: small;">END IF;</span></p>
</blockquote>
<p><span><br />
</span><span style="font-size: small;">&nbsp;<span><span class="hilite2">decode</span> 函数会挨个匹配supplier_id 的值.</span></span></p>
<p><span><br />
</span><span style="font-size: small;">&nbsp;</span></p>
<h2><span style="font-size: small;">常见问题：</span></h2>
<p><span style="font-size: small;">
<hr />
</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span><span style="font-size: small;"><strong>问题1</strong>:&nbsp;
现在一个阅读者想问，怎么使用<span class="hilite2">decode</span>函数来比较两个日期呢？（例如：date1 和
date2）, 如果date1 &gt; date2, <span class="hilite2">decode</span>
函数返回date2.&nbsp;否则<span class="hilite2">decode</span>函数返回 date1.</span></span></p>
<p><span><span style="font-size: small;"><strong>回答</strong>:&nbsp;
要实现上述要求，可使用<span class="hilite2">decode</span>函数如下：</span></span></p>
<blockquote class="sql_command">
<p><span style="font-size: small;"><span class="hilite2">decode</span>((date1
- date2) - abs(date1 - date2), 0, date2, date1)</span></p>
</blockquote>
<p><span style="font-size: small;">如果date1大于date2，下面表达是会等于0：</span></p>
<blockquote>
<p><span style="font-size: small;">(date1 - date2) - abs(date1 - date2)</span></p>
</blockquote>
<p><span><span style="font-size: small;"><strong>帮助性提示</strong>: 可用<span class="hilite2">decode</span>函数绑定</span></span><a href="http://knowyouknowme.javaeye.com/admin/blogs/sign.php"><span style="font-size: small;">SIGN&nbsp;函数</span></a><span style="font-size: small;">&nbsp;像下面这样:</span></p>
<p><span style="font-size: small;">上面比较日期的语句可修改如下:</span></p>
<blockquote class="sql_command">
<p><span style="font-size: small; color: #ff00ff;"><span class="hilite2">DECODE</span>(SIGN(date1-date2), 1, date2, date1)</span></p>
</blockquote>
<p><span style="font-size: small;">SIGN/<span class="hilite2">DECODE</span>
联合对于有关销售红利等数字方面的比较是非常有用的。</span></p>
<blockquote class="sql_command">
<p><span style="font-size: small;"><span class="hilite2">DECODE</span>(SIGN(actual-target),
-1, 'NO Bonus for you', 0,'Just made it', 1, 'Congrats, you are a
winner')</span></p>
</blockquote>
<p><span style="font-size: small;">
<hr />
</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span><span style="font-size: small;"><strong>问题2</strong>:&nbsp;
我想知道是否可以用<span class="hilite2">decode</span>函数来确定数字范围，例如 1-10 =
'category 1', 11-20 = 'category 2', 比一个一个比较应该会好一点吧.</span></span></p>
<p><span><span style="font-size: small;"><strong>回答</strong>:
不幸的告诉你，不可以用<span class="hilite2">decode</span>函数来确定数字的范围.
可是你可以试着创建一个表达式，这个表达式可以得一个数字指定的范围, 下一个数字对应下一个指定的范围, 以此类推.</span></span></p>
<p><span style="font-size: small;"><strong>例如：</strong></span></p>
<p><span style="font-size: small; color: #ff00ff;">select
supplier_id,<span class="hilite2">decode</span>(trunc((supplier_id-1)/10),0,'category
1',1,'category 2',2,'category 3','unknown') result from suppliers;</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;"><span>这个例子基于这个公式：</span><span>trunc
((supplier_id - 1) / 10</span></span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;">如果supplier_id在1和10之间，表达式计算值=0.</span></p>
<p><span style="font-size: small;">如果supplier_id在11和20之间，表达式计算值=1.</span></p>
<p><span>
<p><span style="font-size: small;">如果supplier_id在21和30之间，表达式计算值=3.</span></p>
</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;">等等；
<hr />
</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span><span style="font-size: small;"><strong>问题3</strong>:&nbsp; 我想写一个<span class="hilite2">decode</span>函数，要求如下:</span></span></p>
<blockquote>
<p><span style="font-size: small;">如果&nbsp;yrs_of_service &lt; 1 返回 0.04<br />
如
果&nbsp;yrs_of_service &gt;= 1 and &lt; 5 返回0.04<br />
如果&nbsp;yrs_of_service &gt; 5
返回 0.06</span></p>
</blockquote>
<p><span style="font-size: small;">这种情况我该怎么做呢?</span></p>
<p><span><span style="font-size: small;"><strong>回答</strong>:&nbsp; You will
need to create a formula that will evaluate to a single number for each
one of your ranges.</span></span></p>
<p><span style="font-size: small;">For example:</span></p>
<p><span style="font-size: small; color: #ff00ff;">select
emp_name,<span class="hilite2">decode</span>(trunc((yrs_of_service+3)/4),0,0.04,1,0.04,0.06)
as perc_value from employees;</span></p>
<p><span style="font-size: small;">
<hr />
</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span><span style="font-size: small;"><strong>问题4</strong>:&nbsp; <span class="hilite2">decode</span>函数的参数个数有限制吗？我得到一个错误 "ORA-00939: too many
arguments for function".</span></span></p>
<p><span><span style="font-size: small;"><strong>回答</strong>:&nbsp; 是的，<span class="hilite2">decode</span>函数的最大参数个数为255个,包括<em>expression</em>, <em>search</em>,
and <em>result</em> arguments.&lt;!-- InstanceEndEditable --&gt; </span></span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;">-------------------------------------------------------------------------------------------------------------</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;"><strong>二、sign</strong></span></p>
<p><span style="font-size: small;">在<span class="hilite1">Oracle</span>/PLSQL
中, <strong>sign</strong> 函数返回一个数字的正负标志.</span></p>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small;"><span>语法如下：</span><span>sign( number )</span></span></p>
<p><span><em></em></span><span style="font-size: small;">&nbsp;</span></p>
<p><span><span style="font-size: small;"><em>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; number</em>
要测试标志的数字.</span></span></p>
<blockquote>
<p><span style="font-size: small;">If <em>number</em> &lt; 0, then sign
returns -1.<br />
If <em>number</em> = 0, then sign returns 0.<br />
If <em>number</em>
&gt; 0, then sign returns 1.</span><span><br />
</span></p>
</blockquote>
<p class="example_heading"><span style="font-size: small;">应用于:</span></p>
<ul>
    <li>
    <span style="font-size: small;"><span class="hilite1">Oracle</span> 8i, <span class="hilite1">Oracle</span> 9i, <span class="hilite1">Oracle</span>
    10g, <span class="hilite1">Oracle</span> 11g </span><span><br />
    </span>
    </li>
</ul>
<p class="example_heading"><span style="font-size: small;">例如:</span></p>
<p class="example_heading"><span style="font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></p>
<blockquote>
<table border="0" cellpadding="3" cellspacing="0" width="257">
    <tbody>
        <tr>
            <td class="function_example" width="102"><span style="font-size: small;">sign(-23)</span></td>
            <td class="function_desc" width="151"><span style="font-size: small;">would
            return -1</span></td>
        </tr>
        <tr>
            <td class="function_example" width="102"><span style="font-size: small;">sign(0.001)</span></td>
            <td class="function_desc" width="151"><span style="font-size: small;">would
            return -1</span></td>
        </tr>
        <tr>
            <td class="function_example" width="102"><span style="font-size: small;">sign(0)</span></td>
            <td class="function_desc" width="151"><span style="font-size: small;">would
            return 0</span></td>
        </tr>
        <tr>
            <td class="function_example" width="102"><span style="font-size: small;">sign(0.001)</span></td>
            <td class="function_desc" width="151"><span style="font-size: small;">would
            return 1</span></td>
        </tr>
        <tr>
            <td class="function_example" width="102"><span style="font-size: small;">sign(23)</span></td>
            <td class="function_desc" width="151"><span style="font-size: small;">would
            return 1</span></td>
        </tr>
        <tr>
            <td class="function_example" width="102"><span style="font-size: small;">sig(23.601)</span></td>
            <td class="function_desc" width="151">
            <p><span style="font-size: small;">would return 1</span></p>
            <p><span style="font-size: small;">&nbsp;</span></p>
            </td>
        </tr>
    </tbody>
</table>
<span style="font-family: comic sans ms,sans-serif;"><strong></strong></span>
</blockquote>
</span>
<p><span style="font-size: small;">&nbsp;</span></p>
<p style="text-align: left;"><span style="font-size: small;">&nbsp;</span></p>
<p style="text-align: left;"><span style="font-size: small; font-family: comic sans ms,sans-serif;">----------------------------------------------------------------------------------------------------</span></p>
<p style="text-align: left;"><span style="font-size: small; font-family: comic sans ms,sans-serif;"><strong>三、trunc(number)</strong></span></p>
<p><span style="font-size: small; font-family: comic sans ms,sans-serif;">在<span class="hilite1">Oracle</span>/PLSQL中,&nbsp;<strong>trunc</strong>
function returns a number truncated to a certain number of decimal
places.</span></p>
<p><span style="font-family: comic sans ms,sans-serif;"><span style="font-size: small;"><strong>trunc</strong> function 语法如下:</span></span></p>
<blockquote class="definition">
<p><span style="font-size: small; font-family: comic sans ms,sans-serif;">trunc( number, [ decimal_places ] )</span></p>
</blockquote>
<p><span style="font-family: comic sans ms,sans-serif;"><span><span style="font-size: small;"><em>number</em> 要截取的数字.</span></span></span></p>
<p><span style="font-family: comic sans ms,sans-serif;"><span><span style="font-size: small;"><em>decimal_places</em> 要保留的小数位.
这个参数必须是个整数.&nbsp;如果此参数缺省，默认保留0位小数</span></span></span><span style="font-family: comic sans ms,sans-serif;"><br />
</span><span style="font-size: small;">&nbsp;</span></p>
<p class="example_heading"><span style="font-size: small; font-family: comic sans ms,sans-serif;">应用于:</span></p>
<ul>
    <li><span style="font-size: small; font-family: comic sans ms,sans-serif;"><span class="hilite1">Oracle</span> 8i, <span class="hilite1">Oracle</span> 9i, <span class="hilite1">Oracle</span>
    10g, <span class="hilite1">Oracle</span> 11g </span></li>
</ul>
<p style="text-align: left;"><span style="font-family: comic sans ms,sans-serif;"><br />
</span><span style="font-size: small;">&nbsp;</span></p>
<p class="example_heading"><span style="font-size: small; font-family: comic sans ms,sans-serif;">例如For example:</span></p>
<blockquote>
<table border="0" cellpadding="3" cellspacing="0" width="323">
    <tbody>
        <tr>
            <td class="function_example" width="133"><span style="font-size: small; font-family: comic sans ms,sans-serif;">trunc(125.815)</span></td>
            <td class="function_desc"><span style="font-size: small; font-family: comic sans ms,sans-serif;">would return 125</span></td>
        </tr>
        <tr>
            <td class="function_example"><span style="font-size: small; font-family: comic sans ms,sans-serif;">trunc(125.815, 0)</span></td>
            <td class="function_desc"><span style="font-size: small; font-family: comic sans ms,sans-serif;">would return 125</span></td>
        </tr>
        <tr>
            <td class="function_example"><span style="font-size: small; font-family: comic sans ms,sans-serif;">trunc(125.815, 1)</span></td>
            <td class="function_desc"><span style="font-size: small; font-family: comic sans ms,sans-serif;">would return 125.8</span></td>
        </tr>
        <tr>
            <td class="function_example"><span style="font-size: small; font-family: comic sans ms,sans-serif;">trunc(125.815, 2)</span></td>
            <td class="function_desc"><span style="font-size: small; font-family: comic sans ms,sans-serif;">would return 125.81</span></td>
        </tr>
        <tr>
            <td class="function_example"><span style="font-size: small; color: #ff00ff; font-family: comic sans ms,sans-serif;">trunc(125.81,
            3)</span></td>
            <td class="function_desc"><span style="font-size: small; color: #ff00ff; font-family: comic sans ms,sans-serif;">would return 125.81</span></td>
        </tr>
        <tr>
            <td class="function_example"><span style="font-size: small; font-family: comic sans ms,sans-serif;">trunc(-125.815, 2)</span></td>
            <td class="function_desc"><span style="font-size: small; font-family: comic sans ms,sans-serif;">would return -125.81</span></td>
        </tr>
        <tr>
            <td class="function_example"><span style="font-size: small; font-family: comic sans ms,sans-serif;">trunc(125.815, -1)</span></td>
            <td class="function_desc"><span style="font-size: small; font-family: comic sans ms,sans-serif;">would return 120</span></td>
        </tr>
        <tr>
            <td class="function_example"><span style="font-size: small; font-family: comic sans ms,sans-serif;">trunc(125.815, -2)</span></td>
            <td class="function_desc"><span style="font-size: small; font-family: comic sans ms,sans-serif;">would return 100</span></td>
        </tr>
        <tr>
            <td class="function_example"><span style="font-size: small; color: #ff00ff; font-family: comic sans ms,sans-serif;">trunc(125.81,
            -3)</span></td>
            <td class="function_desc"><span style="font-size: small; color: #ff00ff; font-family: comic sans ms,sans-serif;">would return 0</span></td>
        </tr>
    </tbody>
</table>
<p><span style="font-size: small;">&nbsp;</span></p>
<p><span style="font-size: small; font-family: comic sans ms,sans-serif;">&nbsp;如果<em>decimal_places</em> 大于<em>number</em>
本身的小数位数，返回原数字不会加0.</span></p>
<p><span style="font-size: small; font-family: Comic Sans MS;">如：trunc(125.81,3)
would return 125.81;</span></p>
<p><span style="font-size: small; font-family: Comic Sans MS;">如果<em>decimal_places</em>
为负数，那么将指定的位数</span></p>
</blockquote>
<p><span style="font-size: small;">&nbsp;</span></p>
<img src ="http://www.blogjava.net/conans/aggbug/319966.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2010-05-03 20:16 <a href="http://www.blogjava.net/conans/articles/319966.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle rownum 专题</title><link>http://www.blogjava.net/conans/articles/319963.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Mon, 03 May 2010 11:46:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/319963.html</guid><description><![CDATA[<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: center;" align="center"><strong><span style="font-size: 14pt;" lang="EN-US"><span style="font-family: Times New Roman;">Rownum</span></span></strong><strong><span style="font-size: 14pt; font-family: 宋体;">专题</span></strong><strong></strong></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"><span style="font-size: small; font-family: Times New Roman;">&nbsp;</span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small;"><span style="font-family: 宋体;">对于</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">来说它是</span><span lang="EN-US"><span style="font-family: Times New Roman;">oracle</span></span><span style="font-family: 宋体;">系统顺序分配为从查询返回的行的编号，返回的第一行分配的是</span><span lang="EN-US"><span style="font-family: Times New Roman;">1</span></span><span style="font-family: 宋体;">，第二行是</span><span lang="EN-US"><span style="font-family: Times New Roman;">2</span></span><span style="font-family: 宋体;">，依此类推，这个伪字段可以用于限制查询返回的总行数，而且</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">不能以任何表的名称作为前缀。</span></span><span lang="EN-US"><br />
</span><span style="font-family: 宋体;"><span style="font-size: small;">举例说明：</span></span><span lang="EN-US"><br />
</span><span style="font-size: small;"><span style="font-family: 宋体;">例如表：</span><span lang="EN-US"><span style="font-family: Times New Roman;">student(</span></span><span style="font-family: 宋体;">学生</span><span lang="EN-US"><span style="font-family: Times New Roman;">)</span></span><span style="font-family: 宋体;">表，表结构为：</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">ID</span></span><span style="font-size: small;"><span style="font-family: 宋体;">　　　</span><span lang="EN-US"><span style="font-family: Times New Roman;"> char(6)</span></span><span style="font-family: 宋体;">　　　　　</span><span lang="EN-US"><span style="font-family: Times New Roman;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --</span></span><span style="font-family: 宋体;">学号</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">name</span></span><span style="font-size: small;"><span style="font-family: 宋体;">　　</span><span lang="EN-US"><span style="font-family: Times New Roman;">VARCHAR2(10)</span></span><span style="font-family: 宋体;">　　　</span><span lang="EN-US"><span style="font-family: Times New Roman;">--</span></span><span style="font-family: 宋体;">姓名</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;"> <br />
<br />
/*
Formatted on 2008/09/24 09:15 (Formatter Plus v4.8.7) */<br />
CREATE TABLE
student (ID CHAR(6), NAME VARCHAR2(100));<br />
<br />
INSERT INTO student<br />
&nbsp;&nbsp;&nbsp;&nbsp;
VALUES ('200001', '</span></span><span style="font-family: 宋体;">张一</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;">');<br />
INSERT INTO student<br />
&nbsp;&nbsp;&nbsp;&nbsp; VALUES ('200002', '</span></span><span style="font-family: 宋体;">王二</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;">');<br />
INSERT
INTO student<br />
&nbsp;&nbsp;&nbsp;&nbsp; VALUES ('200003', '</span></span><span style="font-family: 宋体;">李三</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;">');<br />
INSERT
INTO student<br />
&nbsp;&nbsp;&nbsp;&nbsp; VALUES ('200004', '</span></span><span style="font-family: 宋体;">赵四</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;">');<br />
COMMIT ;<br />
<br />
<br />
(1)
rownum </span></span><span style="font-family: 宋体;">对于等于某值的查询条件</span></span><span lang="EN-US"><br />
</span><span style="font-size: small;"><span style="font-family: 宋体;">如果希望找到学生表中第一条学生的信息，可以使用</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum=1</span></span><span style="font-family: 宋体;">作为条件。但是想找到学生表中第二条学生的信息，使用</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum=2</span></span><span style="font-family: 宋体;">结果查不到数据。因为</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">都是从</span><span lang="EN-US"><span style="font-family: Times New Roman;">1</span></span><span style="font-family: 宋体;">开始，但是</span><span lang="EN-US"><span style="font-family: Times New Roman;">1</span></span><span style="font-family: 宋体;">以上的自然数在</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">做等于判断是时认为都是</span><span lang="EN-US"><span style="font-family: Times New Roman;">false</span></span><span style="font-family: 宋体;">条件，所以无法查到</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum = n</span></span><span style="font-family: 宋体;">（</span><span lang="EN-US"><span style="font-family: Times New Roman;">n&gt;1</span></span><span style="font-family: 宋体;">的自然数）。</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">SQL&gt; select
rownum,id,name from student where rownum=1;</span></span><span style="font-family: 宋体;"><span style="font-size: small;">（可以用在限制返回记录条数的地
方，保证不出错，如：隐式游标）</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">SQL&gt; select
rownum,id,name from student where rownum=1;<br />
&nbsp;&nbsp;&nbsp; ROWNUM ID&nbsp;&nbsp;&nbsp;&nbsp; NAME<br />
----------
------ ---------------------------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1
200001 </span></span><span style="font-family: 宋体;"><span style="font-size: small;">张一</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">SQL&gt; select
rownum,id,name from student where rownum =2; <br />
&nbsp;&nbsp;&nbsp; ROWNUM ID&nbsp;&nbsp;&nbsp;&nbsp; NAME<br />
----------
------ ---------------------------------------------------<br />
<br />
</span></span><span style="font-size: small;"><span style="font-family: 宋体;">（</span><span lang="EN-US"><span style="font-family: Times New Roman;">2</span></span><span style="font-family: 宋体;">）</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">对于大于某值的查询条件</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">&nbsp;&nbsp; </span></span><span style="font-size: small;"><span style="font-family: 宋体;">如果想找到从第二行记录以后的
记录，当使用</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum&gt;2</span></span><span style="font-family: 宋体;">是查不出记录的，
原因是由于</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">是一个总是从</span><span lang="EN-US"><span style="font-family: Times New Roman;">1</span></span><span style="font-family: 宋体;">开始的伪列，</span><span lang="EN-US"><span style="font-family: Times New Roman;">Oracle </span></span><span style="font-family: 宋体;">认为</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum&gt; n(n&gt;1</span></span><span style="font-family: 宋体;">的自然数</span><span lang="EN-US"><span style="font-family: Times New Roman;">)</span></span><span style="font-family: 宋体;">这种条件依旧不成立，所以查不到记录</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">SQL&gt; select rownum,id,name from student where rownum &gt;2;<br />
ROWNUM
ID&nbsp;&nbsp;&nbsp;&nbsp; NAME<br />
---------- ------
---------------------------------------------------<br />
</span></span><span style="font-size: small;"><span style="font-family: 宋体;">那如何才能找到第二行以后的记
录呀。可以使用以下的子查询方法来解决。注意子查询中的</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">必须要有别名，否则还是不会查出记录来，这是因为</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">不是某个表的列，如果不起别名的话，无法知道</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">是子查询的列还是主查询的列。</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">SQL&gt;select *
from(select rownum no ,id,name from student) where no&gt;2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
NO ID&nbsp;&nbsp;&nbsp;&nbsp; NAME<br />
---------- ------
---------------------------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3 200003
</span></span><span style="font-family: 宋体;"><span style="font-size: small;">李三</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4 200004 </span></span><span style="font-family: 宋体;"><span style="font-size: small;">赵四</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">SQL&gt; select * from(select rownum,id,name from student)where
rownum&gt;2;<br />
&nbsp;&nbsp;&nbsp; ROWNUM ID&nbsp;&nbsp;&nbsp;&nbsp; NAME<br />
---------- ------
---------------------------------------------------<br />
<br />
</span></span><span style="font-size: small;"><span style="font-family: 宋体;">（</span><span lang="EN-US"><span style="font-family: Times New Roman;">3</span></span><span style="font-family: 宋体;">）</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">对于小于某值的查询条件</span></span><span lang="EN-US"><br />
</span><span style="font-size: small;"><span style="font-family: 宋体;">如果想找到第三条记录以前的记
录，当使用</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum&lt;3</span></span><span style="font-family: 宋体;">是能得到两条记录
的。显然</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">对于</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum&lt;n</span></span><span style="font-family: 宋体;">（</span><span lang="EN-US"><span style="font-family: Times New Roman;">(n&gt;1</span></span><span style="font-family: 宋体;">的自然数）的条件认为是成立的，所以可以找到记录。</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">SQL&gt; select rownum,id,name from student where rownum &lt;3;<br />
&nbsp;&nbsp;&nbsp;
ROWNUM ID&nbsp;&nbsp;&nbsp;&nbsp; NAME<br />
---------- ------
---------------------------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 200001 </span></span><span style="font-family: 宋体;"><span style="font-size: small;">张一</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 200002 </span></span><span style="font-family: 宋体;"><span style="font-size: small;">王二</span></span><span lang="EN-US"><br />
<br />
</span><span style="font-size: small;"><span style="font-family: 宋体;">综上几种情况，可能有时候需要
查询</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">在某区间的数据，那怎么办呀从上可以看出</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">对小于某值的查询条件是人为</span><span lang="EN-US"><span style="font-family: Times New Roman;">true</span></span><span style="font-family: 宋体;">的，</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">对于大于某值的查询条件直接认为是</span><span lang="EN-US"><span style="font-family: Times New Roman;">false</span></span><span style="font-family: 宋体;">的，但是可以间接的让它转为认为是</span><span lang="EN-US"><span style="font-family: Times New Roman;">true</span></span><span style="font-family: 宋体;">的。那就必须使用子查询。例如要查询</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">在第二行到第三行之间的数据，包括第二行和第三行数据，那么我们只能写以下语句，先让它返回小于等于
三的记录行，然后在主查询中判断新的</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">的别名
列大于等于二的记录行。但是这样的操作会在大数据集中影响速度。</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">SQL&gt; select *
from (select rownum no,id,name from student where rownum&lt;=3 ) where
no &gt;=2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NO ID&nbsp;&nbsp;&nbsp;&nbsp; NAME<br />
---------- ------
---------------------------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 200002
</span></span><span style="font-family: 宋体;"><span style="font-size: small;">王二</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3 200003 </span></span><span style="font-family: 宋体;"><span style="font-size: small;">李三</span></span><span lang="EN-US"><br />
<br />
</span><span style="font-size: small;"><span style="font-family: 宋体;">（</span><span lang="EN-US"><span style="font-family: Times New Roman;">4</span></span><span style="font-family: 宋体;">）</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">和排序</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">Oracle</span></span><span style="font-size: small;"><span style="font-family: 宋体;">中的</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">的是在取数据的时候产生的序号，所以想对指定排序的数据去指定的</span><span lang="EN-US"><span style="font-family: Times New Roman;">rowmun</span></span><span style="font-family: 宋体;">行数据就必须注意了。</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">SQL&gt; select
rownum ,id,name from student order by name;<br />
&nbsp;&nbsp;&nbsp; ROWNUM ID&nbsp;&nbsp;&nbsp;&nbsp; NAME<br />
----------
------ ---------------------------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3
200003 </span></span><span style="font-family: 宋体;"><span style="font-size: small;">李三</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2
200002 </span></span><span style="font-family: 宋体;"><span style="font-size: small;">王二</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1
200001 </span></span><span style="font-family: 宋体;"><span style="font-size: small;">张一</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4
200004 </span></span><span style="font-family: 宋体;"><span style="font-size: small;">赵四</span></span><span lang="EN-US"><br />
</span><span style="font-size: small;"><span style="font-family: 宋体;">可以看出，</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">并不是按照</span><span lang="EN-US"><span style="font-family: Times New Roman;">name</span></span><span style="font-family: 宋体;">列来生成的序号。系统是按照记录插入时的顺序给记录排的号，</span><span lang="EN-US"><span style="font-family: Times New Roman;">rowid</span></span><span style="font-family: 宋体;">也是顺序分配的。为了解决这个问题，必须使用子查询</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">SQL&gt; select rownum ,id,name from (select * from student order
by name);<br />
&nbsp;&nbsp;&nbsp; ROWNUM ID&nbsp;&nbsp;&nbsp;&nbsp; NAME<br />
---------- ------
---------------------------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 200003
</span></span><span style="font-family: 宋体;"><span style="font-size: small;">李三</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 200002 </span></span><span style="font-family: 宋体;"><span style="font-size: small;">王二</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3 200001 </span></span><span style="font-family: 宋体;"><span style="font-size: small;">张一</span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4
200004 </span></span><span style="font-family: 宋体;"><span style="font-size: small;">赵四</span></span><span lang="EN-US"><br />
</span><span style="font-size: small;"><span style="font-family: 宋体;">这样就成了按</span><span lang="EN-US"><span style="font-family: Times New Roman;">name</span></span><span style="font-family: 宋体;">排序，并且用</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">标出正确序号（有小到大）。</span></span><span lang="EN-US"><br />
<br />
</span><span style="font-size: small;"><span style="color: #ff6600; font-family: 宋体;">笔者在工作中有一上百万条记录的表，在</span><span style="color: #ff6600;" lang="EN-US"><span style="font-family: Times New Roman;">jsp</span></span><span style="color: #ff6600; font-family: 宋体;">页面中需对该表进行分页显示，</span><span style="color: #ff6600;"><span style="font-family: Times New Roman;"> </span></span><span style="color: #ff6600; font-family: 宋体;">便考虑用</span><span style="color: #ff6600;" lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="color: #ff6600; font-family: 宋体;">来作，下面是具体方法</span><span style="color: #ff6600;" lang="EN-US"><span style="font-family: Times New Roman;">(</span></span><span style="color: #ff6600; font-family: 宋体;">每页</span></span><span style="color: #ff6600;" lang="EN-US"><br />
</span><span style="font-size: small;"><span style="color: #ff6600; font-family: 宋体;">显示</span><span style="color: #ff6600;" lang="EN-US"><span style="font-family: Times New Roman;">20</span></span><span style="color: #ff6600; font-family: 宋体;">条</span><span style="color: #ff6600;" lang="EN-US"><span style="font-family: Times New Roman;">)</span></span><span style="color: #ff6600; font-family: 宋体;">：</span></span><span style="font-size: small;"><span style="color: #ff6600;" lang="EN-US"><span style="font-family: Times New Roman;"> <br />
&#8220;select *
from tabname where rownum&lt;20 order by name" </span></span><span style="color: #ff6600; font-family: 宋体;">但却发现</span><span style="color: #ff6600;" lang="EN-US"><span style="font-family: Times New Roman;">oracle</span></span><span style="color: #ff6600; font-family: 宋体;">却不能按自己的意愿来执行，而是先随便</span></span><span style="color: #ff6600;" lang="EN-US"><br />
</span><span style="font-size: small;"><span style="color: #ff6600; font-family: 宋体;">取</span><span style="color: #ff6600;" lang="EN-US"><span style="font-family: Times New Roman;">20</span></span><span style="color: #ff6600; font-family: 宋体;">条记录，然后再</span><span style="color: #ff6600;" lang="EN-US"><span style="font-family: Times New Roman;"> order by</span></span><span style="color: #ff6600; font-family: 宋体;">，后经咨询</span><span style="color: #ff6600;" lang="EN-US"><span style="font-family: Times New Roman;">oracle,</span></span><span style="color: #ff6600; font-family: 宋体;">说</span><span style="color: #ff6600;" lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="color: #ff6600; font-family: 宋体;">确实就这样，想用的话，只能用子查询</span><span style="color: #ff6600;"><span style="font-family: Times New Roman;"> </span></span><span style="color: #ff6600; font-family: 宋体;">来实现先排序，后</span></span><span style="color: #ff6600;" lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">rownum</span></span><span style="color: #ff6600; font-family: 宋体;"><span style="font-size: small;">，方法如下：</span></span><span style="font-size: small;"><span style="color: #ff6600;" lang="EN-US"><span style="font-family: Times New Roman;"> <br />
"select * from (select * from
tabname order by name) where rownum&lt;20",</span></span><span style="color: #ff6600; font-family: 宋体;">但这样一来，效率会较低很多。</span></span><span style="font-size: small;"><span style="color: #ff6600;" lang="EN-US"><span style="font-family: Times New Roman;"> <br />
</span></span><span style="color: #ff6600; font-family: 宋体;">后经笔者试验，只需在</span><span style="color: #ff6600;" lang="EN-US"><span style="font-family: Times New Roman;">order by </span></span><span style="color: #ff6600; font-family: 宋体;">的字段上加主键或索引即可让</span><span style="color: #ff6600;" lang="EN-US"><span style="font-family: Times New Roman;">oracle</span></span><span style="color: #ff6600; font-family: 宋体;">先按</span><span style="color: #ff6600;"><span style="font-family: Times New Roman;"> </span></span><span style="color: #ff6600; font-family: 宋体;">该字段排序，然后再</span><span style="color: #ff6600;" lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="color: #ff6600; font-family: 宋体;">；方法不变：</span></span><span style="color: #ff6600;" lang="EN-US"><span style="font-size: small; font-family: Times New Roman;"> <br />
&nbsp;&nbsp; &#8220;select * from tabname where rownum&lt;20 order by name"</span></span><span lang="EN-US"><br />
<br />
</span><span style="font-size: small;"><span style="color: blue; font-family: 宋体;">补充：我们正常分页是如下（</span><span style="color: blue;" lang="EN-US"><span style="font-family: Times New Roman;">order by </span></span><span style="color: blue; font-family: 宋体;">主键，在最里面的那一层。非主键字段同样要</span><span style="color: blue;"><span style="font-family: Times New Roman;"> </span></span><span style="color: blue; font-family: 宋体;">加索引）：</span></span><span style="color: blue;" lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">/* Formatted on 2008/09/24 12:14 (Formatter Plus v4.8.7) */<br />
SELECT
*<br />
FROM (SELECT tmp.*, ROWNUM rn<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM (SELECT&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
FROM student<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE 1 = 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ORDER
BY NAME DESC) tmp<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE 1 = 1 AND ROWNUM &lt;= 3)<br />
WHERE 1
= 1 AND rn &gt;= 2</span></span><span lang="EN-US"><br />
<br />
<br />
<span style="font-size: small; font-family: Times New Roman;">(5) </span></span><span style="font-size: small;"><span style="font-family: 宋体;">取得某列中第</span><span lang="EN-US"><span style="font-family: Times New Roman;">N</span></span><span style="font-family: 宋体;">大的行</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;"> <br />
<br />
select
column_name from <br />
(select table_name.*,dense_rank() over (order by
column desc) rank from table_name) <br />
where rank = &amp;N</span></span><span style="font-family: 宋体;">；</span></span><span lang="EN-US"><br />
<br />
<span style="font-family: Times New Roman;"><span style="font-size: small;"><span style="color: #3366ff;">/* Formatted on 2008/09/24 12:30
(Formatter Plus v4.8.7) */<br />
SELECT *<br />
FROM (SELECT student.*,
DENSE_RANK () OVER (ORDER BY ID DESC) RANK<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM student)<br />
WHERE
RANK = 2</span><br />
<br />
(6)</span></span></span><span style="font-size: small;"><span style="font-family: 宋体;">假如要返回前</span><span lang="EN-US"><span style="font-family: Times New Roman;">5</span></span><span style="font-family: 宋体;">条记录：</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;"> <br />
<br />
select
* from tablename where rownum&lt;6;(</span></span><span style="font-family: 宋体;">或是</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum &lt;= 5 </span></span><span style="font-family: 宋体;">或是</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;">rownum
!= 6) <br />
</span></span><span style="font-family: 宋体;">假如要返回第</span><span lang="EN-US"><span style="font-family: Times New Roman;">5-9</span></span><span style="font-family: 宋体;">条记录：</span></span><span lang="EN-US"><span style="font-size: small; font-family: Times New Roman;"> <br />
</span><span style="font-family: Times New Roman;"><span style="font-size: small;"><span style="color: blue;">/* Formatted on 2008/09/24 12:34 (Formatter Plus
v4.8.7) */<br />
SELECT&nbsp;&nbsp; *<br />
&nbsp;&nbsp;&nbsp; FROM student<br />
&nbsp;&nbsp; WHERE ROWNUM &lt; 4<br />
MINUS<br />
SELECT&nbsp;&nbsp;
*<br />
&nbsp;&nbsp;&nbsp; FROM student<br />
&nbsp;&nbsp; WHERE ROWNUM &lt; 2</span><br />
<br />
order by
name <br />
</span></span></span><span style="font-size: small;"><span style="font-family: 宋体;">选出结果后用</span><span lang="EN-US"><span style="font-family: Times New Roman;">name</span></span><span style="font-family: 宋体;">排序显示结果。</span><span lang="EN-US"><span style="font-family: Times New Roman;">(</span></span><span style="font-family: 宋体;">先选再排序</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;">)
<br />
<br />
</span></span><span style="font-family: 宋体;">注意：只能用以上符号</span><span lang="EN-US"><span style="font-family: Times New Roman;">(&lt;</span></span><span style="font-family: 宋体;">、</span><span lang="EN-US"><span style="font-family: Times New Roman;">&lt;=</span></span><span style="font-family: 宋体;">、</span><span lang="EN-US"><span style="font-family: Times New Roman;">!=)</span></span><span style="font-family: 宋体;">。</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;"> <br />
<br />
(7)select
* from tablename where rownum != 10;</span></span><span style="font-family: 宋体;">返回的是前９条记录。</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;">
<br />
</span></span><span style="font-family: 宋体;">不能用：</span><span lang="EN-US"><span style="font-family: Times New Roman;">&gt;,&gt;=,=,Between...and</span></span><span style="font-family: 宋体;">。由于</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum</span></span><span style="font-family: 宋体;">是一个总是从</span><span lang="EN-US"><span style="font-family: Times New Roman;">1</span></span><span style="font-family: 宋体;">开始的伪列，</span><span lang="EN-US"><span style="font-family: Times New Roman;">Oracle </span></span><span style="font-family: 宋体;">认为这种条件</span><span style="font-family: Times New Roman;"> </span><span style="font-family: 宋体;">不成立，查不到记录</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;">. <br />
<br />
</span></span><span style="font-family: 宋体;">另
外，这个方法更快：</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;"> <br />
<br />
select
* from ( <br />
select rownum r,a from yourtable <br />
where rownum &lt;= 20
<br />
order by name ) <br />
where r &gt; 10 <br />
</span></span><span style="font-family: 宋体;">这样取出第</span><span lang="EN-US"><span style="font-family: Times New Roman;">11-20</span></span><span style="font-family: 宋体;">条记录</span><span lang="EN-US"><span style="font-family: Times New Roman;">!(</span></span><span style="font-family: 宋体;">先选再排序再选</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;">)
<br />
<br />
</span></span><span style="font-family: 宋体;">要先排序再选则须用</span><span lang="EN-US"><span style="font-family: Times New Roman;">select</span></span><span style="font-family: 宋体;">嵌套：内层排序外层选。</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;"> <br />
<span style="color: blue;">rownum</span></span></span><span style="color: blue; font-family: 宋体;">是随着结果集生成的，一旦生成，就不会变化了；同时</span><span style="color: blue;" lang="EN-US"><span style="font-family: Times New Roman;">,</span></span><span style="color: blue; font-family: 宋体;">生成的结果
是依次递加的，没有</span><span style="color: blue;" lang="EN-US"><span style="font-family: Times New Roman;">1</span></span><span style="color: blue; font-family: 宋体;">就永远不会有</span><span style="color: blue;" lang="EN-US"><span style="font-family: Times New Roman;">2! </span></span></span><span lang="EN-US"><br />
<span style="font-size: small; font-family: Times New Roman;">rownum </span></span><span style="font-size: small;"><span style="font-family: 宋体;">是在</span><span style="font-family: Times New Roman;"> </span><span style="font-family: 宋体;">查询集合产生的过程中产生的伪列，并且如果</span><span lang="EN-US"><span style="font-family: Times New Roman;">where</span></span><span style="font-family: 宋体;">条件中存在</span><span lang="EN-US"><span style="font-family: Times New Roman;"> rownum </span></span><span style="font-family: 宋体;">条件的话，则</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;">:
<br />
<br />
1</span></span><span style="font-family: 宋体;">：</span><span style="font-family: Times New Roman;"> </span><span style="font-family: 宋体;">假如</span><span style="font-family: Times New Roman;"> </span><span style="font-family: 宋体;">判定条件是常量，则：</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;">
<br />
</span></span><span style="font-family: 宋体;">只能</span><span lang="EN-US"><span style="font-family: Times New Roman;"> rownum = 1,
&lt;= </span></span><span style="font-family: 宋体;">大于</span><span lang="EN-US"><span style="font-family: Times New Roman;">1 </span></span><span style="font-family: 宋体;">的自然数，</span><span lang="EN-US"><span style="font-family: Times New Roman;"> = </span></span><span style="font-family: 宋体;">大于</span><span lang="EN-US"><span style="font-family: Times New Roman;">1 </span></span><span style="font-family: 宋体;">的数是没有结果的，</span><span style="font-family: Times New Roman;"> </span><span style="font-family: 宋体;">大于一个数也是没有结果的</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;"> <br />
</span></span><span style="font-family: 宋体;">即</span><span style="font-family: Times New Roman;"> </span><span style="font-family: 宋体;">当出现一个</span><span lang="EN-US"><span style="font-family: Times New Roman;"> rownum </span></span><span style="font-family: 宋体;">不满足条件的时候则</span><span style="font-family: Times New Roman;"> </span><span style="font-family: 宋体;">查询结束</span><span style="font-family: Times New Roman;"> </span><span style="font-family: 宋体;">　　</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;">this
is stop key! <br />
<br />
2: </span></span><span style="font-family: 宋体;">当判
定值不是常量的时候</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;"> <br />
</span></span><span style="font-family: 宋体;">若条件是</span><span lang="EN-US"><span style="font-family: Times New Roman;"> = var , </span></span><span style="font-family: 宋体;">则只有当</span><span lang="EN-US"><span style="font-family: Times New Roman;"> var </span></span><span style="font-family: 宋体;">为</span><span lang="EN-US"><span style="font-family: Times New Roman;">1 </span></span><span style="font-family: 宋体;">的时候才满足条件，这个时候不存在</span><span lang="EN-US"><span style="font-family: Times New Roman;"> stop key ,</span></span><span style="font-family: 宋体;">必须进行</span><span lang="EN-US"><span style="font-family: Times New Roman;"> full scan ,</span></span><span style="font-family: 宋体;">对每个满足其他</span><span lang="EN-US"><span style="font-family: Times New Roman;">where</span></span><span style="font-family: 宋体;">条件的数据进行判定</span></span><span style="font-size: small;"><span lang="EN-US"><span style="font-family: Times New Roman;"> <br />
</span></span><span style="font-family: 宋体;">选出一行后才能去选</span><span lang="EN-US"><span style="font-family: Times New Roman;">rownum=2</span></span><span style="font-family: 宋体;">的行</span><span lang="EN-US"><span style="font-family: Times New Roman;">&#8230;&#8230;</span></span></span></p>
<img src ="http://www.blogjava.net/conans/aggbug/319963.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2010-05-03 19:46 <a href="http://www.blogjava.net/conans/articles/319963.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle递归查询</title><link>http://www.blogjava.net/conans/articles/318052.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Mon, 12 Apr 2010 05:35:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/318052.html</guid><description><![CDATA[转自：http://www.javaeye.com/topic/625574<br />
<br />
有的情况下，我们需要用递归的方法整理数据，这才程序中很容易做到，但是在数据库中，用SQL语句怎么实现？下面我以最典型的树形结构来说明下如何在Oracle使用递归查询。 <br />
&nbsp;&nbsp;&nbsp; 为了说明方便，创建一张数据库表，用于存储一个简单的树形结构
<div>
<div>
<div>Sql代码 <embed src="http://www.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=create%20table%20TEST_TREE%0A(%0A%20%20ID%20%20%20NUMBER%2C%0A%20%20PID%20%20NUMBER%2C%0A%20%20IND%20%20NUMBER%2C%0A%20%20NAME%20VARCHAR2(32)%0A)%0A" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" height="15" width="14"></div>
</div>
<ol start="1">
    <li>create&nbsp;table&nbsp;TEST_TREE&nbsp;&nbsp;</li>
    <li>(&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;ID&nbsp;&nbsp;&nbsp;NUMBER,&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;PID&nbsp;&nbsp;NUMBER,&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;IND&nbsp;&nbsp;NUMBER,&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;NAME&nbsp;VARCHAR2(32)&nbsp;&nbsp;</li>
    <li>)&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">create table TEST_TREE
(
ID   NUMBER,
PID  NUMBER,
IND  NUMBER,
NAME VARCHAR2(32)
)
</pre>
<p><br />
&nbsp;&nbsp;&nbsp; ID是主键，PID是父节点ID，IND是排序字段，NAME是节点名称。初始化几条测试数据。</p>
<table style="text-align: left;" border="1">
    <tbody>
        <tr>
            <th>ID</th>
            <th>PID</th>
            <th>IND</th>
            <th>NAME</th>
        </tr>
        <tr>
            <td>1</td>
            <td>0</td>
            <td>1</td>
            <td>根节点</td>
        </tr>
        <tr>
            <td>2</td>
            <td>1</td>
            <td>1</td>
            <td>一级菜单1</td>
        </tr>
        <tr>
            <td>3</td>
            <td>1</td>
            <td>2</td>
            <td>一级菜单2</td>
        </tr>
        <tr>
            <td>4</td>
            <td>1</td>
            <td>2</td>
            <td>一级菜单3</td>
        </tr>
        <tr>
            <td>5</td>
            <td>2</td>
            <td>1</td>
            <td>一级1子1</td>
        </tr>
        <tr>
            <td>6</td>
            <td>2</td>
            <td>2</td>
            <td>一级1子2</td>
        </tr>
        <tr>
            <td>7</td>
            <td>4</td>
            <td>1</td>
            <td>一级3子1</td>
        </tr>
        <tr>
            <td>8</td>
            <td>4</td>
            <td>2</td>
            <td>一级3子2</td>
        </tr>
        <tr>
            <td>9</td>
            <td>4</td>
            <td>3</td>
            <td>一级3子3</td>
        </tr>
        <tr>
            <td>10</td>
            <td>4</td>
            <td>0</td>
            <td>一级3子0</td>
        </tr>
    </tbody>
</table>
<p>一、基本使用：</p>
<p>&nbsp;&nbsp;&nbsp; 在Oracle中，递归查询要用到start&nbsp;&nbsp; with 。。。。connect&nbsp;&nbsp; by&nbsp;&nbsp; prior。。。</p>
<p>&nbsp;&nbsp;&nbsp; 具体格式是：</p>
<div>
<div>
<div>Sql代码 <embed src="http://www.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=SELECT%20column%0AFROM%20table_name%0ASTART%20WITH%20column%3Dvalue%0ACONNECT%20BY%20PRIOR%20%E7%88%B6%E4%B8%BB%E9%94%AE%3D%E5%AD%90%E5%A4%96%E9%94%AE" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" height="15" width="14"></div>
</div>
<ol start="1">
    <li>SELECT&nbsp;column&nbsp;&nbsp;</li>
    <li>FROM&nbsp;table_name&nbsp;&nbsp;</li>
    <li>START&nbsp;WITH&nbsp;column=value&nbsp;&nbsp;</li>
    <li>CONNECT&nbsp;BY&nbsp;PRIOR&nbsp;父主键=子外键&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">SELECT column
FROM table_name
START WITH column=value
CONNECT BY PRIOR 父主键=子外键</pre>
<p>&nbsp;&nbsp;&nbsp; 对于本例来说，就是：</p>
<div>
<div>
<div>Sql代码 <embed src="http://www.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=select%20%20%20d.*%20%20%20from%20%20test_tree%20d%20%0A%20%20start%20%20%20with%20%20%20d.pid%3D0%0A%20%20connect%20%20%20by%20%20%20prior%20%20%20d.id%3Dd.pid%20" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" height="15" width="14"></div>
</div>
<ol start="1">
    <li>select&nbsp;&nbsp;&nbsp;d.*&nbsp;&nbsp;&nbsp;from&nbsp;&nbsp;test_tree&nbsp;d&nbsp;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;start&nbsp;&nbsp;&nbsp;with&nbsp;&nbsp;&nbsp;d.pid=0&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;connect&nbsp;&nbsp;&nbsp;by&nbsp;&nbsp;&nbsp;prior&nbsp;&nbsp;&nbsp;d.id=d.pid&nbsp;&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">select   d.*   from  test_tree d
start   with   d.pid=0
connect   by   prior   d.id=d.pid </pre>
<p>&nbsp;&nbsp; 查询结果如下：</p>
<table border="1">
    <tbody>
        <tr>
            <th>ID</th>
            <th>PID</th>
            <th>IND</th>
            <th>NAME</th>
        </tr>
        <tr>
            <td>1</td>
            <td>0</td>
            <td>1</td>
            <td>根节点</td>
        </tr>
        <tr>
            <td>2</td>
            <td>1</td>
            <td>1</td>
            <td>一级菜单1</td>
        </tr>
        <tr>
            <td>5</td>
            <td>2</td>
            <td>1</td>
            <td>一级1子1</td>
        </tr>
        <tr>
            <td>6</td>
            <td>2</td>
            <td>2</td>
            <td>一级1子2</td>
        </tr>
        <tr>
            <td>3</td>
            <td>1</td>
            <td>2</td>
            <td>一级菜单2</td>
        </tr>
        <tr>
            <td>4</td>
            <td>1</td>
            <td>2</td>
            <td>一级菜单3</td>
        </tr>
        <tr>
            <td>7</td>
            <td>4</td>
            <td>1</td>
            <td>一级3子1</td>
        </tr>
        <tr>
            <td>8</td>
            <td>4</td>
            <td>2</td>
            <td>一级3子2</td>
        </tr>
        <tr>
            <td>9</td>
            <td>4</td>
            <td>3</td>
            <td>一级3子3</td>
        </tr>
        <tr>
            <td>10</td>
            <td>4</td>
            <td>0</td>
            <td>一级3子0</td>
        </tr>
    </tbody>
</table>
<p>&nbsp;我们从结果中可以看到，记录已经是按照树形结构进行排列了，但是现在有个新问题，如果我们有这样的需求，就是不但要求结果按照树形结构显示，还要根据ind字段在每一个分支内进行排序，这个问题怎么处理呢？我们可能很自然的想到如下语句：</p>
<div>
<div>
<div>Sql代码 <embed src="http://www.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=select%20%20%20d.*%20%20%20from%20%20test_tree%20d%20%0A%20%20start%20%20%20with%20%20%20d.pid%3D0%0A%20%20connect%20%20%20by%20%20%20prior%20%20%20d.id%3Dd.pid%20%0A%20%20order%20by%20d.ind" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" height="15" width="14"></div>
</div>
<ol start="1">
    <li>select&nbsp;&nbsp;&nbsp;d.*&nbsp;&nbsp;&nbsp;from&nbsp;&nbsp;test_tree&nbsp;d&nbsp;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;start&nbsp;&nbsp;&nbsp;with&nbsp;&nbsp;&nbsp;d.pid=0&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;connect&nbsp;&nbsp;&nbsp;by&nbsp;&nbsp;&nbsp;prior&nbsp;&nbsp;&nbsp;d.id=d.pid&nbsp;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;order&nbsp;by&nbsp;d.ind&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">select   d.*   from  test_tree d
start   with   d.pid=0
connect   by   prior   d.id=d.pid
order by d.ind</pre>
<p>&nbsp;结果如下：</p>
<table border="1">
    <tbody>
        <tr>
            <th>ID</th>
            <th>PID</th>
            <th>IND</th>
            <th>NAME</th>
        </tr>
        <tr>
            <td>1</td>
            <td>0</td>
            <td>1</td>
            <td>根节点</td>
        </tr>
        <tr>
            <td>2</td>
            <td>1</td>
            <td>1</td>
            <td>一级菜单1</td>
        </tr>
        <tr>
            <td>5</td>
            <td>2</td>
            <td>1</td>
            <td>一级1子1</td>
        </tr>
        <tr>
            <td>6</td>
            <td>2</td>
            <td>2</td>
            <td>一级1子2</td>
        </tr>
        <tr>
            <td>4</td>
            <td>1</td>
            <td>2</td>
            <td>一级菜单3</td>
        </tr>
        <tr>
            <td>10</td>
            <td>4</td>
            <td>0</td>
            <td>一级3子0</td>
        </tr>
        <tr>
            <td>8</td>
            <td>4</td>
            <td>2</td>
            <td>一级3子2</td>
        </tr>
        <tr>
            <td>9</td>
            <td>4</td>
            <td>3</td>
            <td>一级3子3</td>
        </tr>
        <tr>
            <td>7</td>
            <td>4</td>
            <td>1</td>
            <td>一级3子1</td>
        </tr>
        <tr>
            <td>3</td>
            <td>1</td>
            <td>2</td>
            <td>一级菜单2</td>
        </tr>
    </tbody>
</table>
<p>这显然不是我们想要的结果，那下面的这个语句呢？</p>
<div>
<div>
<div>Sql代码 <embed src="http://www.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=select%20%20%20d.*%20%20%20from%20%20(select%20dd.*%20from%20test_tree%20dd%20order%20by%20dd.ind)%20d%20%0A%20%20start%20%20%20with%20%20%20d.pid%3D0%0A%20%20connect%20%20%20by%20%20%20prior%20%20%20d.id%3Dd.pid%20" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" height="15" width="14"></div>
</div>
<ol start="1">
    <li>select&nbsp;&nbsp;&nbsp;d.*&nbsp;&nbsp;&nbsp;from&nbsp;&nbsp;(select&nbsp;dd.*&nbsp;from&nbsp;test_tree&nbsp;dd&nbsp;order&nbsp;by&nbsp;dd.ind)&nbsp;d&nbsp;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;start&nbsp;&nbsp;&nbsp;with&nbsp;&nbsp;&nbsp;d.pid=0&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;connect&nbsp;&nbsp;&nbsp;by&nbsp;&nbsp;&nbsp;prior&nbsp;&nbsp;&nbsp;d.id=d.pid&nbsp;&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">select   d.*   from  (select dd.* from test_tree dd order by dd.ind) d
start   with   d.pid=0
connect   by   prior   d.id=d.pid </pre>
<p>结果如下：</p>
<table border="1">
    <tbody>
        <tr>
            <th>ID</th>
            <th>PID</th>
            <th>IND</th>
            <th>NAME</th>
        </tr>
        <tr>
            <td>1</td>
            <td>0</td>
            <td>1</td>
            <td>根节点</td>
        </tr>
        <tr>
            <td>2</td>
            <td>1</td>
            <td>1</td>
            <td>一级菜单1</td>
        </tr>
        <tr>
            <td>5</td>
            <td>2</td>
            <td>1</td>
            <td>一级1子1</td>
        </tr>
        <tr>
            <td>6</td>
            <td>2</td>
            <td>2</td>
            <td>一级1子2</td>
        </tr>
        <tr>
            <td>4</td>
            <td>1</td>
            <td>2</td>
            <td>一级菜单3</td>
        </tr>
        <tr>
            <td>10</td>
            <td>4</td>
            <td>0</td>
            <td>一级3子0</td>
        </tr>
        <tr>
            <td>8</td>
            <td>4</td>
            <td>2</td>
            <td>一级3子2</td>
        </tr>
        <tr>
            <td>9</td>
            <td>4</td>
            <td>3</td>
            <td>一级3子3</td>
        </tr>
        <tr>
            <td>7</td>
            <td>4</td>
            <td>1</td>
            <td>一级3子1</td>
        </tr>
        <tr>
            <td>3</td>
            <td>1</td>
            <td>2</td>
            <td>一级菜单2</td>
        </tr>
    </tbody>
</table>
<p>这个结果看似对了，但由于一级菜单3节点下有一个节点的ind=0，导致一级菜单2被拍到了3下面。如果想使用类似这样的语句做到各分支内排序，则需要找到一个能够准确描述菜单级别的字段，但是对于示例表来说，不存在这么一个字段。</p>
<p>那我们如何实现需求呢？其实Oracle9以后，提供了一种排序&#8220;order siblings by&#8221;就可以实现我们的需求，用法如下：</p>
<div>
<div>
<div>Sql代码 <embed src="http://www.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=select%20%20%20d.*%20%20%20from%20%20test_tree%20d%20%0A%20%20start%20%20%20with%20%20%20d.pid%3D0%0A%20%20connect%20%20%20by%20%20%20prior%20%20%20d.id%3Dd.pid%20%0A%20%20order%20%20%20siblings%20%20%20by%20%20%20d.ind%20%20%20asc" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" height="15" width="14"></div>
</div>
<ol start="1">
    <li>select&nbsp;&nbsp;&nbsp;d.*&nbsp;&nbsp;&nbsp;from&nbsp;&nbsp;test_tree&nbsp;d&nbsp;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;start&nbsp;&nbsp;&nbsp;with&nbsp;&nbsp;&nbsp;d.pid=0&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;connect&nbsp;&nbsp;&nbsp;by&nbsp;&nbsp;&nbsp;prior&nbsp;&nbsp;&nbsp;d.id=d.pid&nbsp;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;order&nbsp;&nbsp;&nbsp;siblings&nbsp;&nbsp;&nbsp;by&nbsp;&nbsp;&nbsp;d.ind&nbsp;&nbsp;&nbsp;asc&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="sql">select   d.*   from  test_tree d
start   with   d.pid=0
connect   by   prior   d.id=d.pid
order   siblings   by   d.ind   asc</pre>
<p>结果如下：</p>
<table border="1">
    <tbody>
        <tr>
            <th>ID</th>
            <th>PID</th>
            <th>IND</th>
            <th>NAME</th>
        </tr>
        <tr>
            <td>1</td>
            <td>0</td>
            <td>1</td>
            <td>根节点</td>
        </tr>
        <tr>
            <td>2</td>
            <td>1</td>
            <td>1</td>
            <td>一级菜单1</td>
        </tr>
        <tr>
            <td>5</td>
            <td>2</td>
            <td>1</td>
            <td>一级1子1</td>
        </tr>
        <tr>
            <td>6</td>
            <td>2</td>
            <td>2</td>
            <td>一级1子2</td>
        </tr>
        <tr>
            <td>3</td>
            <td>1</td>
            <td>2</td>
            <td>一级菜单2</td>
        </tr>
        <tr>
            <td>4</td>
            <td>1</td>
            <td>2</td>
            <td>一级菜单3</td>
        </tr>
        <tr>
            <td>10</td>
            <td>4</td>
            <td>0</td>
            <td>一级3子0</td>
        </tr>
        <tr>
            <td>7</td>
            <td>4</td>
            <td>1</td>
            <td>一级3子1</td>
        </tr>
        <tr>
            <td>8</td>
            <td>4</td>
            <td>2</td>
            <td>一级3子2</td>
        </tr>
        <tr>
            <td>9</td>
            <td>4</td>
            <td>3</td>
            <td>一级3子3</td>
        </tr>
    </tbody>
</table>
<p>这样一来，查询结果就完全符合我们的要求了。</p>
<p>至于在Oracle8以前版本，或者其他数据库中如何实现类似的功能，希望大家来指教下，谢谢。</p>
<br />
<br />
<img src ="http://www.blogjava.net/conans/aggbug/318052.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2010-04-12 13:35 <a href="http://www.blogjava.net/conans/articles/318052.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)Oracle开发专题之：窗口函数 </title><link>http://www.blogjava.net/conans/articles/242303.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Mon, 24 Nov 2008 09:25:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/242303.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;只有注册用户登录后才能阅读该文。<a href='http://www.blogjava.net/conans/articles/242303.html'>阅读全文</a><img src ="http://www.blogjava.net/conans/aggbug/242303.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-11-24 17:25 <a href="http://www.blogjava.net/conans/articles/242303.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（转）Oracle开发专题之：分析函数2(Rank, Dense_rank, row_number) </title><link>http://www.blogjava.net/conans/articles/242192.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Mon, 24 Nov 2008 01:21:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/242192.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;只有注册用户登录后才能阅读该文。<a href='http://www.blogjava.net/conans/articles/242192.html'>阅读全文</a><img src ="http://www.blogjava.net/conans/aggbug/242192.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-11-24 09:21 <a href="http://www.blogjava.net/conans/articles/242192.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)Oracle开发专题之：分析函数(OVER) </title><link>http://www.blogjava.net/conans/articles/242191.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Mon, 24 Nov 2008 01:19:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/242191.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;只有注册用户登录后才能阅读该文。<a href='http://www.blogjava.net/conans/articles/242191.html'>阅读全文</a><img src ="http://www.blogjava.net/conans/aggbug/242191.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-11-24 09:19 <a href="http://www.blogjava.net/conans/articles/242191.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle 日期类型字段的操作(转)</title><link>http://www.blogjava.net/conans/articles/210933.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Thu, 26 Jun 2008 11:55:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/210933.html</guid><description><![CDATA[<div class="blog_content">
<p><strong></strong>在java对oracle的操作中，日期字段是很头疼的事情，其实仔细研究一下也并不难掌握。 </p>
<p>　　举个例子来说明：</p>
<p>　　表 book&nbsp; 中有name varchar2(20)//书籍名称,buydate Date //购买日期 两个字段。</p>
<p>　　已经创建了数据库连接Connection conn;</p>
<p>　　<strong>方法一、使用java.sql.Date实现比较简单的yyyy-mm-dd格式日期。</strong> </p>
<p>　　java.sql.Date不支持时间格式。切记不要使用new java.sql.Date(int year,int month,int date),因为还要处理时间差问题。</p>
<p>&nbsp;</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://sunxboy.javaeye.com/blog/206010#"><img alt="复制代码" src="http://sunxboy.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>PreparedStatement&nbsp;pstmt&nbsp;=&nbsp;conn.prepareStatement(</span><span class="string">"insert&nbsp;into&nbsp;book&nbsp;(name,buydate)&nbsp;values&nbsp;(?,?)"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>　　java.sql.Date&nbsp;buydate=java.sql.Date.valueOf(</span><span class="string">"2005-06-08"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>　　pstmt.setString(</span><span class="number">1</span><span>,&nbsp;</span><span class="string">"Java编程思想"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>　　pstmt.setDate(</span><span class="number">2</span><span>,buydate&nbsp;); &nbsp;&nbsp;</span></span></li>
    <li><span>　　pstmt.execute();&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">PreparedStatement pstmt = conn.prepareStatement("insert into book (name,buydate) values (?,?)");
　　java.sql.Date buydate=java.sql.Date.valueOf("2005-06-08");
　　pstmt.setString(1, "Java编程思想");
　　pstmt.setDate(2,buydate );
　　pstmt.execute();
</pre>
&nbsp;
<p>&nbsp;</p>
<p>　　<strong>方法二、使用java.sql.Timestamp,同上不使用new Timestamp(....)</strong> </p>
<p>&nbsp;</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://sunxboy.javaeye.com/blog/206010#"><img alt="复制代码" src="http://sunxboy.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>PreparedStatement&nbsp;pstmt&nbsp;=&nbsp;conn.prepareStatement(</span><span class="string">"insert&nbsp;into&nbsp;book&nbsp;(name,buydate)&nbsp;values&nbsp;(?,?)"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>　　java.sql.Timestamp&nbsp;buydate=java.sql.Timestamp.valueOf(</span><span class="string">"2004-06-08&nbsp;05:33:99"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>　　pstmt.setString(</span><span class="number">1</span><span>,&nbsp;</span><span class="string">"Java编程思想"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>　　pstmt.setTimestamp(</span><span class="number">2</span><span>,buydate&nbsp;); &nbsp;&nbsp;</span></span></li>
    <li><span>　　pstmt.execute();&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">PreparedStatement pstmt = conn.prepareStatement("insert into book (name,buydate) values (?,?)");
　　java.sql.Timestamp buydate=java.sql.Timestamp.valueOf("2004-06-08 05:33:99");
　　pstmt.setString(1, "Java编程思想");
　　pstmt.setTimestamp(2,buydate );
　　pstmt.execute();
</pre>
&nbsp;
<p>&nbsp;</p>
<p>　　<strong>方法三、使用oracle 的to_date内置函数</strong> </p>
<p>&nbsp;</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://sunxboy.javaeye.com/blog/206010#"><img alt="复制代码" src="http://sunxboy.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>PreparedStatement&nbsp;pstmt&nbsp;=&nbsp;conn.prepareStatement(</span><span class="string">"insert&nbsp;into&nbsp;book&nbsp;(name,buydate)&nbsp;values&nbsp;(?,to_date(?,&nbsp;'yyyy-mm-dd&nbsp;hh24:mi:ss')"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>　　String&nbsp;buydate=</span><span class="string">"2004-06-08&nbsp;05:33:99"</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>　　pstmt.setString(</span><span class="number">1</span><span>,&nbsp;</span><span class="string">"Java编程思想"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>　　pstmt.setString(</span><span class="number">2</span><span>,buydate&nbsp;); &nbsp;&nbsp;</span></span></li>
    <li><span>　　pstmt.execute();&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">PreparedStatement pstmt = conn.prepareStatement("insert into book (name,buydate) values (?,to_date(?, 'yyyy-mm-dd hh24:mi:ss')");
　　String buydate="2004-06-08 05:33:99";
　　pstmt.setString(1, "Java编程思想");
　　pstmt.setString(2,buydate );
　　pstmt.execute();
</pre>
&nbsp;
<p>&nbsp;</p>
<p>　　<strong>附:oracle日期格式参数 含义说明&nbsp; <br />
</strong>　　d: 一周中的星期几&nbsp; <br />
　　day: 天的名字，使用空格填充到9个字符&nbsp; <br />
　　dd: 月中的第几天&nbsp; <br />
　　ddd: 年中的第几天&nbsp; <br />
　　dy: 天的简写名&nbsp; <br />
　　iw: ISO标准的年中的第几周&nbsp; <br />
　　iyyy: ISO标准的四位年份&nbsp; <br />
　　yyyy: 四位年份&nbsp; <br />
　　yyy,yy,y: 年份的最后三位，两位，一位&nbsp; <br />
　　hh: 小时，按12小时计&nbsp; <br />
　　hh24: 小时，按24小时计&nbsp; <br />
　　mi: 分&nbsp; <br />
　　ss: 秒&nbsp; <br />
　　mm: 月&nbsp; <br />
　　mon: 月份的简写&nbsp; <br />
　　month: 月份的全名&nbsp; <br />
　　w: 该月的第几个星期&nbsp; <br />
　　ww: 年中的第几个星期</p>
</div>
<img src ="http://www.blogjava.net/conans/aggbug/210933.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-06-26 19:55 <a href="http://www.blogjava.net/conans/articles/210933.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle时间的应用(转)</title><link>http://www.blogjava.net/conans/articles/210931.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Thu, 26 Jun 2008 11:53:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/210931.html</guid><description><![CDATA[<p>1、转换函数<br />
与date操作关系最大的就是两个转换函数：to_date(),to_char()<br />
to_date()&nbsp;作用将字符类型按一定格式转化为日期类型：<br />
具体用法:to_date('2004-11-27','yyyy-mm-dd'),前者为字符串，后者为转换日期格式，注意，前后两者要以一对应。<br />
如;to_date('2004-11-27&nbsp;13:34:43',&nbsp;'yyyy-mm-dd&nbsp;hh24:mi:ss')&nbsp;将得到具体的时间<br />
<br />
多种日期格式：<br />
<br />
YYYY：四位表示的年份&nbsp;<br />
YYY，YY，Y：年份的最后三位、两位或一位，缺省为当前世纪&nbsp;<br />
MM：01~12的月份编号&nbsp;<br />
MONTH：九个字符表示的月份，右边用空格填补&nbsp;<br />
MON：三位字符的月份缩写&nbsp;<br />
WW：一年中的星期&nbsp;<br />
D：星期中的第几天&nbsp;<br />
DD：月份中的第几天&nbsp;<br />
DDD：年所中的第几天&nbsp;<br />
DAY：九个字符表示的天的全称，右边用空格补齐&nbsp;<br />
HH，HH12：一天中的第几个小时，12进制表示法&nbsp;<br />
HH24：一天中的第几个小时，取值为00~23&nbsp;<br />
MI：一小时中的分钟&nbsp;<br />
SS：一分钟中的秒&nbsp;<br />
SSSS：从午夜开始过去的秒数&nbsp;<br />
<br />
to_char():将日期转按一定格式换成字符类型<br />
SQL&gt;&nbsp;select&nbsp;to_char(sysdate,'yyyy-mm-dd&nbsp;hh24:mi:ss')&nbsp;time&nbsp;from&nbsp;dual;<br />
<br />
TIME<br />
-------------------<br />
2004-10-08&nbsp;15:22:58<br />
<br />
即把当前时间按yyyy-mm-dd&nbsp;hh24:mi:ss格式转换成字符类型<br />
<br />
在oracle中处理日期大全&nbsp;<br />
<br />
&nbsp;&nbsp;TO_DATE格式&nbsp;&nbsp;<br />
Day:&nbsp;&nbsp;<br />
dd&nbsp;number&nbsp;12&nbsp;&nbsp;<br />
dy&nbsp;abbreviated&nbsp;fri&nbsp;&nbsp;<br />
day&nbsp;spelled&nbsp;out&nbsp;friday&nbsp;&nbsp;<br />
ddspth&nbsp;spelled&nbsp;out,&nbsp;ordinal&nbsp;twelfth&nbsp;&nbsp;<br />
Month:&nbsp;&nbsp;<br />
mm&nbsp;number&nbsp;03&nbsp;&nbsp;<br />
mon&nbsp;abbreviated&nbsp;mar&nbsp;&nbsp;<br />
month&nbsp;spelled&nbsp;out&nbsp;march&nbsp;&nbsp;<br />
Year:&nbsp;&nbsp;<br />
yy&nbsp;two&nbsp;digits&nbsp;98&nbsp;&nbsp;<br />
yyyy&nbsp;four&nbsp;digits&nbsp;1998&nbsp;&nbsp;<br />
<br />
24小时格式下时间范围为：&nbsp;0:00:00&nbsp;-&nbsp;23:59:59....&nbsp;&nbsp;<br />
12小时格式下时间范围为：&nbsp;1:00:00&nbsp;-&nbsp;12:59:59&nbsp;....&nbsp;&nbsp;<br />
<br />
[ZT]日期和??函???<br />
1.&nbsp;&nbsp;<br />
日期和字符转换函数用法（to_date,to_char）&nbsp;&nbsp;<br />
<br />
2.&nbsp;&nbsp;<br />
select&nbsp;to_char(&nbsp;to_date(222,'J'),'Jsp')&nbsp;from&nbsp;dual&nbsp;&nbsp;<br />
<br />
显示Two&nbsp;Hundred&nbsp;Twenty-Two&nbsp;&nbsp;<br />
<br />
3.&nbsp;&nbsp;<br />
求某天是星期几&nbsp;&nbsp;<br />
select&nbsp;to_char(to_date('2002-08-26','yyyy-mm-dd'),'day')&nbsp;from&nbsp;dual;&nbsp;&nbsp;<br />
星期一&nbsp;&nbsp;<br />
select&nbsp;to_char(to_date('2002-08-26','yyyy-mm-dd'),'day','NLS_DATE_LANGUAGE&nbsp;=&nbsp;American')&nbsp;from&nbsp;dual;&nbsp;&nbsp;<br />
monday&nbsp;&nbsp;<br />
设置日期语言&nbsp;&nbsp;<br />
ALTER&nbsp;SESSION&nbsp;SET&nbsp;NLS_DATE_LANGUAGE='AMERICAN';&nbsp;&nbsp;<br />
也可以这样&nbsp;&nbsp;<br />
TO_DATE&nbsp;('2002-08-26',&nbsp;'YYYY-mm-dd',&nbsp;'NLS_DATE_LANGUAGE&nbsp;=&nbsp;American')&nbsp;&nbsp;<br />
<br />
4.&nbsp;&nbsp;<br />
两个日期间的天数&nbsp;&nbsp;<br />
select&nbsp;floor(sysdate&nbsp;-&nbsp;to_date('20020405','yyyymmdd'))&nbsp;from&nbsp;dual;&nbsp;&nbsp;<br />
<br />
5.&nbsp;时间为null的用法&nbsp;&nbsp;<br />
select&nbsp;id,&nbsp;active_date&nbsp;from&nbsp;table1&nbsp;&nbsp;<br />
UNION&nbsp;&nbsp;<br />
select&nbsp;1,&nbsp;TO_DATE(null)&nbsp;from&nbsp;dual;&nbsp;&nbsp;<br />
<br />
注意要用TO_DATE(null)&nbsp;&nbsp;<br />
<br />
6.&nbsp;&nbsp;<br />
a_date&nbsp;between&nbsp;to_date('20011201','yyyymmdd')&nbsp;and&nbsp;to_date('20011231','yyyymmdd')&nbsp;&nbsp;<br />
那么12月31号中午12点之后和12月1号的12点之前是不包含在这个范围之内的。&nbsp;&nbsp;<br />
所以，当时间需要精确的时候，觉得to_char还是必要的&nbsp;&nbsp;<br />
7.&nbsp;日期格式冲突问题&nbsp;&nbsp;<br />
输入的格式要看你安装的ORACLE字符集的类型,&nbsp;比如:&nbsp;US7ASCII,&nbsp;date格式的类型就是:&nbsp;'01-Jan-01'&nbsp;&nbsp;<br />
alter&nbsp;system&nbsp;set&nbsp;NLS_DATE_LANGUAGE&nbsp;=&nbsp;American&nbsp;&nbsp;<br />
alter&nbsp;session&nbsp;set&nbsp;NLS_DATE_LANGUAGE&nbsp;=&nbsp;American&nbsp;&nbsp;<br />
或者在to_date中写&nbsp;&nbsp;<br />
select&nbsp;to_char(to_date('2002-08-26','yyyy-mm-dd'),'day','NLS_DATE_LANGUAGE&nbsp;=&nbsp;American')&nbsp;from&nbsp;dual;&nbsp;&nbsp;<br />
注意我这只是举了NLS_DATE_LANGUAGE，当然还有很多，&nbsp;&nbsp;<br />
可查看&nbsp;&nbsp;<br />
select&nbsp;*&nbsp;from&nbsp;nls_session_parameters&nbsp;&nbsp;<br />
select&nbsp;*&nbsp;from&nbsp;V$NLS_PARAMETERS&nbsp;&nbsp;<br />
<br />
8.&nbsp;&nbsp;<br />
select&nbsp;count(*)&nbsp;&nbsp;<br />
from&nbsp;(&nbsp;select&nbsp;rownum-1&nbsp;rnum&nbsp;&nbsp;<br />
from&nbsp;all_objects&nbsp;&nbsp;<br />
where&nbsp;rownum&nbsp;&lt;=&nbsp;to_date('2002-02-28','yyyy-mm-dd')&nbsp;-&nbsp;to_date('2002-&nbsp;&nbsp;<br />
02-01','yyyy-mm-dd')+1&nbsp;&nbsp;<br />
)&nbsp;&nbsp;<br />
where&nbsp;to_char(&nbsp;to_date('2002-02-01','yyyy-mm-dd')+rnum-1,&nbsp;'D'&nbsp;)&nbsp;&nbsp;<br />
not&nbsp;&nbsp;<br />
in&nbsp;(&nbsp;'1',&nbsp;'7'&nbsp;)&nbsp;&nbsp;<br />
<br />
查找2002-02-28至2002-02-01间除星期一和七的天数&nbsp;&nbsp;<br />
在前后分别调用DBMS_UTILITY.GET_TIME,&nbsp;让后将结果相减(得到的是1/100秒,&nbsp;而不是毫秒).&nbsp;&nbsp;<br />
<br />
9.&nbsp;&nbsp;<br />
select&nbsp;months_between(to_date('01-31-1999','MM-DD-YYYY'),&nbsp;&nbsp;<br />
to_date('12-31-1998','MM-DD-YYYY'))&nbsp;"MONTHS"&nbsp;FROM&nbsp;DUAL;&nbsp;&nbsp;<br />
1&nbsp;&nbsp;<br />
<br />
select&nbsp;months_between(to_date('02-01-1999','MM-DD-YYYY'),&nbsp;&nbsp;<br />
to_date('12-31-1998','MM-DD-YYYY'))&nbsp;"MONTHS"&nbsp;FROM&nbsp;DUAL;&nbsp;&nbsp;<br />
<br />
1.03225806451613&nbsp;&nbsp;<br />
10.&nbsp;Next_day的用法&nbsp;&nbsp;<br />
Next_day(date,&nbsp;day)&nbsp;&nbsp;<br />
<br />
Monday-Sunday,&nbsp;for&nbsp;format&nbsp;code&nbsp;DAY&nbsp;&nbsp;<br />
Mon-Sun,&nbsp;for&nbsp;format&nbsp;code&nbsp;DY&nbsp;&nbsp;<br />
1-7,&nbsp;for&nbsp;format&nbsp;code&nbsp;D&nbsp;&nbsp;<br />
<br />
11&nbsp;&nbsp;<br />
select&nbsp;to_char(sysdate,'hh:mi:ss')&nbsp;TIME&nbsp;from&nbsp;all_objects&nbsp;&nbsp;<br />
注意：第一条记录的TIME&nbsp;与最后一行是一样的&nbsp;&nbsp;<br />
可以建立一个函数来处理这个问题&nbsp;&nbsp;<br />
create&nbsp;or&nbsp;replace&nbsp;function&nbsp;sys_date&nbsp;return&nbsp;date&nbsp;is&nbsp;&nbsp;<br />
begin&nbsp;&nbsp;<br />
return&nbsp;sysdate;&nbsp;&nbsp;<br />
end;&nbsp;&nbsp;<br />
<br />
select&nbsp;to_char(sys_date,'hh:mi:ss')&nbsp;from&nbsp;all_objects;&nbsp;&nbsp;<br />
12.&nbsp;&nbsp;<br />
获得小时数&nbsp;&nbsp;<br />
<br />
SELECT&nbsp;EXTRACT(HOUR&nbsp;FROM&nbsp;TIMESTAMP&nbsp;'2001-02-16&nbsp;2:38:40')&nbsp;from&nbsp;offer&nbsp;&nbsp;<br />
SQL&gt;&nbsp;select&nbsp;sysdate&nbsp;,to_char(sysdate,'hh')&nbsp;from&nbsp;dual;&nbsp;&nbsp;<br />
<br />
SYSDATE&nbsp;TO_CHAR(SYSDATE,'HH')&nbsp;&nbsp;<br />
--------------------&nbsp;---------------------&nbsp;&nbsp;<br />
2003-10-13&nbsp;19:35:21&nbsp;07&nbsp;&nbsp;<br />
<br />
SQL&gt;&nbsp;select&nbsp;sysdate&nbsp;,to_char(sysdate,'hh24')&nbsp;from&nbsp;dual;&nbsp;&nbsp;<br />
<br />
SYSDATE&nbsp;TO_CHAR(SYSDATE,'HH24')&nbsp;&nbsp;<br />
--------------------&nbsp;-----------------------&nbsp;&nbsp;<br />
2003-10-13&nbsp;19:35:21&nbsp;19&nbsp;&nbsp;<br />
<br />
获取年月日与此类似&nbsp;&nbsp;<br />
13.&nbsp;&nbsp;<br />
年月日的处理&nbsp;&nbsp;<br />
select&nbsp;older_date,&nbsp;&nbsp;<br />
newer_date,&nbsp;&nbsp;<br />
years,&nbsp;&nbsp;<br />
months,&nbsp;&nbsp;<br />
abs(&nbsp;&nbsp;<br />
trunc(&nbsp;&nbsp;<br />
newer_date-&nbsp;&nbsp;<br />
add_months(&nbsp;older_date,years*12+months&nbsp;)&nbsp;&nbsp;<br />
)&nbsp;&nbsp;<br />
)&nbsp;days&nbsp;&nbsp;<br />
from&nbsp;(&nbsp;select&nbsp;&nbsp;<br />
trunc(months_between(&nbsp;newer_date,&nbsp;older_date&nbsp;)/12)&nbsp;YEARS,&nbsp;&nbsp;<br />
mod(trunc(months_between(&nbsp;newer_date,&nbsp;older_date&nbsp;)),&nbsp;&nbsp;<br />
12&nbsp;)&nbsp;MONTHS,&nbsp;&nbsp;<br />
newer_date,&nbsp;&nbsp;<br />
older_date&nbsp;&nbsp;<br />
from&nbsp;(&nbsp;select&nbsp;hiredate&nbsp;older_date,&nbsp;&nbsp;<br />
add_months(hiredate,rownum)+rownum&nbsp;newer_date&nbsp;&nbsp;<br />
from&nbsp;emp&nbsp;)&nbsp;&nbsp;<br />
)&nbsp;&nbsp;<br />
<br />
14.&nbsp;&nbsp;<br />
处理月份天数不定的办法&nbsp;&nbsp;<br />
select&nbsp;to_char(add_months(last_day(sysdate)&nbsp;+1,&nbsp;-2),&nbsp;'yyyymmdd'),last_day(sysdate)&nbsp;from&nbsp;dual&nbsp;&nbsp;<br />
<br />
16.&nbsp;&nbsp;<br />
找出今年的天数&nbsp;&nbsp;<br />
select&nbsp;add_months(trunc(sysdate,'year'),&nbsp;12)&nbsp;-&nbsp;trunc(sysdate,'year')&nbsp;from&nbsp;dual&nbsp;&nbsp;<br />
<br />
闰年的处理方法&nbsp;&nbsp;<br />
to_char(&nbsp;last_day(&nbsp;to_date('02'&nbsp;||&nbsp;:year,'mmyyyy')&nbsp;),&nbsp;'dd'&nbsp;)&nbsp;&nbsp;<br />
如果是28就不是闰年&nbsp;&nbsp;<br />
<br />
17.&nbsp;&nbsp;<br />
yyyy与rrrr的区别&nbsp;&nbsp;<br />
'YYYY99&nbsp;TO_C&nbsp;&nbsp;<br />
-------&nbsp;----&nbsp;&nbsp;<br />
yyyy&nbsp;99&nbsp;0099&nbsp;&nbsp;<br />
rrrr&nbsp;99&nbsp;1999&nbsp;&nbsp;<br />
yyyy&nbsp;01&nbsp;0001&nbsp;&nbsp;<br />
rrrr&nbsp;01&nbsp;2001&nbsp;&nbsp;<br />
<br />
18.不同时区的处理&nbsp;&nbsp;<br />
select&nbsp;to_char(&nbsp;NEW_TIME(&nbsp;sysdate,&nbsp;'GMT','EST'),&nbsp;'dd/mm/yyyy&nbsp;hh:mi:ss')&nbsp;,sysdate&nbsp;&nbsp;<br />
from&nbsp;dual;&nbsp;&nbsp;<br />
<br />
19.&nbsp;&nbsp;<br />
5秒钟一个间隔&nbsp;&nbsp;<br />
Select&nbsp;TO_DATE(FLOOR(TO_CHAR(sysdate,'SSSSS')/300)&nbsp;*&nbsp;300,'SSSSS')&nbsp;,TO_CHAR(sysdate,'SSSSS')&nbsp;&nbsp;<br />
from&nbsp;dual&nbsp;&nbsp;<br />
<br />
2002-11-1&nbsp;9:55:00&nbsp;35786&nbsp;&nbsp;<br />
SSSSS表示5位秒数&nbsp;&nbsp;<br />
<br />
20.&nbsp;&nbsp;<br />
一年的第几天&nbsp;&nbsp;<br />
select&nbsp;TO_CHAR(SYSDATE,'DDD'),sysdate&nbsp;from&nbsp;dual&nbsp;&nbsp;<br />
310&nbsp;2002-11-6&nbsp;10:03:51&nbsp;&nbsp;<br />
<br />
21.计算小时,分,秒,毫秒&nbsp;&nbsp;<br />
select&nbsp;&nbsp;<br />
Days,&nbsp;&nbsp;<br />
A,&nbsp;&nbsp;<br />
TRUNC(A*24)&nbsp;Hours,&nbsp;&nbsp;<br />
TRUNC(A*24*60&nbsp;-&nbsp;60*TRUNC(A*24))&nbsp;Minutes,&nbsp;&nbsp;<br />
TRUNC(A*24*60*60&nbsp;-&nbsp;60*TRUNC(A*24*60))&nbsp;Seconds,&nbsp;&nbsp;<br />
TRUNC(A*24*60*60*100&nbsp;-&nbsp;100*TRUNC(A*24*60*60))&nbsp;mSeconds&nbsp;&nbsp;<br />
from&nbsp;&nbsp;<br />
(&nbsp;&nbsp;<br />
select&nbsp;&nbsp;<br />
trunc(sysdate)&nbsp;Days,&nbsp;&nbsp;<br />
sysdate&nbsp;-&nbsp;trunc(sysdate)&nbsp;A&nbsp;&nbsp;<br />
from&nbsp;dual&nbsp;&nbsp;<br />
)&nbsp;&nbsp;<br />
<br />
<br />
<br />
select&nbsp;*&nbsp;from&nbsp;tabname&nbsp;&nbsp;<br />
order&nbsp;by&nbsp;decode(mode,'FIFO',1,-1)*to_char(rq,'yyyymmddhh24miss');&nbsp;&nbsp;<br />
<br />
//&nbsp;&nbsp;<br />
floor((date2-date1)&nbsp;/365)&nbsp;作为年&nbsp;&nbsp;<br />
floor((date2-date1,&nbsp;365)&nbsp;/30)&nbsp;作为月&nbsp;&nbsp;<br />
mod(mod(date2-date1,&nbsp;365),&nbsp;30)作为日.&nbsp;&nbsp;<br />
23.next_day函数&nbsp;&nbsp;<br />
next_day(sysdate,6)是从当前开始下一个星期五。后面的数字是从星期日开始算起。&nbsp;&nbsp;<br />
1&nbsp;2&nbsp;3&nbsp;4&nbsp;5&nbsp;6&nbsp;7&nbsp;&nbsp;<br />
日&nbsp;一&nbsp;二&nbsp;三&nbsp;四&nbsp;五&nbsp;六<br />
<br />
oracle中有很多关于日期的函数<br />
<br />
在oracle中有很多关于日期的函数，如：&nbsp;<br />
1、add_months()用于从一个日期值增加或减少一些月份&nbsp;<br />
date_value:=add_months(date_value,number_of_months)&nbsp;<br />
例：&nbsp;<br />
SQL&gt;&nbsp;select&nbsp;add_months(sysdate,12)&nbsp;"Next&nbsp;Year"&nbsp;from&nbsp;dual;&nbsp;<br />
<br />
Next&nbsp;Year&nbsp;<br />
----------&nbsp;<br />
13-11月-04&nbsp;<br />
<br />
SQL&gt;&nbsp;select&nbsp;add_months(sysdate,112)&nbsp;"Last&nbsp;Year"&nbsp;from&nbsp;dual;&nbsp;<br />
<br />
Last&nbsp;Year&nbsp;<br />
----------&nbsp;<br />
13-3月&nbsp;-13&nbsp;<br />
<br />
SQL&gt;&nbsp;<br />
<br />
2、current_date()返回当前会放时区中的当前日期&nbsp;<br />
date_value:=current_date&nbsp;<br />
SQL&gt;&nbsp;column&nbsp;sessiontimezone&nbsp;for&nbsp;a15&nbsp;<br />
SQL&gt;&nbsp;select&nbsp;sessiontimezone,current_date&nbsp;from&nbsp;dual;&nbsp;<br />
<br />
SESSIONTIMEZONE&nbsp;CURRENT_DA&nbsp;<br />
---------------&nbsp;----------&nbsp;<br />
+08:00&nbsp;13-11月-03&nbsp;<br />
<br />
SQL&gt;&nbsp;alter&nbsp;session&nbsp;set&nbsp;time_zone='-11:00'&nbsp;<br />
&nbsp;&nbsp;2&nbsp;/&nbsp;<br />
<br />
会话已更改。&nbsp;<br />
<br />
SQL&gt;&nbsp;select&nbsp;sessiontimezone,current_timestamp&nbsp;from&nbsp;dual;&nbsp;<br />
<br />
SESSIONTIMEZONE&nbsp;CURRENT_TIMESTAMP&nbsp;<br />
---------------&nbsp;------------------------------------&nbsp;<br />
-11:00&nbsp;12-11月-03&nbsp;04.59.13.668000&nbsp;下午&nbsp;-11:&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;00&nbsp;<br />
<br />
SQL&gt;&nbsp;<br />
<br />
3、current_timestamp()以timestamp&nbsp;with&nbsp;time&nbsp;zone数据类型返回当前会放时区中的当前日期&nbsp;<br />
timestamp_with_time_zone_value:=current_timestamp([timestamp_precision])&nbsp;<br />
SQL&gt;&nbsp;column&nbsp;sessiontimezone&nbsp;for&nbsp;a15&nbsp;<br />
SQL&gt;&nbsp;column&nbsp;current_timestamp&nbsp;format&nbsp;a36&nbsp;<br />
SQL&gt;&nbsp;select&nbsp;sessiontimezone,current_timestamp&nbsp;from&nbsp;dual;&nbsp;<br />
<br />
SESSIONTIMEZONE&nbsp;CURRENT_TIMESTAMP&nbsp;<br />
---------------&nbsp;------------------------------------&nbsp;<br />
+08:00&nbsp;13-11月-03&nbsp;11.56.28.160000&nbsp;上午&nbsp;+08:&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;00&nbsp;<br />
<br />
SQL&gt;&nbsp;alter&nbsp;session&nbsp;set&nbsp;time_zone='-11:00'&nbsp;<br />
&nbsp;&nbsp;2&nbsp;/&nbsp;<br />
<br />
会话已更改。&nbsp;<br />
<br />
SQL&gt;&nbsp;select&nbsp;sessiontimezone,current_timestamp&nbsp;from&nbsp;dual;&nbsp;<br />
<br />
SESSIONTIMEZONE&nbsp;CURRENT_TIMESTAMP&nbsp;<br />
---------------&nbsp;------------------------------------&nbsp;<br />
-11:00&nbsp;12-11月-03&nbsp;04.58.00.243000&nbsp;下午&nbsp;-11:&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;00&nbsp;<br />
<br />
SQL&gt;&nbsp;<br />
<br />
4、dbtimezone()返回时区&nbsp;<br />
varchar_value:=dbtimezone&nbsp;<br />
SQL&gt;&nbsp;select&nbsp;dbtimezone&nbsp;from&nbsp;dual;&nbsp;<br />
<br />
DBTIME&nbsp;<br />
------&nbsp;<br />
-07:00&nbsp;<br />
<br />
SQL&gt;&nbsp;<br />
<br />
5、extract()找出日期或间隔值的字段值&nbsp;<br />
date_value:=extract(date_field&nbsp;from&nbsp;[datetime_value|interval_value])&nbsp;<br />
SQL&gt;&nbsp;select&nbsp;extract(month&nbsp;from&nbsp;sysdate)&nbsp;"This&nbsp;Month"&nbsp;from&nbsp;dual;&nbsp;<br />
<br />
This&nbsp;Month&nbsp;<br />
----------&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;11&nbsp;<br />
<br />
SQL&gt;&nbsp;select&nbsp;extract(year&nbsp;from&nbsp;add_months(sysdate,36))&nbsp;"3&nbsp;Years&nbsp;Out"&nbsp;from&nbsp;dual;&nbsp;<br />
<br />
3&nbsp;Years&nbsp;Out&nbsp;<br />
-----------&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2006&nbsp;<br />
<br />
SQL&gt;&nbsp;<br />
<br />
6、last_day()返回包含了日期参数的月份的最后一天的日期&nbsp;<br />
date_value:=last_day(date_value)&nbsp;<br />
SQL&gt;&nbsp;select&nbsp;last_day(date'2000-02-01')&nbsp;"Leap&nbsp;Yr?"&nbsp;from&nbsp;dual;&nbsp;<br />
<br />
Leap&nbsp;Yr?&nbsp;<br />
----------&nbsp;<br />
29-2月&nbsp;-00&nbsp;<br />
<br />
SQL&gt;&nbsp;select&nbsp;last_day(sysdate)&nbsp;"Last&nbsp;day&nbsp;of&nbsp;this&nbsp;month"&nbsp;from&nbsp;dual;&nbsp;<br />
<br />
Last&nbsp;day&nbsp;o&nbsp;<br />
----------&nbsp;<br />
30-11月-03&nbsp;<br />
<br />
SQL&gt;&nbsp;<br />
<br />
7、localtimestamp()返回会话中的日期和时间&nbsp;<br />
timestamp_value:=localtimestamp&nbsp;<br />
SQL&gt;&nbsp;column&nbsp;localtimestamp&nbsp;format&nbsp;a28&nbsp;<br />
SQL&gt;&nbsp;select&nbsp;localtimestamp&nbsp;from&nbsp;dual;&nbsp;<br />
<br />
LOCALTIMESTAMP&nbsp;<br />
----------------------------&nbsp;<br />
13-11月-03&nbsp;12.09.15.433000&nbsp;<br />
下午&nbsp;<br />
<br />
SQL&gt;&nbsp;select&nbsp;localtimestamp,current_timestamp&nbsp;from&nbsp;dual;&nbsp;<br />
<br />
LOCALTIMESTAMP&nbsp;CURRENT_TIMESTAMP&nbsp;<br />
----------------------------&nbsp;------------------------------------&nbsp;<br />
13-11月-03&nbsp;12.09.31.006000&nbsp;13-11月-03&nbsp;12.09.31.006000&nbsp;下午&nbsp;+08:&nbsp;<br />
下午&nbsp;00&nbsp;<br />
<br />
SQL&gt;&nbsp;alter&nbsp;session&nbsp;set&nbsp;time_zone='-11:00';&nbsp;<br />
<br />
会话已更改。&nbsp;<br />
<br />
SQL&gt;&nbsp;select&nbsp;localtimestamp,to_char(sysdate,'DD-MM-YYYY&nbsp;HH:MI:SS&nbsp;AM')&nbsp;"SYSDATE"&nbsp;from&nbsp;dual;&nbsp;<br />
<br />
LOCALTIMESTAMP&nbsp;SYSDATE&nbsp;<br />
----------------------------&nbsp;------------------------&nbsp;<br />
12-11月-03&nbsp;05.11.31.259000&nbsp;13-11-2003&nbsp;12:11:31&nbsp;下午&nbsp;<br />
下午&nbsp;<br />
<br />
SQL&gt;&nbsp;<br />
<br />
8、months_between()判断两个日期之间的月份数量&nbsp;<br />
number_value:=months_between(date_value,date_value)&nbsp;<br />
SQL&gt;&nbsp;select&nbsp;months_between(sysdate,date'1971-05-18')&nbsp;from&nbsp;dual;&nbsp;<br />
<br />
MONTHS_BETWEEN(SYSDATE,DATE'1971-05-18')&nbsp;<br />
----------------------------------------&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;&nbsp;&nbsp;389.855143&nbsp;<br />
<br />
SQL&gt;&nbsp;select&nbsp;months_between(sysdate,date'2001-01-01')&nbsp;from&nbsp;dual;&nbsp;<br />
<br />
MONTHS_BETWEEN(SYSDATE,DATE'2001-01-01')&nbsp;<br />
----------------------------------------&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;&nbsp;&nbsp;34.4035409&nbsp;<br />
<br />
SQL&gt;&nbsp;<br />
<br />
9、next_day()给定一个日期值，返回由第二个参数指出的日子第一次出现在的日期值（应返回相应日子的名称字符串）<br />
<br />
?周相?日期函?<br />
<br />
1.查询某周的第一天<br />
select&nbsp;trunc(decode(ww,&nbsp;53,&nbsp;to_date(yy&nbsp;||&nbsp;'3112',&nbsp;'yyyyddmm'),&nbsp;to_date(yy&nbsp;||&nbsp;'-'&nbsp;||&nbsp;to_char(ww&nbsp;*&nbsp;7),&nbsp;'yyyy-ddd')),&nbsp;'d')&nbsp;last_day<br />
from&nbsp;(select&nbsp;substr('2004-32',&nbsp;1,&nbsp;4)&nbsp;yy,&nbsp;to_number(substr('2004-32',&nbsp;6))&nbsp;ww<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;dual)<br />
<br />
select&nbsp;trunc(to_date(substr('2003-01',1,5)||to_char((to_number(substr('2003-01',6)))*7),'yyyy-ddd'),'d')-6&nbsp;first_day&nbsp;from&nbsp;dual<br />
<br />
select&nbsp;min(v_date)&nbsp;from<br />
&nbsp;&nbsp;(select&nbsp;(to_date('200201','yyyymm')&nbsp;+&nbsp;rownum)&nbsp;v_date<br />
&nbsp;&nbsp;from&nbsp;all_tables<br />
&nbsp;&nbsp;where&nbsp;rownum&nbsp;&lt;&nbsp;370)<br />
where&nbsp;to_char(v_date,'yyyy-iw')&nbsp;=&nbsp;'2002-49'<br />
<br />
2.查询某周的最后一天<br />
select&nbsp;trunc(decode(ww,&nbsp;53,&nbsp;to_date(yy&nbsp;||&nbsp;'3112',&nbsp;'yyyyddmm'),&nbsp;to_date(yy&nbsp;||&nbsp;'-'&nbsp;||&nbsp;to_char(ww&nbsp;*&nbsp;7),&nbsp;'yyyy-ddd')),&nbsp;'d')&nbsp;-&nbsp;6&nbsp;first_day<br />
&nbsp;&nbsp;from&nbsp;(select&nbsp;substr('2004-33',&nbsp;1,&nbsp;4)&nbsp;yy,&nbsp;to_number(substr('2004-33',&nbsp;6))&nbsp;ww<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;dual)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
select&nbsp;trunc(to_date(substr('2003-01',1,5)||to_char((to_number(substr('2003-01',6)))*7),'yyyy-ddd'),'d')&nbsp;last_day&nbsp;from&nbsp;dual<br />
<br />
select&nbsp;max(v_date)&nbsp;from<br />
&nbsp;&nbsp;(select&nbsp;(to_date('200408','yyyymm')&nbsp;+&nbsp;rownum)&nbsp;v_date<br />
&nbsp;&nbsp;from&nbsp;all_tables<br />
&nbsp;&nbsp;where&nbsp;rownum&nbsp;&lt;&nbsp;370)<br />
where&nbsp;to_char(v_date,'yyyy-iw')&nbsp;=&nbsp;'2004-33'<br />
<br />
3.查询某周的日期<br />
select&nbsp;min_date,&nbsp;to_char(min_date,'day')&nbsp;day&nbsp;from<br />
(select&nbsp;to_date(substr('2004-33',1,4)||'001'+rownum-1,'yyyyddd')&nbsp;min_date&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;all_tables<br />
&nbsp;&nbsp;where&nbsp;rownum&nbsp;&lt;=&nbsp;decode(mod(to_number(substr('2004-33',1,4)),4),0,366,365)&nbsp;&nbsp;<br />
&nbsp;&nbsp;union<br />
<br />
&nbsp;&nbsp;select&nbsp;to_date(substr('2004-33',1,4)-1||<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decode(mod(to_number(substr('2004-33',1,4))-1,4),0,359,358)+rownum,'yyyyddd')&nbsp;min_date&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;all_tables&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where&nbsp;rownum&nbsp;&lt;=&nbsp;7<br />
&nbsp;&nbsp;union<br />
<br />
&nbsp;&nbsp;select&nbsp;to_date(substr('2004-33',1,4)+1||'001'+rownum-1,'yyyyddd')&nbsp;min_date&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;all_tables&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where&nbsp;rownum&nbsp;&lt;=&nbsp;7&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 />
where&nbsp;to_char(min_date,'yyyy-iw')&nbsp;='2004-33' </p>
<img src ="http://www.blogjava.net/conans/aggbug/210931.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-06-26 19:53 <a href="http://www.blogjava.net/conans/articles/210931.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>3 款 SQL INJECTION 攻击检测工具</title><link>http://www.blogjava.net/conans/articles/210663.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Wed, 25 Jun 2008 11:48:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/210663.html</guid><description><![CDATA[写道 "随着 <a href="http://blogs.zdnet.com/security/?p=1059">SQL INJECTION</a> 攻击的<a href="http://blogs.zdnet.com/security/?p=1122">明显增多</a>，<a href="http://blogs.zdnet.com/security/?p=1336">微软近日发布了三个免费工具</a>，帮助网站管理员和检测存在的风险并对可能的攻击进行拦截。
<div class="full"><a href="http://www.communities.hp.com/securitysoftware/blogs/spilabs/archive/2008/06/23/finding-sql-injection-with-scrawlr.aspx"><strong>Scrawlr</strong> </a><br />
<br />
下载地址：<a href="https://download.spidynamics.com/Products/scrawlr/">https://download.spidynamics.com/Products/scrawlr/</a> <br />
<br />
这个微软和 HP合作开发的工具，会在网站中爬行，对所有网页的查询字符串进行分析并发现其中的 SQL INJECTION 风险。Scrawlr 使用了部分 HP WebInspect 相同的技术，但只检测 SQL INJECTION 风险。Scrawlr 从一个起始 URL 入口，爬遍整个网站，并对站点中所有网页进行分析以找到可能存在的漏洞。 <br />
<br />
<br />
<a href="http://support.microsoft.com/kb/954476"><strong>Microsoft Source Code Analyzer for SQL Injection</strong> </a><br />
<br />
下载地址：<a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=58A7C46E-A599-4FCB-9AB4-A4334146B6BA&amp;displaylang=en">http://www.microsoft.com/downloads/details.aspx?FamilyId=58A7C46E-A599-4FCB-9AB4-A4334146B6BA&amp;displaylang=en</a> <br />
<br />
这款被称作 MSCASI 的工具可以检测 ASP 代码并发现其中的 SQL INJECTION 漏洞（ASP 代码以 SQL INJECTION 漏洞著称），你需要向 MSCASI 提供原始代码，MSCASI 会帮你找到存在风险的代码位置。 <br />
<br />
<strong><br />
<a href="http://learn.iis.net/page.aspx/473/using-urlscan">URLScan 3.0</a> </strong><br />
<br />
下载地址： <a href="http://www.iis.net/downloads/default.aspx?tabid=34&amp;g=6&amp;i=1697">http://www.iis.net/downloads/default.aspx?tabid=34&amp;g=6&amp;i=1697</a> <br />
<br />
该工具会让 IIS 限制某些类型的 HTTP 请求，通过对特定 HTTP 请求进行限制，可以防止某些有害的请求在服务器端执行。UrlScan 通过一系列关键词发现恶意请求，并阻止恶意请求的执行。 </div>
 <img src ="http://www.blogjava.net/conans/aggbug/210663.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-06-25 19:48 <a href="http://www.blogjava.net/conans/articles/210663.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle开发专题之：级联查询(Hierarchical Queries) 进阶应用：伪列Level</title><link>http://www.blogjava.net/conans/articles/209876.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Sun, 22 Jun 2008 10:49:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/209876.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 目录：1.使用伪列Level显示表中节点的层次关系2.统计表中节点的层数3.统计表中各个层次的节点数量4.查找表中各个层次的节点信息5.在Start with中使用子查询6.判断节点和节点之间是否具有层次关系7.删除级联表中的子树一、使用伪列Level显示表中节点的层次关系：Oracle9i对级联查询的支持不仅在于提供了像Start with.....&nbsp;&nbsp;<a href='http://www.blogjava.net/conans/articles/209876.html'>阅读全文</a><img src ="http://www.blogjava.net/conans/aggbug/209876.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-06-22 18:49 <a href="http://www.blogjava.net/conans/articles/209876.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>五种提高 SQL 性能的方法</title><link>http://www.blogjava.net/conans/articles/209592.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Fri, 20 Jun 2008 15:06:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/209592.html</guid><description><![CDATA[<div class="blog_content"><font face="Verdana" size="2">本文节选自MSDN的文章《五种提高 SQL 性能的方法》，提出如何提高基于SQL Server应用程序的运行效率，非常值得推荐。对一些Traffic很高的应用系统而言，如何提高和改进SQL指令，是非常重要的，也是一个很好的突破点。<br />
*文章主要包括如下一些内容（如感兴趣，请直接访问下面的URL阅读完整的中英文文档）：<br />
<br />
</font><font size="2"><font face="Verdana"><strong>1,&nbsp;从 INSERT 返回 IDENTITY&nbsp; <br />
</strong>SELECT @@IDENTITY<br />
<br />
</font></font><font size="2"><font face="Verdana"><strong>2, 内嵌视图与临时表&nbsp; <br />
</strong>临时表&nbsp;－ 在 tempdb 中的临时表会导致查询进行大量 I/O 操作和磁盘访问，临时表会消耗大量资源。<br />
内嵌视图 －使用内嵌视图取代临时表。内嵌视图只是一个可以联接到 FROM 子句中的查询。如果只需要将数据联接到其他查询，则可以试试使用内嵌视图，以节省资源。<br />
<br />
<strong>3, 避免 LEFT JOIN 和 NULL</strong>&nbsp; <br />
LEFT JOIN 消耗的资源非常之多，因为它们包含与 NULL（不存在）数据匹配的数据。在某些情况下，这是不可避免的，但是代价可能非常高。LEFT JOIN 比 INNER JOIN 消耗资源更多，所以如果您可以重新编写查询以使得该查询不使用任何 LEFT JOIN，则会得到非常可观的回报。<br />
<br />
加快使用 LEFT JOIN 的查询速度的一项技术涉及创建一个 <font color="#ff0000">TABLE 数据类型</font>， 插入第一个表（LEFT JOIN 左侧的表）中的所有行，然后使用第二个表中的值更新 TABLE 数据类型。此技术是一个两步的过程，但与标准的 LEFT JOIN 相比，可以节省大量时间。一个很好的规则是尝试各种不同的技术并记录每种技术所需的时间，直到获得用于您的应用程序的执行性能最佳的查询。<br />
DECLARE @tblMonths <font color="#0000ff">TABLE </font>(sMonth VARCHAR(7))<br />
<br />
<strong>4, 灵活使用笛卡尔乘积</strong>&nbsp; <br />
对 于此技巧，我将进行非常详细的介绍，并提倡在某些情况下使用笛卡尔乘积。出于某些原因，笛卡尔乘积 (CROSS JOIN) 遭到了很多谴责，开发人员通常会被警告根本就不要使用它们。在许多情况下，它们消耗的资源太多，从而无法高效使用。但是像 SQL 中的任何工具一样，如果正确使用，它们也会很有价值。<br />
<br />
其中一段示例代码，值得效仿：<br />
-- 笛卡尔乘积则可以返回所有月份的所有客户。笛卡尔乘积基本上是将第一个表与第二个表相乘，生成一个行集合，其中包含第一个表中的行数与第二个表中的行数相 乘的结果。因此，笛卡尔乘积会向表 @tblFinal 返回 12（所有月份）*81（所有客户）=972 行。最后的步骤是使用此日期范围内每个客户的月销售额总计更新 @tblFinal 表，以及选择最终的行集。<br />
<br />
</font></font><font face="Verdana" color="#000080" size="2">DECLARE @tblMonths TABLE (sMonth VARCHAR(7))<br />
DECLARE @tblCustomers TABLE (&nbsp;&nbsp;&nbsp; CustomerID CHAR(10),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CompanyName VARCHAR(50),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ContactName VARCHAR(50))<br />
DECLARE @tblFinal TABLE (&nbsp;&nbsp;&nbsp; sMonth VARCHAR(7), <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CustomerID CHAR(10),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CompanyName VARCHAR(50),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ContactName VARCHAR(50),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mSales MONEY)</font>
<p><br />
<font face="Verdana" color="#000080" size="2">DECLARE @dtStartDate DATETIME, <br />
&nbsp;&nbsp;&nbsp; @dtEndDate DATETIME,<br />
&nbsp;&nbsp;&nbsp; @dtDate DATETIME,<br />
&nbsp;&nbsp;&nbsp; @i INTEGER</font></p>
<p><font face="Verdana" color="#000080" size="2">SET @dtEndDate = '5/5/1997'</font></p>
<p><font face="Verdana" color="#000080" size="2">SET @dtEndDate = DATEADD(DD, -1, CAST(CAST((MONTH(@dtEndDate) + 1) AS&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; VARCHAR(2)) + '/01/' + CAST(YEAR(@dtEndDate) AS VARCHAR(4)) + ' 23:59:59' AS DATETIME))<br />
SET @dtStartDate = DATEADD(MM, -1 * 12, @dtEndDate)</font></p>
<p><br />
<font face="Verdana" color="#000080" size="2">-- Get all months into the first table<br />
SET @i = 0<br />
WHILE (@i &lt; 12)<br />
BEGIN<br />
&nbsp;&nbsp;&nbsp; SET @dtDate = DATEADD(mm, -1 * @i, @dtEndDate)<br />
&nbsp;&nbsp;&nbsp; INSERT INTO @tblMonths SELECT CAST(YEAR(@dtDate) AS VARCHAR(4)) + '-' +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CASE <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHEN MONTH(@dtDate) &lt; 10 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; THEN '0' + CAST(MONTH(@dtDate) AS VARCHAR(2))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ELSE CAST(MONTH(@dtDate) AS VARCHAR(2))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END AS sMonth<br />
&nbsp;&nbsp;&nbsp; SET @i = @i + 1<br />
END</font></p>
<p><font face="Verdana" color="#000080" size="2">-- Get all clients who had sales during that period into the "y" table<br />
INSERT INTO @tblCustomers<br />
&nbsp;&nbsp;&nbsp; SELECT&nbsp;&nbsp;&nbsp; DISTINCT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.CustomerID,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.CompanyName,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.ContactName<br />
&nbsp;&nbsp;&nbsp; FROM Customers c<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INNER JOIN Orders o ON c.CustomerID = o.CustomerID<br />
&nbsp;&nbsp;&nbsp; WHERE&nbsp;&nbsp;&nbsp; o.OrderDate BETWEEN @dtStartDate AND @dtEndDate</font></p>
<p><font face="Verdana" color="#000080" size="2">INSERT INTO @tblFinal<br />
SELECT&nbsp;&nbsp;&nbsp; m.sMonth,<br />
&nbsp;&nbsp;&nbsp; c.CustomerID,<br />
&nbsp;&nbsp;&nbsp; c.CompanyName,<br />
&nbsp;&nbsp;&nbsp; c.ContactName,<br />
&nbsp;&nbsp;&nbsp; 0<br />
FROM @tblMonths m CROSS JOIN @tblCustomers c</font></p>
<p><font face="Verdana" color="#000080" size="2">UPDATE @tblFinal&nbsp; SET <br />
&nbsp;&nbsp;&nbsp; mSales = mydata.mSales<br />
FROM @tblFinal f INNER JOIN <br />
&nbsp;&nbsp;&nbsp; (<br />
&nbsp;&nbsp;&nbsp; SELECT&nbsp;&nbsp;&nbsp; c.CustomerID,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CAST(YEAR(o.OrderDate) AS VARCHAR(4)) + '-' +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CASE WHEN MONTH(o.OrderDate) &lt; 10 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; THEN '0' + CAST(MONTH(o.OrderDate) AS VARCHAR(2))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ELSE CAST(MONTH(o.OrderDate) AS VARCHAR(2))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END AS sMonth,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM(od.Quantity * od.UnitPrice) AS mSales<br />
&nbsp;&nbsp;&nbsp; FROM Customers c<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INNER JOIN Orders o ON c.CustomerID = o.CustomerID<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INNER JOIN [Order Details] od ON o.OrderID = od.OrderID<br />
&nbsp;&nbsp;&nbsp; WHERE&nbsp;&nbsp;&nbsp; o.OrderDate BETWEEN @dtStartDate AND @dtEndDate<br />
&nbsp;&nbsp;&nbsp; GROUP BY<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.CustomerID,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CAST(YEAR(o.OrderDate) AS VARCHAR(4)) + '-' +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CASE WHEN MONTH(o.OrderDate) &lt; 10 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; THEN '0' + CAST(MONTH(o.OrderDate) AS VARCHAR(2))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ELSE CAST(MONTH(o.OrderDate) AS VARCHAR(2))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END<br />
&nbsp;&nbsp;&nbsp; ) mydata on f.CustomerID = mydata.CustomerID AND f.sMonth = <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mydata.sMonth </font></p>
<p><br />
<font size="2"><font face="Verdana"><font color="#000080">SELECT&nbsp;&nbsp;&nbsp; f.sMonth,<br />
&nbsp;&nbsp;&nbsp; f.CustomerID,<br />
&nbsp;&nbsp;&nbsp; f.CompanyName,<br />
&nbsp;&nbsp;&nbsp; f.ContactName,<br />
&nbsp;&nbsp;&nbsp; f.mSales<br />
FROM @tblFinal f<br />
ORDER BY<br />
&nbsp;&nbsp;&nbsp; f.CompanyName,<br />
&nbsp;&nbsp;&nbsp; f.sMonth</font><br />
<br />
<br />
<strong>5,&nbsp;拾遗补零</strong>&nbsp; <br />
这 里介绍其他一些可帮助提高 SQL 查询效率的常用技术。假设您将按区域对所有销售人员进行分组并将他们的销售额进行小计，但是您只想要那些数据库中标记为处于活动状态的销售人员。您可以按 区域对销售人员分组，并使用 HAVING 子句消除那些未处于活动状态的销售人员，也可以在 WHERE 子句中执行此操作。在 WHERE 子句中执行此操作会减少需要分组的行数，所以比在 HAVING 子句中执行此操作效率更高。HAVING 子句中基于行的条件的筛选会强制查询对那些在 WHERE 子句中会被去除的数据进行分组。</font></font></p>
<p><font face="Verdana" size="2">另 一个提高效率的技巧是使用 DISTINCT 关键字查找数据行的单独报表，来代替使用 GROUP BY 子句。在这种情况下，使用 DISTINCT 关键字的 SQL 效率更高。请在需要计算聚合函数（SUM、COUNT、MAX 等）的情况下再使用 GROUP BY。另外，如果您的查询总是自己返回一个唯一的行，则不要使用 DISTINCT 关键字。在这种情况下，DISTINCT 关键字只会增加系统开销。</font> <br />
</p>
</div>
<img src ="http://www.blogjava.net/conans/aggbug/209592.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-06-20 23:06 <a href="http://www.blogjava.net/conans/articles/209592.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ORACLE SQL 优化</title><link>http://www.blogjava.net/conans/articles/209590.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Fri, 20 Jun 2008 15:05:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/209590.html</guid><description><![CDATA[<p>一、&nbsp;先介绍一下<span class="hilite1">oracle</span>的SGA：数据库的系统全局区，SGA主要由三部分构成：共享池、数据缓冲区、日志缓冲区。</p>
<p>1、&nbsp;共享池又由两部分构成：共享SQL区和数据字典缓冲区。共享SQL区专门存放用户SQL命令，<span class="hilite1">oracle</span>使用最近最少使用等优先级算法来更新覆盖；数据字典缓冲区（library cache）存放数据库运行的动态信息。数据库运行一段时间后，DBA需要查看这些内存区域的命中率以从数据库角度对数据库性能调优。通过执行下述语句查看：<br />
select (sum(pins - reloads)) / sum(pins) "Lib Cache"&nbsp; from&nbsp; v$librarycache;<br />
--查看共享SQL区的重用率，最好在90％以上，否则需要增加共享池的大小。<br />
select (sum(gets - getmisses - usage - fix<span id="S__699_ADDIV_8" onmouseover="S__699.SHOWFLOW('ED','8',event);this.style.textDecoration='none';" style="cursor: pointer; color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="S__699.SHOWFLOW('ED','8',event);" onmouseout="S__699.hidden('8');;this.style.textDecoration='underline';" oncontentextmenu="return false">ED</span>)) / sum(gets) "Row Cache"&nbsp; from v$rowcache;<br />
--查看数据字典缓冲区的命中率，最好在90％以上，否则需要增加共享池的大小。<br />
2、&nbsp; 数据缓冲区：存放sql运行结果抓取到的data block；<br />
&nbsp;SELECT name, value&nbsp;&nbsp; FROM v$sysstat&nbsp;&nbsp; WHERE name IN ('db block gets', 'consistent gets','physical reads');<br />
-- 查看数据库数据缓冲区的使用情况。查询出来的结果可以计算出来数据缓冲区的使用命中率＝1 - ( physical reads / (db block gets + consistent gets) )。命中率应该在90％以上，否则需要增加数据缓冲区的大小。<br />
3、&nbsp;日志缓冲区：存放数据库运行生成的日志。<br />
select name,value from v$sysstat where name in ('redo entries','redo log space requests');<br />
--查看日志缓冲区的使用情况。查询出的结果可以计算出日志缓冲区的申请失败率：申请失败率＝requests/entries，申请失败率应该接近于0，否则说明日志缓冲区开设太小，需要增加<span class="hilite1">ORACLE</span>数据库的日志缓冲区。<br />
二．Sql语句的执行步骤：<br />
　 了解sql的执行步骤有利于更好的优化它们，每条sql语句执行时都要经历以下几步：<br />
1.&nbsp; Create&nbsp; cursor ； <br />
2.&nbsp; Parse, if it is not already in the shared pool.；<br />
3.&nbsp; Any query in the statement is processed. <br />
4.&nbsp; Bind Variables&nbsp; <br />
5.&nbsp; Execute. <br />
6.&nbsp; If possible, the statement is parallelized. <br />
7.&nbsp; Rows to be returned are fetched. </p>
<p>其中，Parse—是最有优化潜力的阶段。<br />
Cursor创建后，<span class="hilite1">oracle</span>将在share pool中寻找是否该sql语句已经存在，若已经存在且已经被parsed，则不需要再执行parse，直接到下一步。若未在share pool中找到，则parse步一般需要执行下面步骤：<br />
1.&nbsp; The statement is validated. <br />
2.&nbsp; The data is validated. <br />
3.&nbsp; Locks are allocated.<br />
4.&nbsp; Privileges are verified. <br />
5.&nbsp; The execution plan is determined. <br />
6.&nbsp; The statement is loaded into the shared SQL area. <br />
--parse有这么多步骤，所以能利用sharepool中现成的parse结果很重要。</p>
<p>三. 如何提高share pool中Sql共享率？<br />
要实现sql共享，跳过parse步骤，有如下基本要求条件：<br />
1. sql文本完全相同：<br />
--uppercase&nbsp; and&nbsp; lowercase<br />
--white space (spaces, tabs, carriage returns)<br />
--comments<br />
2.参考对象相同:<br />
&nbsp; --Referenced schema&#8217;s objects must be the same objects<br />
3. 绑定变量相同<br />
--Bind variables must match the same name and data type.（所以对于格式相同、<span id="S__699_ADDIV_1" onmouseover="S__699.SHOWFLOW('具体','1',event);this.style.textDecoration='none';" style="cursor: pointer; color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="S__699.SHOWFLOW('具体','1',event);" onmouseout="S__699.hidden('1');;this.style.textDecoration='underline';" oncontentextmenu="return false">具体</span>条件不同的sql，建议经常使用变量来代替常量，以尽量使用重复sql代码，避开parse阶段，提高执行速度）<br />
--tip：<br />
--尽量使用存储过程；尽量使用变量代替常量，可以提高share pool共享率，跳过parse阶段，提高效率。<br />
四．什么是好的sql语句？<br />
总结出以下特征：<br />
&#8226; 尽量使用 PL/SQL提高性能： PL/SQL可以将sql语句块一次送给数据库服务器处理，不用PL/SQL只能一句一句送。 <br />
&#8226;&nbsp; 尽量使用stored procedure：降低<span class="hilite1">oracle</span>通过<span id="S__699_ADDIV_6" onmouseover="S__699.SHOWFLOW('网络','6',event);this.style.textDecoration='none';" style="cursor: pointer; color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="S__699.SHOWFLOW('网络','6',event);" onmouseout="S__699.hidden('6');;this.style.textDecoration='underline';" oncontentextmenu="return false">网络</span>传输的数据量，并能提高共享sql区域的重用率。<br />
&#8226; 尽量使用packages： Packages在第一次调用时能将整个包 load进内存，对提高性能有帮助。 <br />
&#8226;&nbsp; 尽量使用cached sequences 来生成primary key ：提高主键生成速度和使用性能。 <br />
&#8226;&nbsp; 很好地利用空间：如用VARCHAR2 数据类型代替 CHAR等<br />
&#8226;&nbsp; 只在非常必要时才使用hint：仅在对sql的执行计划非常肯定地要使用hint时才使用。 </p>
<p>五．<span class="hilite2">Sql优化工具</span>的介绍：<br />
sqlexpert；toad；explain-table；PL/SQL；OEM等<br />
掌握一种，熟练使用即可。<br />
我的习惯：看执行计划用sqlplus 的autotrace，优化用sql expert。</p>
<p>--Autotrace使用方法：<br />
1.&nbsp;DBA在db中创建plustrace 角色：运行@?/sqlplus/admin/plustrce.sql<br />
2.&nbsp;DBA给用户赋予角色：grant plustrace to username;<br />
3.&nbsp; 用户创建自己的plan_table：运行@?/rdbms/admin/utlxplan.sql。--以上是第一次使用时需要进行的必要操作。<br />
4.&nbsp; 用户sqlplus连接数据库，对会话进行如下设置：<br />
Set&nbsp; autotrace&nbsp; -----off/on/trace[only]------explain/statistics，<br />
然后录入sql语句回车即可查看执行计划—推荐；<br />
或者用如下命令行：<br />
Explain plan set statement_id=&#8217;myplan1&#8217;&nbsp;&nbsp; for&nbsp;&nbsp; Your sql-statement;<br />
然后查看用户自己的plan_table</p>
<p>--演示Sql-expert的使用，连接到指定数据库，输入sql，显示执行计划或者sql优化结果，图形界面如下：<br />
&nbsp;</p>
<p>--ps：但我在使用中发现sql-expert的执行计划有时候显示得并不准确，所以建议以sqlplus中的为准。其sql优化倒很值得参考，有多种结果，用户可以自己测试和选择。</p>
<p>六．SQL优化技巧<br />
在这方面，长期搞数据库应用开发的人应该更有经验，我这里大概总结一下自己遇到过的和搜集到的一些sql优化经验，跟大家共同学习。<br />
SQL语言是一种灵活的语言，相同的功能可以使用不同的语句来实现，但是语句的执行效率可能会很不相同的，生产系统里经常跑的sql语句更要注意执行效率，否则会占用大量系统<span id="S__699_ADDIV_5" onmouseover="S__699.SHOWFLOW('资源','5',event);this.style.textDecoration='none';" style="cursor: pointer; color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="S__699.SHOWFLOW('资源','5',event);" onmouseout="S__699.hidden('5');;this.style.textDecoration='underline';" oncontentextmenu="return false">资源</span>，带慢整个系统。SQL优化的实质就是在结果正确的前提下，用优化器可以识别的语句，充份利用索引，执行过程中访问尽量少的数据块，减少表扫描的I/O次数，尽量<span id="S__699_ADDIV_3" onmouseover="S__699.SHOWFLOW('避免','3',event);this.style.textDecoration='none';" style="cursor: pointer; color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="S__699.SHOWFLOW('避免','3',event);" onmouseout="S__699.hidden('3');;this.style.textDecoration='underline';" oncontentextmenu="return false">避免</span>全表扫描和其他额外开销。<br />
Sql优化：<br />
1、&nbsp;先介绍一下<span class="hilite1">oracle</span>数据库常用的两种优化器：RBO（rule-based-optimizer）和CBO(cost-based-optimizer)。目前更多地采用CBO(cost-based-optimizer)基于开销的优化器。在CBO方式下，<span class="hilite1">Oracle</span>会根据表及索引的状态信息来选择计划；在RBO方式下，<span class="hilite1">Oracle</span>会根据自己内部设置的一些规则来决定选择计划，例如<span class="hilite1">oracle</span>会根据以下优先级来选择执行计划（越靠前，rank越低，越快）：</p>
<p><br />
&nbsp;RANK&nbsp;Access path<br />
1&nbsp;ROWID等于常量<br />
2&nbsp;唯一键值或主键的聚簇连接*<br />
3&nbsp;唯一键值或主键的哈希聚簇连接*&nbsp; <br />
4&nbsp;整个复合索引等于常量<br />
5&nbsp;唯一索引列等于常量<br />
6&nbsp;完全聚簇键等于同一个聚簇上的另一个表对应的聚簇键*<br />
7&nbsp;哈希聚簇键等于常数*<br />
8&nbsp;完全聚簇键等于常数*<br />
9&nbsp;整个非唯一组合索引等于常量<br />
10&nbsp;非唯一索引连结<br />
11&nbsp;整个组合索引等于小范围的值<br />
12&nbsp;组合索引的大部分前面的列等于常量<br />
13&nbsp;索引列取值存在上限和下限或者索引列LIKE "ABC%"（范围限制）<br />
14&nbsp;非唯一索引列取值存在上限和下限或者索引列LIKE "ABC%"（范围限制）<br />
15&nbsp;唯一索引列或是常量（范围无限制）<br />
16&nbsp;非唯一索引列或是常（范围无限制）<br />
17&nbsp;非索引列的等值连接(sort/merge join)<br />
18&nbsp;单一索引列的最大或最小值<br />
19&nbsp;ORDER BY整个索引<br />
20&nbsp;全表扫描</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>2、&nbsp;创建索引：创建索引一般有以下两个目的：维护被索引列的唯一性和提供快速访问表中数据的策略。<br />
索引创建原则：<br />
--在select操作占大部分的表上创建索引；<br />
--在where子句中出现最频繁的列上创建索引；<br />
--在选择性高的列上创建索引（补充索引选择性，最高是1，eg：primary key）<br />
--复合索引的主列应该是最有选择性的和where限定条件最常用的列，并以此类推第二列&#8230;&#8230;。<br />
--小于5M的表，最好不要使用索引来查询，表越小，越适合用全表扫描。</p>
<p>索引使用原则：<br />
--查询结果是所有数据行的5%以下时，使用index查询<span id="S__699_ADDIV_4" onmouseover="S__699.SHOWFLOW('效果','4',event);this.style.textDecoration='none';" style="cursor: pointer; color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="S__699.SHOWFLOW('效果','4',event);" onmouseout="S__699.hidden('4');;this.style.textDecoration='underline';" oncontentextmenu="return false">效果</span>最好；<br />
--where条件中经常用到表的多列时，使用复合索引效果会好于几个单列索引。因为当sql 语句所查询的列，全部都出现在复合索引中时，此时由于 <span class="hilite1">Oracle</span> 只需要查询索引块即可获得所有数据，当然比使用多个单列索引要快得多；<br />
--索引利于select，但对经常insert，delte尤其update的表，会降低效率。</p>
<p>eg：试比较下面两条SQL语句(emp 表的deptno列上建有ununique index)：<br />
语句A：SELECT dname, deptno FROM dept WHERE deptno NOT IN&nbsp; <br />
(SELECT deptno FROM emp);<br />
语句B：SELECT dname, deptno FROM dept WHERE NOT EXISTS<br />
(SELECT deptno&nbsp; FROM emp WHERE dept.deptno = emp.deptno);<br />
这两条查询语句实现的结果是相同的，但是执行语句A的时候，<span class="hilite1">ORACLE</span>会对整个emp表进行扫描，没有使用建立在emp表上的deptno索引，执行语句B的时候，由于在子查询中使用了联合查询，<span class="hilite1">ORACLE</span>只是对emp表进行的部分数据扫描，并利用了deptno列的索引，所以语句B的效率要比语句A的效率高。我的测试结果：(当emp表有37M时的测试)：<br />
SQL&gt; SELECT dname, deptno FROM dept WHERE deptno NOT IN<br />
(SELECT deptno FROM emp);<br />
DNAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEPTNO<br />
-------------- ----------<br />
OPERATIONS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 40</p>
<p>Elapsed: 00:00:01.08<br />
Execution Plan<br />
----------------------------------------------------------<br />
&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT STATEMENT Optimizer=CHOOSE<br />
&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; FILTER<br />
&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'DEPT'<br />
&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'EMP'<br />
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; 31&nbsp; db block gets<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4635&nbsp; consistent gets<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; physical reads<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; redo size<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 541&nbsp; bytes sent via SQL*Net to client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 550&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 />
1&nbsp;rows processed<br />
SQL&gt; SELECT dname, deptno FROM dept WHERE NOT EXISTS<br />
(SELECT deptno&nbsp; FROM emp WHERE dept.deptno = emp.deptno);<br />
DNAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEPTNO<br />
-------------- ----------<br />
OPERATIONS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 40</p>
<p>Elapsed: 00:00:00.30</p>
<p>Execution Plan<br />
----------------------------------------------------------<br />
&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT STATEMENT Optimizer=CHOOSE<br />
&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; FILTER<br />
&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'DEPT'<br />
&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'IND_EMP_DEPTNO' (NON-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; 12&nbsp; db block gets<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 19&nbsp; consistent gets<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; physical reads<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 144&nbsp; redo size<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 541&nbsp; bytes sent via SQL*Net to client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 550&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; 1&nbsp; rows processed</p>
<p>3．&nbsp;索引常用类型，按存储方式分为：B-tree ，bitmap，reverse key index<br />
&nbsp;B-ree：最常用的一种，又可以分为primary, unique,nonunique，composite,cluster等<br />
&nbsp;bitmap适用情况：<br />
--该列重复值很高（eg：性别列、分数列ABC级等），最好该列有not null的限制；<br />
--bitmap对大表效果好，且很节省索引空间；<br />
--适合并发度低的表，因为其数据更新时会锁住整个bitmap block；<br />
--使用bitmap索引时，需要加hint强制使用（应该是<span class="hilite1">oracle</span>一个bug）<br />
&nbsp;Reverse索引：适用于序列生成的数字列，会将index key列值倒序存放，尤其表的更改并发度又比较高时，更适合用reverse索引，这样可以将相似值的行分散到索引的多个叶子节点，降低冲突，提高性能。<br />
根据应用需求在适当列建合适的索引。</p>
<p>4、　<span class="hilite1">Oracle</span> 要使用一个索引，有一些基本要求条件：<br />
----where 子句中的这个字段，必须是复合索引的第一个字段；<br />
eg：一个索引是按 f1, f2, f3的次序建立的，若where 子句是 f2 = : var2, 则因为 f2 不是索引的第1个字段，无法使用该索引。<br />
---- where 子句中的这个字段，不应该参与任何形式的计算：任何对列的操作都将导致表扫描，它包括数据库函数、计算表达式等等，查询时要尽可能将操作移至等号右边。<br />
----应尽量熟悉各种操作符对 <span class="hilite1">Oracle</span> 是否使用索引的影响：以下这些操作会显式（explicitly）地阻止 <span class="hilite1">Oracle</span> 使用索引： is null ;&nbsp; is not null ;&nbsp; not in;&nbsp; !=;&nbsp; like ; numeric_col+0;date_col+0; char_col||&#8217; &#8217;;&nbsp; to_char;&nbsp; to_number，to_date 等。<br />
Eg：<br />
Select jobid from mytabs where isReq='0' and to_date (updatedate) &gt;= to_Date ( '2001-7-18', 'YYYY-MM-DD')；--updatedate列的索引也不会生效。 </p>
<p>5、索引不是越多越好。特别是大量从来或者几乎不用的索引，对系统只有损害。OLTP系统每表超过5个索引即会降低性能，&nbsp; 而且在一个sql 中， <span class="hilite1">Oracle</span> 从不能使用超过 5个索引。 <br />
索引对select有正面效果，但对insert，delete尤其是update有负面效果，会影响速度，索引越多，影响越大。所以<span class="hilite1">oracle</span>工具sqlldr倒入数据时，好的做法是先建好表结构，再倒入数据，最后才建索引，以提高数据倒入的速度，<span class="hilite1">oracle</span>工具import默认就是先倒入数据，然后才建索引。所以建索引时要充分考虑该表的主要应用。<br />
Tips： 经常做insert，delete尤其是update的表最好定期exp/imp表数据，整理数据，降低碎片（缺点：要停应用，以保持数据一致性，不实 用）；有索引的最好定期rebuild索引（rebuild期间只允许表的select操作，可在数据库较空闲时间提交），以降低索引碎片，提高效率；</p>
<p>6、何时适合使用全表扫描？<br />
&nbsp; --小表，仅有几个data block的表（5M以下）；<br />
--对数据行的选择率高于20%时可考虑用全表扫描（如有1000行记录，一次选出200行以上）<br />
&nbsp; <br />
7．选择联合查询的联合次序。联合查询分为3种：merge join,nested loop,hash join，这里讲的是nested&nbsp; loop的联合情况（后面实际案例1的优化就属于此类）；<br />
考虑下面的例子：<br />
SELECT stuff&nbsp; FROM taba a, tabb b, tabc c <br />
WHERE a.acol between :alow and :ahigh <br />
AND b.bcol between :blow and :bhigh <br />
AND c.ccol between :clow and :chigh <br />
AND a.key1 = b.key1 <br />
AMD a.key2 = c.key2;<br />
这 个SQL例子中，程序员首先需要选择要查询的主表，因为主表要进行整个表数据的扫描，所以主表应该数据量最小，所以例子中表A的acol列的范围应该比表 B和表C相应列的范围小。内外表的选择可由公式：外层表中的匹配行数*内层表中每一次查找的次数确定，乘积最小为最佳方案。</p>
<p>8、用UNION ALL代替UNION：<br />
UNION是最常用的集操作，使多个记录集联结成为单个集，对返回的数据行有唯一性要求，所以<span class="hilite1">oracle</span>就需要进行SORT UNIQUE操作（与使用distinct时操作类似），如果结果集又比较大，则操作会比较慢；<br />
UNION ALL操作不排除重复记录行，所以会快很多，如果数据本身重复行存在可能性较小时，用union all会比用union效率高很多！</p>
<p>9．&nbsp;避免在SQL里使用PL/SQL功能调用：<br />
PL/SQL块有利于提高重复使用代码，但是如果混合在SQL语句中，反而会降低效率。Eg：<br />
US$()为一货币转换的PL/SQL<br />
Sql:&nbsp; select name,US$(amount,currency) from salary where US$(amount,currency)&gt;1000;<br />
该sql效率低下，因为混合PL/SQL和sql时，<span class="hilite1">oracle</span>使用的机制不同，执行时，<span class="hilite1">oracle</span>将调用分成两个组件：用带有赋值变量的SQL语句代替功能调用，和对功能调用的PL/SQL块：<br />
即：<br />
select name,:a1 from salary where :a2&gt;1000;<br />
和<br />
begin<br />
:a1:=US$(:amount,:currency);<br />
end;<br />
对salary表里的每一行执行PL/SQL两次，效率大大降低。</p>
<p>10 子查询中慎重使用IN或者NOT IN语句，使用where (NOT) exists的效果要好的多。IN、OR子句常会使索引失效，可以考虑把子句拆开，拆开的子句中尽量包含索引。<br />
&nbsp;<br />
11慎重使用视图的联合查询，尤其是比较复杂的视图之间的联合查询。一般对视图的查询最好都分解为对数据表的直接查询效果要好一些。</p>
<p>12&nbsp; <span class="hilite1">ORACLE</span>提 供的DBMS_SHARED_POOL程序可以帮助程序员将某些经常使用的存储过程&#8220;钉&#8221;在SQL区中而不被换出内存，程序员对于经常使用并且占用内存较 多的存储过程&#8220;钉&#8221;到内存中有利于提高最终用户的响应时间。一定要确认非常有必要时才采用这个方法，否则对系统只有坏的影响，会降低内存利用率。<br />
(execute DBMS_SHARED_POOL.KEEP('APPOWNER.ADD_CLIENT','P'); <br />
（P代表PROCEDURES，C代表CURSORS）)</p>
<p>13. 从物理存储方面降低竞争，提高索引效率：将索引和数据分开不同的表空间存放，以减少I/O竞争（尽量将索引、数据表空间从物理底蹭分开是数据库建设前期物 理设计工作的重要部分）。举例：九七数据库里的TB表（长驻cache；仅几十行数据，并发度高，更新频繁，分多个block存放，降低block I/O竞争）</p>
<p>14．加hint强制使用索引<br />
有时候<span class="hilite1">oracle</span>自动判断的CBO信息不能令人满意时，就需要我们手工加hint来强制sql语句得到我们想要的执行计划。<br />
Hint的基本使用方法：<br />
----紧跟DML（select，insert，delete，update）之后：/*+hint_content*/，/*和+之间不能有空格；或者用--+，此行后面均为hint<span id="S__699_ADDIV_9" onmouseover="S__699.SHOWFLOW('内容','9',event);this.style.textDecoration='none';" style="cursor: pointer; color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="S__699.SHOWFLOW('内容','9',event);" onmouseout="S__699.hidden('9');;this.style.textDecoration='underline';" oncontentextmenu="return false">内容</span>；<br />
----一句sql只能有一个hint，但里面可以有多层，eg：/*+hint1,hint2&#8230;*/；<br />
----sql语句中若使用了别名(aliase)，则hint里面也必须使用别名。<br />
--不要对view查询加hint，无效。<br />
Tip：尽量少用hint，因为随着数据变化，可能加hint的执行计划逐渐变的不再是最优；加hint的维护成本较高；</p>
<p>15．使用session/transaction级别的临时表会大大提高中间处理的速度：<br />
---临时表只对本session或者transaction可见，关闭session或者退出transaction时，临时表自动被清理drop；<br />
---其他session/transaction可以建同名的temporary table，用户只对自己的temp table操作；<br />
---临时表使用temp表空间，此类表的DML操作不产生redo log，只产生undo log<br />
---可以在其上建index，index也一样是temporary的，生命阶段同temp table。<br />
create global temporary table tab_name(&#8230;.)；</p>
<p>结语：<br />
<span class="hilite1">Oracle</span> 是否真正使用索引，使用索引是否真正有效，还是必须进行实地的测验。合理的做法是，对所写的复杂的 sql, 在将它写入应用程序之前，先在产品数据库上做一次explain，获得对该 sql 的解析，明确看到 <span class="hilite1">Oracle</span> 是如何执行该sql 的，并进行适当优化调整；<br />
另外，即使是相同的sql语句，也会因为表的大小等<span id="S__699_ADDIV_2" onmouseover="S__699.SHOWFLOW('原因','2',event);this.style.textDecoration='none';" style="cursor: pointer; color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="S__699.SHOWFLOW('原因','2',event);" onmouseout="S__699.hidden('2');;this.style.textDecoration='underline';" oncontentextmenu="return false">原因</span>造成执行计划的不同，所以一定要具体情况具体分析！ 如果经常做 explain, 就会发现，喜爱写复杂的 sql 并不是个好习惯，因为过分复杂的sql 其解析计划往往不尽如人意。事实上，将复杂的 sql 拆开，有时候会极大地提高效率，因为能获得很好的优化。</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; <br />
&nbsp;2004.5.26 定稿 <br />
实际案例:<br />
1、 select 'x' from dh where dhso in (select ogso from og where ogid = 21097023 and ogzt='VALID') and dhcz = 18 and dhzt&lt;&gt;'OVER'；<br />
执行情况：no rows selected&nbsp;&nbsp; Elapsed: 00:07:05.98<br />
Execution Plan<br />
----------------------------------------------------------<br />
&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT STATEMENT Optimizer=CHOOSE<br />
&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; VIEW<br />
&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; SORT (UNIQUE)<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; TABLE ACCESS (BY INDEX ROWID) OF 'DH'<br />
&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'IND_DHCZ_DHZT' (NON-UNIQUE)<br />
&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'OG'<br />
&nbsp;&nbsp; 7&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (UNIQUE SCAN) OF 'PK_OGID_OGSO' (UNIQUE)<br />
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; 421027&nbsp; consistent gets<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 15181&nbsp; physical reads<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1000&nbsp; redo size<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 181&nbsp; bytes sent via SQL*Net to client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 278&nbsp; bytes received via SQL*Net from client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; SQL*Net roundtrips to/from client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; sorts (memory)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; sorts (disk)<br />
0&nbsp;rows processed<br />
原语句用7分6秒完成，使用sqlexpert优化后选取的一个新语句如下，出结果仅用8秒！<br />
select /*+ ALL_ROWS */ 'x' from dh <br />
&nbsp;where EXISTS (SELECT 'X' from og WHERE ogid = 21097023 and ogzt = 'VALID' AND ogso = dhso)&nbsp;&nbsp;&nbsp; and dhcz = 18 and dhzt &lt;&gt; 'OVER'；<br />
执行情况：&nbsp; no rows selected&nbsp;&nbsp; Elapsed: 00:00:08.23<br />
Execution Plan<br />
----------------------------------------------------------<br />
&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT STATEMENT Optimizer=HINT: ALL_ROWS (Cost=119 Card=55<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Bytes=3410)<br />
&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'DH' (Cost=2 Card=1 Bytes<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =31)<br />
&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; NESTED LOOPS (Cost=119 Card=55 Bytes=3410)<br />
&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SORT (UNIQUE)<br />
&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'OG' (Cost=6 Card=5<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5 Bytes=1705)<br />
&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'PK_OGID_OGSO' (UNIQUE) (Cos<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t=2 Card=2191)</p>
<p>&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'IND_DHSO' (NON-UNIQUE) (Cost=1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Card=2018)<br />
Statistics<br />
----------------------------------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 16&nbsp; recursive calls<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; db block gets<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp; consistent gets<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; physical reads<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; redo size<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 181&nbsp; bytes sent via SQL*Net to client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 278&nbsp; bytes received via SQL*Net from client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; SQL*Net roundtrips to/from client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&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><br />
2、select&nbsp; GGZT,GGXX,GGSJ,GGRQ,GGLR,GGGH,GGDH,GGBZ,GGID&nbsp; <br />
from GG&nbsp; where GGRQ&gt;='20040325' <br />
and GGRQ&lt;='20040325' and GGID&gt;8673 and GGZT='VALID' and GGID in&nbsp; <br />
(select&nbsp; GFGG from GF,GB where GFGG=GBGG <br />
and ((GFGW=1 and GFQX&gt;='003' and GBLX='001' and GBDW=104)&nbsp; <br />
or (GFGW=118 and GFQX&gt;='000' and GBLX='002' and GBDW=102))) <br />
order by GGID DESC;<br />
--联合查询三个小表（GG 1M，&nbsp; GB 2M，&nbsp; GF 2M）, 用了索引反而慢，又费cpu，优化后改成全表扫描:</p>
<p>执行情况：<br />
no rows selected<br />
Elapsed: 00:00:18.57<br />
Execution Plan<br />
----------------------------------------------------------<br />
&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT STATEMENT Optimizer=CHOOSE<br />
&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; SORT (ORDER BY)<br />
&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; VIEW<br />
&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SORT (UNIQUE)<br />
&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CONCATENATION<br />
&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NESTED LOOPS<br />
&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NESTED LOOPS<br />
&nbsp;&nbsp; 7&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'GB'<br />
&nbsp;&nbsp; 8&nbsp;&nbsp;&nbsp; 7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'IND_GBLX_GBDW' (NON-U<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NIQUE)<br />
&nbsp;&nbsp; 9&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'GF'<br />
&nbsp; 10&nbsp;&nbsp;&nbsp; 9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'IND_GFGW' (NON-UNIQUE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<br />
11&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'GG'<br />
&nbsp; 12&nbsp;&nbsp; 11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (UNIQUE SCAN) OF 'PK_GGID' (UNIQUE)<br />
&nbsp; 13&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NESTED LOOPS<br />
&nbsp; 14&nbsp;&nbsp; 13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NESTED LOOPS<br />
&nbsp; 15&nbsp;&nbsp; 14&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'GB'<br />
&nbsp; 16&nbsp;&nbsp; 15&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'IND_GBLX_GBDW' (NON-U<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NIQUE)<br />
&nbsp; 17&nbsp;&nbsp; 14&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'GF'<br />
&nbsp; 18&nbsp;&nbsp; 17&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'IND_GFGW' (NON-UNIQUE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<br />
&nbsp; 19&nbsp;&nbsp; 13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'GG'<br />
&nbsp; 20&nbsp;&nbsp; 19&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (UNIQUE SCAN) OF 'PK_GGID' (UNIQUE)<br />
Statistics<br />
----------------------------------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 243&nbsp; recursive calls<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; db block gets<br />
&nbsp;&nbsp;&nbsp;&nbsp; 346554&nbsp; consistent gets<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20&nbsp; physical reads<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; redo size<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 534&nbsp; bytes sent via SQL*Net to client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 278&nbsp; bytes received via SQL*Net from client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; SQL*Net roundtrips to/from client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8&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><br />
select /*+ full(gg) */ GGZT,GGXX,GGSJ,GGRQ,GGLR,GGGH,GGDH,GGBZ,GGID&nbsp; <br />
from GG&nbsp; where GGRQ&gt;='20040325' <br />
and GGRQ&lt;='20040325' and GGID&gt;8673 and GGZT='VALID' and GGID in&nbsp; <br />
(select /*+ full(gf) */ GFGG from GF,GB where GFGG=GBGG <br />
and ((GFGW=1 and GFQX&gt;='003' and GBLX='001' and GBDW=104)&nbsp; <br />
or (GFGW=118 and GFQX&gt;='000' and GBLX='002' and GBDW=102))) <br />
order by GGID DESC;<br />
执行情况：<br />
no rows selected</p>
<p>Elapsed: 00:00:07.96</p>
<p>Execution Plan<br />
----------------------------------------------------------<br />
&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT STATEMENT Optimizer=CHOOSE (Cost=25 Card=1 Bytes=715)<br />
&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; SORT (ORDER BY) (Cost=25 Card=1 Bytes=715)<br />
&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; HASH JOIN (SEMI) (Cost=22 Card=1 Bytes=715)<br />
&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'GG' (Cost=3 Card=1 Bytes=702)<br />
&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VIEW OF 'VW_NSO_1' (Cost=18 Card=1 Bytes=13)<br />
&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HASH JOIN (Cost=18 Card=1 Bytes=62)<br />
&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'GB' (Cost=4 Card<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =1041 Bytes=32271)<br />
&nbsp;&nbsp; 7&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BITMAP CONVERSION (TO ROWIDS)<br />
&nbsp;&nbsp; 8&nbsp;&nbsp;&nbsp; 7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BITMAP OR<br />
&nbsp;&nbsp; 9&nbsp;&nbsp;&nbsp; 8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BITMAP CONVERSION (FROM ROWIDS)<br />
&nbsp; 10&nbsp;&nbsp;&nbsp; 9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'IND_GBLX_GBDW' (NON<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -UNIQUE) (Cost=1)<br />
&nbsp; 11&nbsp;&nbsp;&nbsp; 8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BITMAP CONVERSION (FROM ROWIDS)<br />
&nbsp; 12&nbsp;&nbsp; 11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'IND_GBLX_GBDW' (NON<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -UNIQUE) (Cost=1)<br />
&nbsp; 13&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'GF' (Cost=13 Card=1213 Byt<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; es=37603)<br />
Statistics<br />
----------------------------------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 390&nbsp; recursive calls<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; db block gets<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 82&nbsp; consistent gets<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4&nbsp; physical reads<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; redo size<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 534&nbsp; bytes sent via SQL*Net to client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 278&nbsp; bytes received via SQL*Net from client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; SQL*Net roundtrips to/from client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&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>
&nbsp;
<img src ="http://www.blogjava.net/conans/aggbug/209590.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-06-20 23:05 <a href="http://www.blogjava.net/conans/articles/209590.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>