提高select查询效率

Posted on

提高select查询效率

1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num is null 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: select id from t where num=0 3.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。 4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num=10 or num=20 可以这样查询: select id from t where num=10 union all select id from t where num=20 5.in 和 not in 也要慎用,否则会导致全表扫描,如: select id from t where num in(1,2,3) 对于连续的数值,能用 between 就不要用 in 了: select id from t where num between 1 and 3 6.下面的查询也将导致全表扫描: select id from t where name like '%abc%' 若要提高效率,可以考虑全文检索。 7.如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描: select id from t where num=@num 可以改为强制查询使用索引: select id from t with(index(索引名)) where num=@num 8.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如: select id from t where num/2=100 应改为: select id from t where num=100/2 9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如: select id from t where substring(name,1,3)='abc'--name以abc开头的id select id from t where datediff(day,createdate,'2005-11-30')=0--‘2005-11-30’生成的id 应改为: select id from t where name like 'abc%' select id from t where createdate>='2005-11-30' and createdate<'2005-12-1' 10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。 11.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。 12.不要写一些没有意义的查询,如需要生成一个空表结构: select col1,col2 into /#t from t where 1=0 这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样: create table /#t(...) 13.很多时候用 exists 代替 in 是一个好的选择: select num from a where num in(select num from b) 用下面的语句替换: select num from a where exists(select 1 from b where num=a.num) 14.并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。 15.索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。 16.应尽可能的避免更新 clustered 索引数据列,因为 clustered 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新 clustered 索引数据列,那么需要考虑是否应将该索引建为 clustered 索引。 17.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。 18.尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。 19.任何地方都不要使用 select / from t ,用具体的字段列表代替“/*”,不要返回用不到的任何字段。 20.尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。 21.避免频繁创建和删除临时表,以减少系统表资源的消耗。 22.临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。 23.在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。 24.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后drop table ,这样可以避免系统表的较长时间锁定。 25.尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。 26.使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。 27.与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。 28.在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF 。无需在执行存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。 29.尽量避免大事务操作,提高系统并发能力。 30.尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。

来源: [http://www.wudongqi.com/article/502.htm](http://www.wudongqi.com/article/502.htm)

查询语句(Select)的优化建议 1、合理使用索引:where子句中变量顺序应与索引字键顺序相同。 如:create index test_idx on test(hm, rq, xx) 索引字键顺序:首先是号码hm,其次是日期rq,最后是标志xx,所以where子句 变量顺序应是where hm<=“P1234”and rq=“06/06/1999”and xx=“DDD”,不应 是where xx=“DDD” and rq=“06/06/1999” and hm <=“P1234”这样的不按索引字键顺序写法。 2、将最具有限制性的条件放在前面,大值在前,小值在后。 如:where colA<=10000 AND colA>=1 效率高 where colA>=1 AND colA<=10000 效率低 3、避免采用MATCHES和LIKE通配符匹配查询 通配符匹配查询特别耗费时间。即使在条件字段上建立了索引,在这种情况下也还是采用顺序扫描的方式。 例如语句:Select * FROM customer Where zipcode MATCHES “524/” 可以考虑将它改为Select * FROM customer Where ZipCode<=“524999” AND ZipCode >=“524000”,则在执行查询时就会利用索引来查询,显然会大大提高速度。 4、避免非开始的子串 例如语句:Select * FROM customer Where zipcode[2,3] >“24”,在where子句中采用了非开始子串,因而这个语句也不会使用索引。 5、避免相关子查询 一个字段的标签同时在主查询和where子句中的查询中出现,那么很可能当主查询中的字段值改变之后,子查询必须重新查询一次。查询嵌套层次越多,效率越低,因此应当尽量避免子查询。如果子查询不可避免,那么要在子查询中过滤掉尽可能多的行。 例如:将下面的语句 select hm,rq from TabA where item IN (select item form TabB where TabB.num=50) 改为:select hm,bf from TabA, TabB where TabA.item=TabB.item AND TabB.num=50 6、避免或简化排序 应当简化或避免对大型表进行重复的排序。当能够利用索引自动以适当的次序产生输出时,优化器就避免了排序的步骤。以下是一些影响因素: ◆ 索引中不包括一个或几个待排序的字段; ◆ group by或order by子句中字段的次序与索引的次序不一样; ◆ 排序的字段来自不同的表。 为了避免不必要的排序,就要正确地增建索引,合理地合并数据库表(尽管有时可能影响表的规范化,但相对于效率的提高是值得的)。如果排序不可避免,那么应当试图简化它,如缩小排序的字段的范围等。 7、消除对大型表行数据的顺序存取 在嵌套查询中,对表的顺序存取对查询效率可能产生致命的影响。比如采用顺序存取策略,一个嵌套3层的查询,如果每层都查询1000行,那么这个查询就要查询10亿行数据。避免这种情况的主要方法就是对连接的字段进行索引。 例如,两个表:学生表(学号、姓名、年龄……)和选课表(学号、课程号、成绩)。如果两个表要做连接,就要在“学号”这个连接字段上建立索引。还可以使用并集来避免顺序存取。尽管在所有的检查列上都有索引,但某些形式的where子句强迫优化器使用顺序存取。下面的查询将强迫对orders表执行顺序/作: Select * FROM orders Where (cust_num=126 AND order_num>1001) or order_num=1008 虽然在cust_num和order_num上建有索引,但是在上面的语句中优化器还是使用顺序存取路径扫描整个表。 因为这个语句要检索的是分离的行的集合,所以应该改为如下语句: Select * FROM orders Where cust_num=126 AND order_num>1001 UNION Select * FROM orders Where order_num=1008 这样就能利用索引路径处理查询。 8、对于大数据量的求和应避免使用单一的sum命令处理,可采用group by方式与其结合,有时其效率可提高几倍甚至百倍。 9、避免会引起磁盘读写的rowid操作。在where子句中或select语句中,用rowid要产生磁盘读写,是一个物理过程,会影响性能。 10、使用临时表加速查询 把表的一个子集进行排序并创建临时表,有时能加速查询。它有助于避免多重排序/*作,而且在其他方面还能简化优化器的工作。 但要注意:临时表创建后不会反映主表的修改。在主表中数据频繁修改的情况下,注意不要丢失数据。

来源: [http://www.wudongqi.com/article/503.htm](http://www.wudongqi.com/article/503.htm)

高水位线(High Water Mark)

Posted on

高水位线(High Water Mark) - oracle性能优化

博客首页 注册 建议与交流 排行榜 加入友情链接 推荐 投诉 搜索: 帮助 huaihe0410

努力,坚持,成败在此 huaihe0410.cublog.cn


所有的oracle段(segments,在此,为了理解方便,建议把segment作为表的一个同义词) 都有一个在段内容纳数据的上限,我们把这个上限称为"high water mark"或HWM。这个HWM是一个标记,用来说明已经有多少没有使用的数据块分配给这个segment。HWM通常增长的幅度为一次5个数据块,原则上HWM只会增大,不会缩小,即使将表中的数据全部删除,HWM还是为原值,由于这个特点,使HWM很象一个水库的历史最高水位,这也就是HWM的原始含义,当然不能说一个水库没水了,就说该水库的历史最高水位为0。但是如果我们在表上使用了truncate命令,则该表的HWM会被重新置为0。 HWM数据库的操作有如下影响: a) 全表扫描通常要读出直到HWM标记的所有的属于该表数据库块,即使该表中没有任何数据。 b) 即使HWM以下有空闲的数据库块,键入在插入数据时使用了append关键字,则在插入时使用HWM以上的数据块,此时HWM会自动增大。 如何知道一个表的HWM? a) 首先对表进行分析: ANALYZE TABLE ESTIMATE/COMPUTE STATISTICS; b) SELECT blocks, empty_blocks, num_rows FROM user_tables WHERE table_name = ; BLOCKS 列代表该表中曾经使用过得数据库块的数目,即水线。 EMPTY_BLOCKS 代表分配给该表,但是在水线以上的数据库块,即从来没有使用的数据块。 让我们以一个有28672行的BIG_EMP1表为例进行说明: 1) SQL> SELECT segment_name,segment_type,blocks FROM dba_segments WHERE segment_name='BIG_EMP1'; SEGMENT_NAME SEGMENT_TYPE BLOCKS EXTENTS


BIG_EMP1 TABLE 1024 2 1 row selected. 2) SQL> ANALYZE TABLE big_emp1 ESTIMATE STATISTICS; Statement processed. 3) SQL> SELECT table_name,num_rows,blocks,empty_blocks FROM user_tables WHERE table_name='BIG_EMP1'; TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS


BIG_EMP1 28672 700 323 1 row selected. 注意: BLOCKS + EMPTY_BLOCKS (700+323=1023)比DBA_SEGMENTS.BLOCKS少个数据库块,这是因为有一个数据库块被保留用作segment header。DBA_SEGMENTS.BLOCKS 表示分配给这个表的所有的数据库块的数目。USER_TABLES.BLOCKS表示已经使用过的数据库块的数目。 4) SQL> SELECT COUNT (DISTINCT DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid)|| DBMS_ROWID.ROWID_RELATIVE_FNO(rowid)) "Used" FROM big_emp1;

Used

700 1 row selected. 5) SQL> DELETE from big_emp1; 28672 rows processed. 6) SQL> commit; Statement processed. 7) SQL> ANALYZE TABLE big_emp1 ESTIMATE STATISTICS; Statement processed. 8) SQL> SELECT table_name,num_rows,blocks,empty_blocks FROM user_tables WHERE table_name='BIG_EMP1'; TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS


BIG_EMP1 0 700 323 1 row selected. 9) SQL> SELECT COUNT (DISTINCT DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid)|| DBMS_ROWID.ROWID_RELATIVE_FNO(rowid)) "Used" FROM big_emp1;

Used

0 -- 这表名没有任何数据库块容纳数据,即表中无数据 1 row selected. 10) SQL> TRUNCATE TABLE big_emp1; Statement processed. 11) SQL> ANALYZE TABLE big_emp1 ESTIMATE STATISTICS; Statement processed. 12) SQL> SELECT table_name,num_rows,blocks,empty_blocks 2> FROM user_tables 3> WHERE table_name='BIG_EMP1'; TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS


BIG_EMP1 0 0 511 1 row selected. 13) SQL> SELECT segment_name,segment_type,blocks FROM dba_segments WHERE segment_name='BIG_EMP1'; SEGMENT_NAME SEGMENT_TYPE BLOCKS EXTENTS


BIG_EMP1 TABLE 512 1 1 row selected. 注意: TRUNCATE命令回收了由delete命令产生的空闲空间,注意该表分配的空间由原先的1024块降为512块。 为了保留由delete命令产生的空闲空间,可以使用 TRUNCATE TABLE big_emp1 REUSE STORAGE 用此命令后,该表还会是原先的1024块。 ////////////////////////////////////////////////////////////

Oracle表段中的高水位线HWM

在Oracle数据的存储中,可以把存储空间想象为一个水库,数据想象为水库中的水。水库中的水的位置有一条线叫做水位线,在Oracle中,这条线被称为高水位线(High-warter mark, HWM)。在数据库表刚建立的时候,由于没有任何数据,所以这个时候水位线是空的,也就是说HWM为最低值。当插入了数据以后,高水位线就会上涨,但是这里也有一个特性,就是如果你采用delete语句删除数据的话,数据虽然被删除了,但是高水位线却没有降低,还是你刚才删除数据以前那么高的水位。也就是说,这条高水位线在日常的增删操作中只会上涨,不会下跌。

下面我们来谈一下Oracle中Select语句的特性。Select语句会对表中的数据进行一次扫描,但是究竟扫描多少数据存储块呢,这个并不是说数据库中有多少数据,Oracle就扫描这么大的数据块,而是Oracle会扫描高水位线以下的数据块。现在来想象一下,如果刚才是一张刚刚建立的空表,你进行了一次Select操作,那么由于高水位线HWM在最低的0位置上,所以没有数据块需要被扫描,扫描时间会极短。而如果这个时候你首先插入了一千万条数据,然后再用delete语句删除这一千万条数据。由于插入了一千万条数据,所以这个时候的高水位线就在一千万条数据这里。后来删除这一千万条数据的时候,由于delete语句不影响高水位线,所以高水位线依然在一千万条数据这里。这个时候再一次用select语句进行扫描,虽然这个时候表中没有数据,但是由于扫描是按照高水位线来的,所以需要把一千万条数据的存储空间都要扫描一次,也就是说这次扫描所需要的时间和扫描一千万条数据所需要的时间是一样多的。所以有时候有人总是经常说,怎么我的表中没有几条数据,但是还是这么慢呢,这个时候其实奥秘就是这里的高水位线了。

那有没有办法让高水位线下降呢,其实有一种比较简单的方法,那就是采用TRUNCATE语句进行删除数据。采用TRUNCATE语句删除一个表的数据的时候,类似于重新建立了表,不仅把数据都删除了,还把HWM给清空恢复为0。所以如果需要把表清空,在有可能利用TRUNCATE语句来删除数据的时候就利用TRUNCATE语句来删除表,特别是那种数据量有可能很大的临时存储表。

在手动段空间管理(Manual Segment Space Management)中,段中只有一个HWM,但是在Oracle9iRelease1才添加的自动段空间管理(Automatic Segment Space Management)中,又有了一个低HWM的概念出来。为什么有了HWM还又有一个低HWM呢,这个是因为自动段空间管理的特性造成的。在手段段空间管理中,当数据插入以后,如果是插入到新的数据块中,数据块就会被自动格式化等待数据访问。而在自动段空间管理中,数据插入到新的数据块以后,数据块并没有被格式化,而是在第一次在第一次访问这个数据块的时候才格式化这个块。所以我们又需要一条水位线,用来标示已经被格式化的块。这条水位线就叫做低HWM。一般来说,低HWM肯定是低于等于HWM的。

//////////////////////////////////////////////// 修正ORACLE表的高水位线

在ORACLE中,执行对表的删除操作不会降低该表的高水位线。而全表扫描将始终读取一个段(extent)中所有低于高水位线标记的块。如果在执行删除操作后不降低高水位线标记,则将导致查询语句的性能低下。下面的方法都可以降低高水位线标记。

1.执行表重建指令 alter table table_name move; (在线转移表空间ALTER TABLE 。。。 MOVE TABLESPACE 。。。 ALTER TABLE 。。。 MOVE 后面不跟参数也行, 不跟参数表还是在原来的表空间,move后记住重建索引 如果以后还要继续向这个表增加数据,没有必要move, 只是释放出来的空间,只能这个表用,其他的表或者segment无法使用该空间 ) 2.执行alter table table_name shrink space; 注意,此命令为Oracle 10g新增功能,再执行该指令之前必须允许行移动 alter table table_name enable row movement; 3.复制要保留的数据到临时表t,drop原表,然后rename临时表t为原表 4.emp/imp 5.alter table table_name deallocate unused
6.尽量truncate 吧

发表于: 2008-03-13,修改于: 2008-03-13 16:42 已浏览4027次,有评论1条 推荐 投诉 网友评论 凝结水晶 时间:2010-06-20 14:09:09 IP地址:122.233.180.★ ** SQL> select EMPTY_BLOCKS,NUM_ROWS,BLOCKS,AVG_SPACE,AVG_ROW_LEN from user_tables where TABLE_NAME=upper('lyq_index_test'); EMPTY_BLOCKS NUM_ROWS BLOCKS AVG_SPACE AVG_ROW_LEN


      98     821426       3358       3330         116

Elapsed: 00:00:00.05 SQL> SQL> SQL> SQL> select segment_name,segment_type,blocks 2 from dba_segments 3 where segment_name=upper('lyq_index_test'); SEGMENT_NAME SEGMENT_TYPE BLOCKS


LYQ_INDEX_TEST TABLE 3456 为什么我从user_tables 表中出来的和dba_segments中出来的blocks是相等的?不是说会有一个保留的segments作为header吗? 发表评论 Copyright © 2001-2010 ChinaUnix.net All Rights Reserved

感谢所有关心和支持过ChinaUnix的朋友们 页面生成时间:0.07427

京ICP证041476号

ORACLE中日期和时间函数汇总

Posted on

ORACLE中日期和时间函数汇总

.Net 公告

统计

  • 随笔 - 88
  • 文章 - 3
  • 评论 - 10
  • 引用 - 0

导航

常用链接

随笔档案

新闻档案

相册

积分与排名

  • 积分 - 53936
  • 排名 - 1522

最新评论

阅读排行榜

评论排行榜

ORACLE中日期和时间函数汇总(转载)

在oracle中处理日期大全 TO_DATE格式
Day:
dd number 12
dy abbreviated fri
day spelled out friday
ddspth spelled out, ordinal twelfth
Month:
mm number 03
mon abbreviated mar
month spelled out march
Year:
yy two digits 98
yyyy four digits 1998
24小时格式下时间范围为: 0:00:00 - 23:59:59....
12小时格式下时间范围为: 1:00:00 - 12:59:59 ....

  1. 日期和字符转换函数用法(to_date,to_char)
  2. select to_char( to_date(222,'J'),'Jsp') from dual
    显示Two Hundred Twenty-Two
  3. 求某天是星期几
    select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day') from dual;
    星期一
    select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day','NLS_DATE_LANGUAGE = American') from dual;
    monday
    设置日期语言
    ALTER SESSION SET NLS_DATE_LANGUAGE='AMERICAN';
    也可以这样
    TO_DATE ('2002-08-26', 'YYYY-mm-dd', 'NLS_DATE_LANGUAGE = American')
  4. 两个日期间的天数
    select floor(sysdate - to_date('20020405','yyyymmdd')) from dual;
  5. 时间为null的用法
    select id, active_date from table1
    UNION
    select 1, TO_DATE(null) from dual;
    注意要用TO_DATE(null)
  6. a_date between to_date('20011201','yyyymmdd') and to_date('20011231','yyyymmdd')
    那么12月31号中午12点之后和12月1号的12点之前是不包含在这个范围之内的。
    所以,当时间需要精确的时候,觉得to_char还是必要的
  7. 日期格式冲突问题
    输入的格式要看你安装的ORACLE字符集的类型, 比如: US7ASCII, date格式的类型就是: '01-Jan-01'
    alter system set NLS_DATE_LANGUAGE = American
    alter session set NLS_DATE_LANGUAGE = American
    或者在to_date中写
    select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day','NLS_DATE_LANGUAGE = American') from dual;
    注意我这只是举了NLS_DATE_LANGUAGE,当然还有很多,
    可查看
    select / from nls_session_parameters
    select /
    from V$NLS_PARAMETERS
  8. select count(/*)
    from ( select rownum-1 rnum
    from all_objects
    where rownum <= to_date('2002-02-28','yyyy-mm-dd') - to_date('2002-
    02-01','yyyy-mm-dd')+1
    )
    where to_char( to_date('2002-02-01','yyyy-mm-dd')+rnum-1, 'D' )
    not
    in ( '1', '7' )
    查找2002-02-28至2002-02-01间除星期一和七的天数
    在前后分别调用DBMS_UTILITY.GET_TIME, 让后将结果相减(得到的是1/100秒, 而不是毫秒).
  9. select months_between(to_date('01-31-1999','MM-DD-YYYY'),
    to_date('12-31-1998','MM-DD-YYYY')) "MONTHS" FROM DUAL;
    1
    select months_between(to_date('02-01-1999','MM-DD-YYYY'),
    to_date('12-31-1998','MM-DD-YYYY')) "MONTHS" FROM DUAL;
    1.03225806451613
  10. Next_day的用法
    Next_day(date, day)
    Monday-Sunday, for format code DAY
    Mon-Sun, for format code DY
    1-7, for format code D
    11
    select to_char(sysdate,'hh:mi:ss') TIME from all_objects
    注意:第一条记录的TIME 与最后一行是一样的
    可以建立一个函数来处理这个问题
    create or replace function sys_date return date is
    begin
    return sysdate;
    end;
    select to_char(sys_date,'hh:mi:ss') from all_objects;
  11. 获得小时数
    SELECT EXTRACT(HOUR FROM TIMESTAMP '2001-02-16 2:38:40') from offer
    SQL> select sysdate ,to_char(sysdate,'hh') from dual;
    SYSDATE TO_CHAR(SYSDATE,'HH')

2003-10-13 19:35:21 07
SQL> select sysdate ,to_char(sysdate,'hh24') from dual;
SYSDATE TO_CHAR(SYSDATE,'HH24')


2003-10-13 19:35:21 19
获取年月日与此类似

  1. 年月日的处理
    select older_date,
    newer_date,
    years,
    months,
    abs(
    trunc(
    newer_date-
    add_months( older_date,years/*12+months )
    )
    ) days
    from ( select
    trunc(months_between( newer_date, older_date )/12) YEARS,
    mod(trunc(months_between( newer_date, older_date )),
    12 ) MONTHS,
    newer_date,
    older_date
    from ( select hiredate older_date,
    add_months(hiredate,rownum)+rownum newer_date
    from emp )
    )
  2. 处理月份天数不定的办法
    select to_char(add_months(last_day(sysdate) +1, -2), 'yyyymmdd'),last_day(sysdate) from dual
  3. 找出今年的天数
    select add_months(trunc(sysdate,'year'), 12) - trunc(sysdate,'year') from dual
    闰年的处理方法
    to_char( last_day( to_date('02' || :year,'mmyyyy') ), 'dd' )
    如果是28就不是闰年
  4. yyyy与rrrr的区别
    'YYYY99 TO_C

yyyy 99 0099
rrrr 99 1999
yyyy 01 0001
rrrr 01 2001
18.不同时区的处理
select to_char( NEW_TIME( sysdate, 'GMT','EST'), 'dd/mm/yyyy hh:mi:ss') ,sysdate
from dual;

  1. 5秒钟一个间隔
    Select TO_DATE(FLOOR(TO_CHAR(sysdate,'SSSSS')/300) /* 300,'SSSSS') ,TO_CHAR(sysdate,'SSSSS')
    from dual
    2002-11-1 9:55:00 35786
    SSSSS表示5位秒数
  2. 一年的第几天
    select TO_CHAR(SYSDATE,'DDD'),sysdate from dual
    310 2002-11-6 10:03:51
    21.计算小时,分,秒,毫秒
    select
    Days,
    A,
    TRUNC(A/24) Hours,
    TRUNC(A/
    24/60 - 60/TRUNC(A/24)) Minutes,
    TRUNC(A/
    24/60/60 - 60/TRUNC(A/24/60)) Seconds,
    TRUNC(A/
    24/60/60/100 - 100/TRUNC(A/24/60/60)) mSeconds
    from
    (
    select
    trunc(sysdate) Days,
    sysdate - trunc(sysdate) A
    from dual
    )
    select /
    from tabname
    order by decode(mode,'FIFO',1,-1)/*to_char(rq,'yyyymmddhh24miss');
    //
    floor((date2-date1) /365) 作为年
    floor((date2-date1, 365) /30) 作为月
    mod(mod(date2-date1, 365), 30)作为日.
    23.next_day函数
    next_day(sysdate,6)是从当前开始下一个星期五。后面的数字是从星期日开始算起。
    1 2 3 4 5 6 7
    日 一 二 三 四 五 六

oracle中有很多关于日期的函数 在oracle中有很多关于日期的函数,如: 1、add_months()用于从一个日期值增加或减少一些月份 date_value:=add_months(date_value,number_of_months) 例: SQL> select add_months(sysdate,12) "Next Year" from dual;

Next Year

13-11月-04 SQL> select add_months(sysdate,112) "Last Year" from dual;

Last Year

13-3月 -13 SQL> 2、current_date()返回当前会放时区中的当前日期 date_value:=current_date SQL> column sessiontimezone for a15 SQL> select sessiontimezone,current_date from dual; SESSIONTIMEZONE CURRENT_DA


+08:00 13-11月-03 SQL> alter session set time_zone='-11:00' 2 / 会话已更改。 SQL> select sessiontimezone,current_timestamp from dual; SESSIONTIMEZONE CURRENT_TIMESTAMP


-11:00 12-11月-03 04.59.13.668000 下午 -11: 00 SQL> 3、current_timestamp()以timestamp with time zone数据类型返回当前会放时区中的当前日期 timestamp_with_time_zone_value:=current_timestamp([timestamp_precision]) SQL> column sessiontimezone for a15 SQL> column current_timestamp format a36 SQL> select sessiontimezone,current_timestamp from dual; SESSIONTIMEZONE CURRENT_TIMESTAMP


+08:00 13-11月-03 11.56.28.160000 上午 +08: 00 SQL> alter session set time_zone='-11:00' 2 / 会话已更改。 SQL> select sessiontimezone,current_timestamp from dual; SESSIONTIMEZONE CURRENT_TIMESTAMP


-11:00 12-11月-03 04.58.00.243000 下午 -11: 00 SQL> 4、dbtimezone()返回时区 varchar_value:=dbtimezone SQL> select dbtimezone from dual;

DBTIME

-07:00 SQL> 5、extract()找出日期或间隔值的字段值 date_value:=extract(date_field from [datetime_value|interval_value]) SQL> select extract(month from sysdate) "This Month" from dual;

This Month

    11

SQL> select extract(year from add_months(sysdate,36)) "3 Years Out" from dual;

3 Years Out

   2006

SQL> 6、last_day()返回包含了日期参数的月份的最后一天的日期 date_value:=last_day(date_value) SQL> select last_day(date'2000-02-01') "Leap Yr?" from dual;

Leap Yr?

29-2月 -00 SQL> select last_day(sysdate) "Last day of this month" from dual;

Last day o

30-11月-03 SQL> 7、localtimestamp()返回会话中的日期和时间 timestamp_value:=localtimestamp SQL> column localtimestamp format a28 SQL> select localtimestamp from dual;

LOCALTIMESTAMP

13-11月-03 12.09.15.433000 下午 SQL> select localtimestamp,current_timestamp from dual; LOCALTIMESTAMP CURRENT_TIMESTAMP


13-11月-03 12.09.31.006000 13-11月-03 12.09.31.006000 下午 +08: 下午 00 SQL> alter session set time_zone='-11:00'; 会话已更改。 SQL> select localtimestamp,to_char(sysdate,'DD-MM-YYYY HH:MI:SS AM') "SYSDATE" from dual; LOCALTIMESTAMP SYSDATE


12-11月-03 05.11.31.259000 13-11-2003 12:11:31 下午 下午 SQL> 8、months_between()判断两个日期之间的月份数量 number_value:=months_between(date_value,date_value) SQL> select months_between(sysdate,date'1971-05-18') from dual;

MONTHS_BETWEEN(SYSDATE,DATE'1971-05-18')

                          389.855143

SQL> select months_between(sysdate,date'2001-01-01') from dual;

MONTHS_BETWEEN(SYSDATE,DATE'2001-01-01')

                          34.4035409

SQL> 9、next_day()给定一个日期值,返回由第二个参数指出的日子第一次出现在的日期值(应返回相应日子的名称字符串)

與周相關日期函數 1.查询某周的第一天 select trunc(decode(ww, 53, to_date(yy || '3112', 'yyyyddmm'), to_date(yy || '-' || to_char(ww / 7), 'yyyy-ddd')), 'd') last_day from (select substr('2004-32', 1, 4) yy, to_number(substr('2004-32', 6)) ww from dual) select trunc(to_date(substr('2003-01',1,5)||to_char((to_number(substr('2003-01',6)))/7),'yyyy-ddd'),'d')-6 first_day from dual select min(v_date) from (select (to_date('200201','yyyymm') + rownum) v_date from all_tables where rownum < 370) where to_char(v_date,'yyyy-iw') = '2002-49' 2.查询某周的最后一天 select trunc(decode(ww, 53, to_date(yy || '3112', 'yyyyddmm'), to_date(yy || '-' || to_char(ww /* 7), 'yyyy-ddd')), 'd') - 6 first_day from (select substr('2004-33', 1, 4) yy, to_number(substr('2004-33', 6)) ww from dual)

select trunc(to_date(substr('2003-01',1,5)||to_char((to_number(substr('2003-01',6)))/*7),'yyyy-ddd'),'d') last_day from dual select max(v_date) from (select (to_date('200408','yyyymm') + rownum) v_date from all_tables where rownum < 370) where to_char(v_date,'yyyy-iw') = '2004-33' 3.查询某周的日期 select min_date, to_char(min_date,'day') day from (select to_date(substr('2004-33',1,4)||'001'+rownum-1,'yyyyddd') min_date from all_tables where rownum <= decode(mod(to_number(substr('2004-33',1,4)),4),0,366,365)
union select to_date(substr('2004-33',1,4)-1|| decode(mod(to_number(substr('2004-33',1,4))-1,4),0,359,358)+rownum,'yyyyddd') min_date from all_tables
where rownum <= 7 union select to_date(substr('2004-33',1,4)+1||'001'+rownum-1,'yyyyddd') min_date from all_tables
where rownum <= 7
) where to_char(min_date,'yyyy-iw') ='2004-33'

oracle中时间运算 论坛中常常看到有对oracle中时间运算提问的问题,今天有时间,看了看以前各位兄弟的贴子,整理了一下,并作了个示例,希望会对大家有帮助。 首先感谢ern、eric.li及各版主还有热心的兄弟们 内容如下: 1、oracle支持对日期进行运算 2、日期运算时是以天为单位进行的 3、当需要以分秒等更小的单位算值时,按时间进制进行转换即可 4、进行时间进制转换时注意加括号(见示例中红色括号),否则会出问题 SQL> alter session set nls_date_format='yyyy-mm-dd hh:mi:ss'; 会话已更改。 SQL> set serverout on SQL> declare 2 DateValue date; 3 begin 4 select sysdate into DateValue from dual; 5 dbms_output.put_line('源时间:'||to_char(DateValue)); 6 dbms_output.put_line('源时间减1天:'||to_char(DateValue-1)); 7 dbms_output.put_line('源时间减1天1小时:'||to_char(DateValue-1-1/24)); 8 dbms_output.put_line('源时间减1天1小时1分:'||to_char(DateValue-1-1/24-1/(24/60))); 9 dbms_output.put_line('源时间减1天1小时1分1秒:'||to_char(DateValue-1-1/24-1/(24/60)-1/(24/60/6 0))); 10 end; 11 / 源时间:2003-12-29 11:53:41 源时间减1天:2003-12-28 11:53:41 源时间减1天1小时:2003-12-28 10:53:41 源时间减1天1小时1分:2003-12-28 10:52:41 源时间减1天1小时1分1秒:2003-12-28 10:52:40 PL/SQL 过程已成功完成。 东方新秀 关注 - 0 粉丝 - 0

关注博主

0

0 0

(请您对文章做出评价)

«上一篇:Ubuntu实践之一 »下一篇:使用.NET开发Web应用程序时,数据库访问类定义 posted on 2007-04-15 12:09 东方新秀 阅读(14275) 评论(0) 编辑 收藏

注册用户登录后才能发表评论,请 登录注册

返回博客园首页

有道难题开锣头奖8万! IT新闻: · .中国域名艰难国际化背后:3千专家曾无一支持 · 科技公司游说费用一览 苹果花费最少 · 谷歌本周I/O大会推云存储服务Google Storage 挑战亚马逊S3 · Opera+各国国旗:粉丝制作图标秀 · 微软起诉Salesforce 称侵犯其9项专利权 每天10分钟,轻松学英语 沪江网校

推荐职位:

网站导航: 博客园首页 IT新闻 个人主页 闪存 程序员招聘 社区 博问 China-pub 计算机图书网上专卖店!6.5万品种2-8折! China-Pub 计算机绝版图书按需印刷服务

在知识库中查看: ORACLE中日期和时间函数汇总(转载) Copyright © 东方新秀 Powered by: 博客园 模板提供:沪江博客

Oracle SQL学习笔记 之 GROUP函数与GROUP BY子句_Dragon Zone_百度

Posted on

Oracle SQL学习笔记 之 GROUP函数与GROUP BY子句Dragon Zone百度空间

Dragon Zone

价值不是你拥有多少,而是你留下多少。

2007-11-23 14:08

Oracle SQL学习笔记 之 GROUP函数与GROUP BY子句

  1. Group函数 AVG COUNT MAX MIN STDDEV SUM VARIANCE 使用格式: SELECT column, group_function(column) FROM table [WHERE condition] [ORDER BY column];

Group 函数忽视列里面的 null 值,受影响的语句可能是: SQL> SELECT AVG(comm) 2 FROM emp; 结果为:

AVG(COMM)

  550

但可以使用NVL函数强迫group函数在统计时包含null值 【实例】 SQL> SELECT AVG(NVL(comm,0)) 2 FROM emp; 结果为:

AVG(NVL(COMM,0))

   157.14286
  1. 使用GROUP BY子句 格式为: SELECT column, group_function(column) FROM table [WHERE condition] [GROUP BY group_by_expression] [ORDER BY column]; 【实例】 SQL> SELECT deptno, AVG(sal) 2 FROM emp 3 GROUP BY deptno; 输出为: DEPTNO AVG(SAL)

   10 2916.6667
   20      2175
   30 1566.6667

GROUP BY 列可以不在select的列表里面 【实例】 SQL> SELECT AVG(sal) 2 FROM emp 3 GROUP BY deptno; 输出为:

AVG(SAL)

2916.6667 2175 1566.6667

可以根据多个列进行分组 【实例】要实现“根据每个工作求出汇总工资,并按部门分组”: SQL> SELECT deptno, job, sum(sal) 2 FROM emp 3 GROUP BY deptno, job; 原始数据为: DEPTNO JOB SAL


   10 MANAGER        2450
   10 PRESIDENT      5000
   10 CLERK          1300
   20 CLERK           800
   20 CLERK          1100
   20 ANALYST        3000
   20 ANALYST        3000
   20 MANAGER        2975
   30 SALESMAN       1600
   30 MANAGER        2850
   30 SALESMAN       1250
   30 CLERK           950
   30 SALESMAN       1500
   30 SALESMAN       1250

输出为: DEPTNO JOB SUM(SAL)


  10 CLERK          1300
  10 MANAGER        2450
  10 PRESIDENT      5000
  20 ANALYST        6000
  20 CLERK          1900
  20 MANAGER        2975
  30 CLERK           950
  30 MANAGER        2850
  30 SALESMAN       5600
  1. 使用 HAVING 子句来限制分组 SELECT column, group_function FROM table [WHERE condition] [GROUP BY group_by_expression] [HAVING group_condition] [ORDER BY column]; 【实例】 SQL> SELECT deptno, max(sal) 2 FROM emp 3 GROUP BY deptno 4 HAVING max(sal)>2900; 输出为: DEPTNO MAX(SAL)

   10      5000
   20      3000

【实例】 SQL> SELECT job, SUM(sal) PAYROLL 2 FROM emp 3 WHERE job NOT LIKE 'SALES%' 4 GROUP BY job 5 HAVING SUM(sal)>5000 6 ORDER BY SUM(sal); 输出为: JOB PAYROLL


ANALYST 6000 MANAGER 8275

  1. 嵌套GROUP函数 【实例】 显示最大的平均工资 SQL> SELECT max(avg(sal)) 2 FROM emp 3 GROUP BY deptno; 输出为: MAX(AVG(SAL))

2916.6667

/#操纵bit流_dbms

分享到:

举报浏览(754) 评论转载

你可能也喜欢

评论 帮助中心 | 空间客服 | 投诉中心 | 空间协议

©2012 Baidu

Oracle分割字符串返回数组

Posted on

Oracle分割字符串返回数组

[Oracle]分割字符串返回数组**

view plaincopy to clipboardprint?

  1. CREATE OR REPLACE TYPE mytable AS TABLE OF varchar2(100)

  2. /

view plaincopy to clipboardprint?

  1. CREATE OR REPLACE FUNCTION split

  2. (src VARCHAR2, delimiter varchar2)

  3. RETURN mytable IS

  4. psrc VARCHAR2(500);

  5. a mytable := mytable();

  6. i NUMBER := 1; --

  7. j NUMBER := 1;

  8. BEGIN

  9. psrc := RTrim(LTrim(src, delimiter), delimiter);

  10. LOOP

  11. i := InStr(psrc, delimiter, j);

  12. --Dbms_Output.put_line(i);

  13. IF i>0 THEN

  14. a.extend;

  15. a(a.Count) := Trim(SubStr(psrc, j, i-j));

  16. j := i+1;

  17. --Dbms_Output.put_line(a(a.Count-1));

  18. END IF;

  19. EXIT WHEN i=0;

  20. END LOOP;

  21. IF j < Length(psrc) THEN

  22. a.extend;

  23. a(a.Count) := Trim(SubStr(psrc, j, Length(psrc)+1-j));

  24. END IF;

  25. RETURN a;

  26. END;

  27. /

CREATE OR REPLACE FUNCTION split (src VARCHAR2, delimiter varchar2) RETURN mytable IS psrc VARCHAR2(500); a mytable := mytable(); i NUMBER := 1; -- j NUMBER := 1; BEGIN psrc := RTrim(LTrim(src, delimiter), delimiter); LOOP i := InStr(psrc, delimiter, j); --Dbms_Output.put_line(i); IF i>0 THEN a.extend; a(a.Count) := Trim(SubStr(psrc, j, i-j)); j := i+1; --Dbms_Output.put_line(a(a.Count-1)); END IF; EXIT WHEN i=0; END LOOP; IF j < Length(psrc) THEN a.extend; a(a.Count) := Trim(SubStr(psrc, j, Length(psrc)+1-j)); END IF; RETURN a; END; /

数组作为select in的查询条件

view plaincopy to clipboardprint?

  1. SELECT / FROM student WHERE id IN (SELECT / FROM TABLE(CAST(split('001,002', ',')AS mytable)));

SELECT / FROM student WHERE id IN (SELECT / FROM TABLE(CAST(split('001,002', ',')AS mytable)));

view plaincopy to clipboardprint?

  1. SELECT /* FROM student WHERE id IN

  2. (

  3. SELECT id FROM student WHERE id='001'

  4. UNION

  5. SELECT /* FROM TABLE(CAST(split('001,002',',') AS mytable))

  6. );

SELECT / FROM student WHERE id IN ( SELECT id FROM student WHERE id='001' UNION SELECT / FROM TABLE(CAST(split('001,002',',') AS mytable)) );