oracle tips
===========================================================
如何sql查询出连续号码段
===========================================================
昨天在itpub看到这个帖子, 问题觉得有意思,, 就仔细想了想. 也给出了一种解决办法..:-)
问题求助,请高手指点..

我有一个表结构,
fphm,kshm
2014,00000001
2014,00000002
2014,00000003
2014,00000004
2014,00000005
2014,00000007
2014,00000008
2014,00000009
2013,00000120
2013,00000121
2013,00000122
2013,00000124
2013,00000125

(第二个字段内可能是连续的数据,可能存在断点。)

怎样能查询出来这样的结果,查询出连续的记录来。
就像下面的这样?
2014,00000001,00000005
2014,00000009,00000007
2013,00000120,00000122
2013,00000124,00000125

方法一: 引用自
hmxxyy.

SQL> select * from gap;

ID SEQ
---------- ----------
1 1
1 4
1 5
1 8
2 1
2 2
2 9

select res1.id, res2.seq str, res1.seq end
from (
select rownum rn, c.*
from (
select *
from gap a
where not exists (
select null from gap b where b.id = a.id and a.seq = b.seq - 1
)
order by id, seq
) c
) res1, (
select rownum rn, d.*
from (
select *
from gap a
where not exists (
select null from gap b where b.id = a.id and a.seq = b.seq + 1
)
order by id, seq
) d
) res2
where res1.id = res2.id
and res1.rn = res2.rn
/

ID STR END
--------- ---------- ----------
1 1 1
1 4 5
1 8 8
2 1 2
2 9 9

方法二: 使用lag/lead分析函数进行处理.. 楼上的方法确实挺好用就是觉得表扫描/表连接比较多, 可能数据量大了. 速度会比较慢, 当然我的这种方法由于使用分析函数使用的比较频繁.所以排序量可能比上一种要多..

SQL> select fphm,lpad(kshm,8,'0') kshm
2 from t
3 /

FPHM KSHM
---------- ----------------
2014 00000001
2014 00000002
2014 00000003
2014 00000004
2014 00000005
2014 00000007
2014 00000008
2014 00000009
2013 00000120
2013 00000121
2013 00000122

FPHM KSHM
---------- ----------------
2013 00000124
2013 00000125

13 rows selected.

SQL> set echo on
SQL> @bbb.sql
SQL> select fphm,lpad(kshm,8,'0') start_kshm,lpad(prev_prev_kshm,8,'0') end_kshm
2 from (
3 select fphm,kshm,next_kshm,prev_kshm,
4 lag(kshm,1,null) over (partition by fphm order by kshm )next_next_kshm,
5 lead(kshm,1,null) over (partition by fphm order by kshm ) prev_prev_kshm
6 from (
7 select *
8 from (
9 select fphm,kshm,
10 lead(kshm,1,null) over (partition by fphm order by kshm) next_kshm,
11 lag(kshm,1,null) over (partition by fphm order by kshm) prev_kshm
12 from t
13 )
14 where ( next_kshm - kshm <> 1 or kshm - prev_kshm <> 1 )
15 or ( next_kshm is null or prev_kshm is null )
16 )
17 )
18 where next_kshm - kshm = 1
19 /

FPHM START_KSHM END_KSHM
---------- ---------------- ----------------
2013 00000120 00000122
2013 00000124 00000125
2014 00000001 00000005
2014 00000007 00000009

SQL> spool off

 查看全文
jametong 发表于:2005.04.27 21:31 ::分类: ( Oracle tips ) ::阅读:(3588次) :: 评论 (23)
===========================================================
如何确定今天是本月的第几周.
===========================================================
1. 我自己想出来的方法.
思路.
a. 先确定元月1号是星期几. 这样可以退出第二周的第一天从哪天开始.
b. 计算出每个月第一天属于全年的那一周.
c. 这样就可以计算出具体某个日期属于哪一天了^_^.
SQL> @bbb.sql
SQL> select date_col,
  2           to_number(to_char(trunc(sysdate,'yyyy'),'d')) year_week_day,
  3           first_day_week,week_no,week_no - first_day_week + 1 week_no
  4  from (
  5      select date_col,
  6          to_number(to_char(trunc(sysdate,'mm') + 7 - 1 ,'ww')) first_day_week,
  7          to_number(to_char(date_col + 7 - 1,'ww')) week_no
  8      from (
  9        select trunc(sysdate,'mm') + rownum - 1 date_col
 10       from dba_objects
 11       where rownum <= to_number(to_char(last_day(sysdate),'dd'))
 12    )
 13  )
 14  /

DATE_COL  YEAR_WEEK_DAY FIRST_DAY_WEEK    WEEK_NO    WEEK_NO                   
--------- ------------- -------------- ---------- ----------                   
01-APR-05             7             14         14          1                   
02-APR-05             7             14         14          1                   
03-APR-05             7             14         15          2                   
04-APR-05             7             14         15          2                   
05-APR-05             7             14         15          2                   
06-APR-05             7             14         15          2                   
07-APR-05             7             14         15          2                   
08-APR-05             7             14         15          2                   
09-APR-05             7             14         15          2                   
10-APR-05             7             14         16          3                   
11-APR-05             7             14         16          3                   

DATE_COL  YEAR_WEEK_DAY FIRST_DAY_WEEK    WEEK_NO    WEEK_NO                   
--------- ------------- -------------- ---------- ----------                   
12-APR-05             7             14         16          3                   
13-APR-05             7             14         16          3                   
14-APR-05             7             14         16          3                   
15-APR-05             7             14         16          3                   
16-APR-05             7             14         16          3                   
17-APR-05             7             14         17          4                   
18-APR-05             7             14         17          4                   
19-APR-05             7             14         17          4                   
20-APR-05             7             14         17          4                   
21-APR-05             7             14         17          4                   
22-APR-05             7             14         17          4                   

DATE_COL  YEAR_WEEK_DAY FIRST_DAY_WEEK    WEEK_NO    WEEK_NO                   
--------- ------------- -------------- ---------- ----------                   
23-APR-05             7             14         17          4                   
24-APR-05             7             14         18          5                   
25-APR-05             7             14         18          5                   
26-APR-05             7             14         18          5                   
27-APR-05             7             14         18          5                   
28-APR-05             7             14         18          5                   
29-APR-05             7             14         18          5                   
30-APR-05             7             14         18          5                   

30 rows selected.

SQL> spool off

2. Tom使用的办法. ( 不得不说这个方法比我的方法要简单多咯:-) )
思路:
a.  取出本月1号的前一个星期天的日期
b.  再取出与该星期天的星期的差距.

SQL> @bbb.sql
SQL> select x,next_day(trunc(x,'mm')-8,'sun') next_day,
  2          trunc((x-next_day(trunc(x,'mm')-8,'sun'))/7)+1 "week"
  3  from (
  4    select trunc(sysdate,'mm') + rownum - 1 x
  5    from dba_objects
  6    where rownum <= to_number(to_char(last_day(sysdate),'dd'))
  7  )
  8  /

X         NEXT_DAY        week                                                 
--------- --------- ----------                                                 
01-APR-05 27-MAR-05          1                                                 
02-APR-05 27-MAR-05          1                                                 
03-APR-05 27-MAR-05          2                                                 
04-APR-05 27-MAR-05          2                                                 
05-APR-05 27-MAR-05          2                                                 
06-APR-05 27-MAR-05          2                                                 
07-APR-05 27-MAR-05          2                                                 
08-APR-05 27-MAR-05          2                                                 
09-APR-05 27-MAR-05          2                                                 
10-APR-05 27-MAR-05          3                                                 
11-APR-05 27-MAR-05          3                                                 

X         NEXT_DAY        week                                                 
--------- --------- ----------                                                 
12-APR-05 27-MAR-05          3                                                 
13-APR-05 27-MAR-05          3                                                 
14-APR-05 27-MAR-05          3                                                 
15-APR-05 27-MAR-05          3                                                 
16-APR-05 27-MAR-05          3                                                 
17-APR-05 27-MAR-05          4                                                 
18-APR-05 27-MAR-05          4                                                 
19-APR-05 27-MAR-05          4                                                 
20-APR-05 27-MAR-05          4                                                 
21-APR-05 27-MAR-05          4                                                 
22-APR-05 27-MAR-05          4                                                 

X         NEXT_DAY        week                                                 
--------- --------- ----------                                                 
23-APR-05 27-MAR-05          4                                                 
24-APR-05 27-MAR-05          5                                                 
25-APR-05 27-MAR-05          5                                                 
26-APR-05 27-MAR-05          5                                                 
27-APR-05 27-MAR-05          5                                                 
28-APR-05 27-MAR-05          5                                                 
29-APR-05 27-MAR-05          5                                                 
30-APR-05 27-MAR-05          5                                                 

30 rows selected.

SQL> spool off



jametong 发表于:2005.04.26 05:54 ::分类: ( Oracle tips ) ::阅读:(6738次) :: 评论 (201)
===========================================================
how to use dbms_application_info
===========================================================
1. 使用dbms_application_info设置longops的相关信息, 这样我们就可以使用v$session_longops视图来监控我们的程序执行的进度了^_^.

在第一个session中执行一个执行时间比较长的匿名块, 我们再在另一个session中监控, 这个session的执行进度^_^.
SQL> set echo on
SQL> @bbb.sql
SQL> declare
  2    rindex binary_integer;
  3    slno      binary_integer;
  4    total  number := 900;
  5    sofar  number := 0;
  6    obj       binary_integer;
  7    cont      binary_integer;
  8  begin
  9    for i in 1..900 loop
 10      sofar := sofar + 1;
 11      dbms_application_info.set_session_longops(rindex,slno,
 12        'test application',obj,cont,sofar,total,'test','seconds');
 13      dbms_lock.sleep(1);
 14    end loop;
 15  end;
 16  /


SQL> set echo on
SQL> @ccc.sql
SQL> col sid format 9999
SQL> col opname format a18
SQL> col target_desc format a10 heading 'target |description '
SQL> col sofar format 9999
SQL> col totalwork format 9999 heading 'total | work '
SQL> col units format a10
SQL> col time_remaining format 9999 heading 'time|remaining'
SQL> col elapsed_seconds format 9999 heading 'elapsed|seconds'
SQL> select sid,opname,target_desc,sofar,totalwork,units,time_remaining,elapse
seconds
  2  from v$session_longops
  3  /

                         target           total                  time elapsed
  SID OPNAME             descriptio SOFAR  work  UNITS      remaining seconds
----- ------------------ ---------- ----- ------ ---------- --------- -------
   10 test application   test          14    900 seconds          759      12

SQL> set echo off
SQL> /

                         target           total                  time elapsed
  SID OPNAME             descriptio SOFAR  work  UNITS      remaining seconds
----- ------------------ ---------- ----- ------ ---------- --------- -------
   10 test application   test          22    900 seconds          838      21

SQL> /

                         target           total                  time elapsed
  SID OPNAME             descriptio SOFAR  work  UNITS      remaining seconds
----- ------------------ ---------- ----- ------ ---------- --------- -------
   10 test application   test          25    900 seconds          840      24

SQL> /

                         target           total                  time elapsed
  SID OPNAME             descriptio SOFAR  work  UNITS      remaining seconds
----- ------------------ ---------- ----- ------ ---------- --------- -------
   10 test application   test          28    900 seconds          841      27

SQL> /

                         target           total                  time elapsed
  SID OPNAME             descriptio SOFAR  work  UNITS      remaining seconds
----- ------------------ ---------- ----- ------ ---------- --------- -------
   10 test application   test          74    900 seconds          815      73

SQL> /

                         target           total                  time elapsed
  SID OPNAME             descriptio SOFAR  work  UNITS      remaining seconds
----- ------------------ ---------- ----- ------ ---------- --------- -------
   10 test application   test         135    900 seconds          754     133

SQL> /

                         target           total                  time elapsed
  SID OPNAME             descriptio SOFAR  work  UNITS      remaining seconds
----- ------------------ ---------- ----- ------ ---------- --------- -------
   10 test application   test         137    900 seconds          757     136

SQL> /

                         target           total                  time elapsed
  SID OPNAME             descriptio SOFAR  work  UNITS      remaining seconds
----- ------------------ ---------- ----- ------ ---------- --------- -------
   10 test application   test         139    900 seconds          761     139

SQL> /

                         target           total                  time elapsed
  SID OPNAME             descriptio SOFAR  work  UNITS      remaining seconds
----- ------------------ ---------- ----- ------ ---------- --------- -------
   10 test application   test         142    900 seconds          758     142

SQL> /

                         target           total                  time elapsed
  SID OPNAME             descriptio SOFAR  work  UNITS      remaining seconds
----- ------------------ ---------- ----- ------ ---------- --------- -------
   10 test application   test         360    900 seconds          542     361

SQL> /

                         target           total                  time elapsed
  SID OPNAME             descriptio SOFAR  work  UNITS      remaining seconds
----- ------------------ ---------- ----- ------ ---------- --------- -------
   10 test application   test         472    900 seconds          428     472

SQL>

2. 可以使用dbms_application_info的set module/action模块将我们的对应的trace信息进行过滤, 达到对某一块具体的sql执行语句的分析的功能^_^.
APPNAME mod='test' mh=2662839991 act='first step' ah=3692506248
=====================
PARSING IN CURSOR #1 len=68 dep=0 uid=57 oct=42 lid=57 tim=195361146957 hv=1346161232 ad='7b37bf68'
alter session set events '10046 trace name context forever,level 12'
END OF STMT
EXEC #1:c=0,e=169,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=195361129557
WAIT #1: nam='SQL*Net message to client' ela= 9 p1=1111838976 p2=1 p3=0
WAIT #1: nam='SQL*Net message from client' ela= 7736508 p1=1111838976 p2=1 p3=0
=====================
PARSING IN CURSOR #1 len=18 dep=0 uid=57 oct=3 lid=57 tim=195368885407 hv=1333943659 ad='7b3732ac'
select * from dual
END OF STMT
PARSE #1:c=0,e=239,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=195368885391
BINDS #1:
EXEC #1:c=0,e=247,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=195368886634
WAIT #1: nam='SQL*Net message to client' ela= 9 p1=1111838976 p2=1 p3=0
FETCH #1:c=0,e=86,p=0,cr=1,cu=0,mis=0,r=1,dep=0,og=4,tim=195368887026
WAIT #1: nam='SQL*Net message from client' ela= 639 p1=1111838976 p2=1 p3=0
FETCH #1:c=0,e=6,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,tim=195368888354
WAIT #1: nam='SQL*Net message to client' ela= 5 p1=1111838976 p2=1 p3=0
*** 2005-04-19 23:19:21.116
WAIT #1: nam='SQL*Net message from client' ela= 18042391 p1=1111838976 p2=1 p3=0
STAT #1 id=1 cnt=1 pid=0 pos=1 obj=31802 op='INDEX FULL SCAN SYS_IOT_TOP_31801 '
=====================
PARSING IN CURSOR #1 len=68 dep=0 uid=57 oct=47 lid=57 tim=195386948246 hv=480137194 ad='7b1ffae0'
BEGIN dbms_application_info.set_module('test','second step'); END;
END OF STMT
PARSE #1:c=10014,e=9811,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=4,tim=195386948228
BINDS #1:
APPNAME mod='test' mh=2662839991 act='second step' ah=1111681585
EXEC #1:c=0,e=704,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=4,tim=195386950096
WAIT #1: nam='SQL*Net message to client' ela= 9 p1=1111838976 p2=1 p3=0
WAIT #1: nam='SQL*Net message from client' ela= 499 p1=1111838976 p2=1 p3=0
.................
.................
这样我们就可以使用sed/awk编辑对应的trace脚本分析对应模块内的sql语句的具体的trace信息, 将对我们没有用户的trace信息过滤出去^_^.

3. 使用dbms_application_info的set_client_info/module/action作为存储系统全局变量的方式..

SQL> create or replace function get_deptno return number is
  2    v_deptno number;
  3    s_deptno varchar2(20);
  4  begin
  5    dbms_application_info.read_client_info(s_deptno);
  6    v_deptno := to_number(s_deptno);
  7    return v_deptno;
  8  end;
  9  /

Function created.

SQL> create or replace view v_emp as
  2  select * from emp where deptno = get_deptno;

View created.

SQL> select * from v_emp;

no rows selected

SQL> exec dbms_application_info.set_client_info('20');

PL/SQL procedure successfully completed.

SQL> select * from v_emp;

EMPNO ENAME      JOB         MGR HIREDATE         SAL       COMM     DEPTNO
----- ---------- --------- ----- --------- ---------- ---------- ----------
 7369 SMITH      CLERK      7902 17-DEC-80        800                    20
 7566 JONES      MANAGER    7839 02-APR-81       2975                    20
 7788 SCOTT      ANALYST    7566 19-APR-87       3000                    20
 7876 ADAMS      CLERK      7788 23-MAY-87       1100                    20
 7902 FORD       ANALYST    7566 03-DEC-81       3000                    20

SQL>

4. dbms_application_info的最基本的功能, 可以告诉我们系统正在做什么, 我们可以通过v$session直接定位相关的module/action的对应的session.
SQL> @sessinfo.sql
SQL> col sid format 9999
SQL> col username format a10
SQL> col client_info format a15
SQL> col module format a15
SQL> col action format a15
SQL> select a.sid,a.username,a.client_info,a.module,a.action
  2  from v$session a,v$mystat b
  3  where a.sid = b.sid
  4  and rownum <= 1
  5  /

  SID USERNAME   CLIENT_INFO     MODULE          ACTION
----- ---------- --------------- --------------- ---------------
   10 SCOTT                      SQL*Plus

SQL> set echo off
SQL> exec dbms_application_info.set_client_info('jametong');

PL/SQL procedure successfully completed.

SQL> exec dbms_application_info.set_module('test','step one');

PL/SQL procedure successfully completed.

SQL> @sessinfo.sql

  SID USERNAME   CLIENT_INFO     MODULE          ACTION
----- ---------- --------------- --------------- ---------------
   10 SCOTT      jametong        test            step one

SQL> exec dbms_application_info.set_module('test','step two');

PL/SQL procedure successfully completed.

SQL> @sessinfo.sql

  SID USERNAME   CLIENT_INFO     MODULE          ACTION
----- ---------- --------------- --------------- ---------------
   10 SCOTT      jametong        test            step two

SQL>


jametong 发表于:2005.04.20 00:04 ::分类: ( Oracle tips ) ::阅读:(578次) :: 评论 (0)
===========================================================
how to user bind var with dbms_job
===========================================================
Subhash -- Thanks for the question regarding "DBMS_JOB -- how to pass parameters to the job", version 8.0.5
originally submitted on 11-Mar-2001 23:13 Eastern US time, last updated 11-Apr-2005 13:18Tom's latest followup | GOTO a Bookmarkable Page | Bottom
You Asked (Jump to Tom's latest followup)

Hi Tom

   I have one procedure execute_job with two in parameters
   (batchnumber and loaddate). Procedure as follows :-


create or replace procedure execute_job(batchnumber in number, Loaddate in
varchar2)
       is
        l_theCursor     integer default dbms_sql.open_cursor;
        l_status        integer;
        p_sql           varchar2(200);
        v_job           number;
        BEGIN
          p_sql  :='alter session set nls_date_format= ''dd-mon-yyyy
          hh24:mi:ss'' ';
          dbms_sql.parse(l_theCursor,p_sql,dbms_sql.native);
          l_status := dbms_sql.execute(l_theCursor);
          dbms_sql.close_cursor(l_theCursor);
          dbms_job.submit(v_job ,  'fileimportedi.LoadFileLater
          (batchnumber);', Loaddate, null);
          commit;
END;


My problem is :-

   when i execute my procedure with following parameters :-

                Execute execute_job(347,'07-mar-2001 19:10:10');

Error comes :-

ERROR at line 1:
ORA-06550: line 1, column 117:
PLS-00201: identifier 'BATCHNUMBER' must be declared
ORA-06550: line 1, column 93:
PL/SQL: Statement ignored
ORA-06512: at "SYS.DBMS_JOB", line 72
ORA-06512: at "SYS.DBMS_JOB", line 140
ORA-06512: at "WMS.EXECUTE_JOB2", line 13
ORA-06512: at line 1

If i changed my dbms_job.submit as follows :-
      dbms_job.submit(v_job ,  'fileimportedi.LoadFileLater(347);',
      Loaddate, null);

then it's run successfully(no error comes) and job successfully submitted in
user_jobs table.

+++

Can we pass batchnumber as  parameter for another packaged procedure or not ? if
yes then how?



Thanks

Subhash

 

 
and we said...

What you should do is to create a parameter table:

create table parameters
( jobid   number PRIMARY KEY,
  batch   number,
  <any other inputs here>
);

and you would then:

....
dbms_job.submit(v_job , 'fileimportedi.LoadFileLater(JOB);',loadDate );
insert into parameters(v_job,batchnumber);
......

Every job can have access to its job number as a parameter like that.  That
would be used to look up the relevant data.  The reason for doing this is so you
are submitting the SAME sql string over and over again to the job queue --

       fileimportedi.LoadFileLater(JOB);

and not:

        fileimportedi.LoadFileLater(1);
        fileimportedi.LoadFileLater(2);
        fileimportedi.LoadFileLater(3);

which would tend to trash your shared pool with lots of UNIQUE sql.

Your loadFileLater routine should delete from the parameter upon successful
completion or you could submit:

  'fileimportedi.LoadFileLater(job);
   declare
       l_job number default job;
   begin
       delete from parameter where jobid = l_job;
   end;'

which would do it automatically for you if loadfilelater succeeded (the delete
would be skipped if the job failed)


short of that, you would have to code:


dbms_job.submit(v_job , 
              'fileimportedi.LoadFileLater(' || batchNumber || ');',
               Loaddate, null);

but that, as i said, would generate UNIQUE sql for each job which is BAD.



 
   Reviews     
GOTO a page to Bookmark Review | Bottom | Top
DBMS_JOB  May 21, 2002
Reviewer:  Ruben  from Sanjose, CA

Hi,

I am trying to call a pl/sql procedure from a form, i want the form to unbind
after it makes the call to the pl/sql procedure as the procedure is huge and
takes a lot of time to execute, for this i want to call the procedure in a
DBMS_JOB.Please can you illustrate how to go about doing the same.(lets assume
that the procedure needed to be invoked is temp(a,b)).


Followup: 
declare
   l_job number;
begin
   dbms_job.submit( l_job, 'temp( ' || a || ',' || b || ');' );
   commit;
end;

is one way to do it.

If you plan on running temp lots with different inputs do this instead:

create table temp_parms( job_id number primary key, a number, b date );

declare
   l_job number;
begin
   dbms_job.submit( l_job, 'temp( JOB );' );
   insert into temp_parms( l_job, a, b );
   commit;
end;


and have TEMP query temp_parms by job_id -- which we passed in -- to get its
parameters (makes better use of binding and that is important)


jametong 发表于:2005.04.13 00:21 ::分类: ( Oracle tips ) ::阅读:(365次) :: 评论 (0)
===========================================================
Problem about small table
===========================================================
昨天出于无聊, 测试了一下关于Oracle9idual表的相关处理.

发现一个问题, 对于很小的表, 使用full table 桑蚕并不是最好的选择..:-)

SQL> create table dual_x(dummy varchar2(1) primary key);

Table created.

SQL> insert into dual_x values('X');

1 row created.
SQL> commit;

Commit complete.

SQL> select * from dual_x;

D                                                                              
-                                                                              
X                                                                              


Execution Plan
----------------------------------------------------------                     
   0      SELECT STATEMENT Optimizer=CHOOSE                                    
   1    0   TABLE ACCESS (FULL) OF 'DUAL_X'                                    

Statistics
----------------------------------------------------------                     
          0  recursive calls                                                   
          0  db block gets                                                     
          3  consistent gets                                                   
          0  physical reads                                                    
          0  redo size                                                         
        375  bytes sent via SQL*Net to client                                  
        503  bytes received via SQL*Net from client                            
          2  SQL*Net roundtrips to/from client                                 
          0  sorts (memory)                                                    
          0  sorts (disk)                                                      
          1  rows processed                                                    

使用普通的全表扫面, 一次全表扫面需要3个consistent read
SQL> /

D                                                                              
-                                                                              
X                                                                              


Execution Plan
----------------------------------------------------------                     
   0      SELECT STATEMENT Optimizer=CHOOSE                                    
   1    0   TABLE ACCESS (FULL) OF 'DUAL_X'                                    

Statistics
----------------------------------------------------------                     
          0  recursive calls                                                   
          0  db block gets                                                     
          3  consistent gets                                                   
          0  physical reads                                                    
          0  redo size                                                         
SQL> select /*+index_ffs(a)*/ * from dual_x a;

D                                                                              
-                                                                              
X                                                                              


Execution Plan
----------------------------------------------------------                     
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=41 Bytes=82)          
   1    0   INDEX (FAST FULL SCAN) OF 'SYS_C002610' (UNIQUE) (Cost=2 C         
          ard=41 Bytes=82)                                                     

Statistics
----------------------------------------------------------                     
         22  recursive calls                                                   
          0  db block gets                                                     
          5  consistent gets                                                   
          0  physical reads                                                    
          0  redo size                                                         

SQL> /

D                                                                              
-                                                                              
X                                                                              

Execution Plan
----------------------------------------------------------                     
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=41 Bytes=82)          
   1    0   INDEX (FAST FULL SCAN) OF 'SYS_C002610' (UNIQUE) (Cost=2 C         
          ard=41 Bytes=82)                                                     
                                                                               
Statistics
----------------------------------------------------------                     
          0  recursive calls                                                   
          0  db block gets                                                     
          3  consistent gets                                                   
          0  physical reads                                                    
          0  redo size                                                         
我修改这条语句的执行计划, 强制使用index fast full scan, 得到的结果是相同的, 还是3个consistent read.

我们来给这个表坐一下分析, 统计一下表/索引相关的信息.
SQL> analyze table dual_x compute statistics for table for all indexes;

Table analyzed.

SQL> select * from dual_x;

D                                                                              
-                                                                              
X                                                                              


Execution Plan
----------------------------------------------------------                     
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=2)            
   1    0   INDEX (FULL SCAN) OF 'SYS_C002610' (UNIQUE) (Cost=1 Card=1         
           Bytes=2)                                                            
                                                                               
Statistics
----------------------------------------------------------                     
          0  recursive calls                                                   
          0  db block gets                                                     
          1  consistent gets                                                   
          0  physical reads                                                    
          0  redo size                                                         

SQL> spool off
我们可以看到现在这个语句的执行计划为INDEX FULL SCAN, 对应的io为1个consistent read. 这是我们的这个小表的执行计划才是最优的.

由上面的例子, 我们可以得出两个结论.

1. 小表也需要优化, 特别是dual表, 每天使用的频率相当高, 这样调整之后, 可以给系统节约大量io读写.
2. 对于小表而言, 全表扫面不一定是最好的.:-)


之后, 我又对v$bh表做了一下查询, 得到下面的这个结果,
SQL> select index_name from ind where table_name = 'DUAL_X';

INDEX_NAME
------------------------------
SYS_C002610

SQL> select * from v$bh where objd = 31819;

     FILE#     BLOCK#     CLASS# STATU        XNC FORCED_READS FORCED_WRITES
---------- ---------- ---------- ----- ---------- ------------ -------------
LOCK_ELE LOCK_ELEMENT_NAME LOCK_ELEMENT_CLASS D T P S D N       OBJD        TS#
-------- ----------------- ------------------ - - - - - - ---------- ----------
         1      89425          4 xcur           0            0             0
00                                            Y N N N N N      31819          0

         1      89426          1 xcur           0            0             0
00                                            Y N N N N N      31819          0


SQL> select * from obj where object_name = 'SYS_C002610';

OBJECT_NAME
--------------------------------------------------------------------------------

SUBOBJECT_NAME                  OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE
------------------------------ ---------- -------------- ------------------
CREATED   LAST_DDL_ TIMESTAMP           STATUS  T G S
--------- --------- ------------------- ------- - - -
SYS_C002610
                                    31820          31820 INDEX
11-APR-05 11-APR-05 2005-04-11:22:25:18 VALID   N Y N


SQL> select * from v$bh where objd = 31820;

     FILE#     BLOCK#     CLASS# STATU        XNC FORCED_READS FORCED_WRITES
---------- ---------- ---------- ----- ---------- ------------ -------------
LOCK_ELE LOCK_ELEMENT_NAME LOCK_ELEMENT_CLASS D T P S D N       OBJD        TS#
-------- ----------------- ------------------ - - - - - - ---------- ----------
         1      89441          4 xcur           0            0             0
00                                            Y N N N N N      31820          0

         1      89442          1 xcur           0            0             0
00                                            Y N N N N N      31820          0

问题: 这个地方只有两条记录, 一个是segment header, 一个是segment data, 但是为什么会产生3个consistent read, 哪位大师能给我解释一下吗:-)

重启数据库之后, 再查询dual_x表, 得到以下的信息, 也就是select * from dual_x 只在v$bh中产生一条记录.
SQL> set autotrace on
SQL> select * from dual_x;

D
-
X


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=2)
   1    0   INDEX (FULL SCAN) OF 'SYS_C002610' (UNIQUE) (Cost=1 Card=1
           Bytes=2)





Statistics
----------------------------------------------------------
        171  recursive calls
          0  db block gets
         26  consistent gets
          2  physical reads
         60  redo size
        375  bytes sent via SQL*Net to client
        503  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          4  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL> /

D
-
X


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=2)
   1    0   INDEX (FULL SCAN) OF 'SYS_C002610' (UNIQUE) (Cost=1 Card=1
           Bytes=2)





Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          1  consistent gets
          0  physical reads
          0  redo size
        375  bytes sent via SQL*Net to client
        503  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL> select * from v$bh where objd = 31820;

     FILE#     BLOCK#     CLASS# STATU        XNC FORCED_READS FORCED_WRITES
---------- ---------- ---------- ----- ---------- ------------ -------------
LOCK_ELE LOCK_ELEMENT_NAME LOCK_ELEMENT_CLASS D T P S D N       OBJD        TS#
-------- ----------------- ------------------ - - - - - - ---------- ----------
         1      89442          1 xcur           0            0             0
00                                            Y N N N N N      31820          0




jametong 发表于:2005.04.11 22:22 ::分类: ( Oracle tips ) ::阅读:(381次) :: 评论 (0)
===========================================================
如何使用base64编码解构Oracle rowid信息
===========================================================
1. 先得到base64编码的处理函数.
http://www.experts-exchange.com/Databases/Oracle/Q_21370166.html
base64编码的函数包, 由以上地址下载所得.

Create Or Replace Package B64 Is
B64 Varchar2(64):='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
Function Base64_2Dec(Val Varchar2) Return Number;
Function Dec2_Base64(Val Number) Return Varchar2;
End B64;
/
Create Or Replace Package Body B64 Is
Function Base64_2Dec
(Val Varchar2)
Return Number Is
I Pls_Integer;
J Pls_Integer;
K Pls_Integer:=0;
N Pls_Integer;
V_Out Number(38):=0;
Begin
  N:=Length(B64);
  For I In Reverse 1..Length(Val) Loop
    J:=Instr(B64,Substr(Val,I,1))-1;
    If J <0 Then
      Raise_Application_Error(-20001,'Invalid Base 64 Number: '||Val);
    End If;
    V_Out:=V_Out+J*(N**K);
    K:=K+1;
  End Loop;
  Return V_Out;
End;

Function Dec2_Base64
(Val Number)
Return Varchar2 Is
V_In Number;
N Pls_Integer;
V_Out Varchar2(30):='';
Begin
  N:=Length(B64);
  V_In:=Trunc(Val);
  While (V_In>0) Loop
    V_Out:=Substr(B64,Mod(V_In,N)+1,1)||V_Out;
    V_In:=Trunc(V_In/N);
  End Loop;
  Return V_Out;
End;

End B64;
/


2. 使用base64解码函数直接解码Oracle Rowid得到Rowid所对应的相关信息:-)
SQL> conn scott/tiger
Connected.
SQL> ed aaa.sql

SQL> @aaa.sql
SQL> select rowid ,
  2          B64.Base64_2Dec(substr(rowid,1,6)) object_no ,
  3          B64.Base64_2Dec(substr(rowid,7,3)) rel_file_id,
  4          B64.Base64_2Dec(substr(rowid,10,6)) block_no,
  5          B64.Base64_2Dec(substr(rowid,16,3)) row_no
  6  from emp a
  7  where rownum <= 5
  8  /

ROWID               OBJECT_NO REL_FILE_ID   BLOCK_NO     ROW_NO
------------------ ---------- ----------- ---------- ----------
AAAHIFAABAAAUMSAAA      29189           1      82706          0
AAAHIFAABAAAUMSAAB      29189           1      82706          1
AAAHIFAABAAAUMSAAC      29189           1      82706          2
AAAHIFAABAAAUMSAAD      29189           1      82706          3
AAAHIFAABAAAUMSAAE      29189           1      82706          4


我们再根据对应的数据字典信息, 来确认上面得到的信息.

SQL> select object_id from obj where object_name = 'EMP';

 OBJECT_ID
----------
     29189

SQL> conn / as sysdba
Connected.
SQL> select owner,segment_name,file_id,block_id,blocks,relative_fno
  2  from dba_extents
  3  where segment_name = 'EMP'
  4  /

OWNER  SEGMENT_NAME    FILE_ID   BLOCK_ID     BLOCKS RELATIVE_FNO
------ ------------ ---------- ---------- ---------- ------------
SCOTT  EMP                   1      82705         16            1

SQL>

由于数据段的第一个block为段头(segment header), 实际的数据段从第二个block开始,即 82705 + 1 = 82706

3. 知道对应的记录的相关信息以后, 我们可以直接使用base64编码算法得到Oracle的Rowid
略!!


jametong 发表于:2005.04.07 23:12 ::分类: ( Oracle tips ) ::阅读:(717次) :: 评论 (0)
===========================================================
一个显示对应日期的日历的sql函数^_^.
===========================================================
出于无聊写了这个函数, 供大家赏玩.:-)

上次贴这个数据的时候, 忘记将对应的数据类型贴出来, 这里将他补齐.

create type DATABAK.date_obj as object (
    month varchar2(20),
    sun char(2),
    mon char(2),
    tue char(2),
    wed char(2),
    thu char(2),
    fri char(2),
    sat char(2)
);

create type DATABAK.date_obj_tab as table of date_obj;


function DATABAK.get_date_str(in_date in date default sysdate)
return date_obj_tab
pipelined
is
date_o date_obj := date_obj(to_char(in_date,'Month'),1,1,1,1,1,1,1);
begin
for rs in (
select
sum(case when date_str = 'sun' then date_d end) sun,
sum(case when date_str = 'mon' then date_d end) mon,
sum(case when date_str = 'tue' then date_d end) tue,
sum(case when date_str = 'wed' then date_d end) wed,
sum(case when date_str = 'thu' then date_d end) thu,
sum(case when date_str = 'fri' then date_d end) fri,
sum(case when date_str = 'sat' then date_d end) sat
from (
select to_number(to_char(date_d,'dd')) date_d,to_char(date_d,'dy') date_str,
to_number(to_char(date_d,'ddd')) - to_number(to_char(date_d,'d')) date_w
from (
select trunc(date_d)+rownum - 1 date_d
from dba_objects a,(
select trunc(in_date,'mm') date_d from dual
) b
where rownum <= to_number(to_char(last_day(date_d),'dd'))
)
)
group by date_w
) loop
date_o.sun := rs.sun;
date_o.mon := rs.mon;
date_o.tue := rs.tue;
date_o.wed := rs.wed;
date_o.thu := rs.thu;
date_o.fri := rs.fri;
date_o.sat := rs.sat;
pipe row (date_o);
end loop;
return;
end;

function DATABAK.get_date_str(in_date in date default sysdate)
return date_obj_tab
pipelined
is
date_o date_obj := date_obj(to_char(in_date,'Month'),1,1,1,1,1,1,1);
begin
for rs in (
select
sum(case when date_str = 'sun' then date_d end) sun,
sum(case when date_str = 'mon' then date_d end) mon,
sum(case when date_str = 'tue' then date_d end) tue,
sum(case when date_str = 'wed' then date_d end) wed,
sum(case when date_str = 'thu' then date_d end) thu,
sum(case when date_str = 'fri' then date_d end) fri,
sum(case when date_str = 'sat' then date_d end) sat
from (
select to_number(to_char(date_d,'dd')) date_d,to_char(date_d,'dy') date_str,
to_number(to_char(date_d,'ddd')) - to_number(to_char(date_d,'d')) date_w
from (
select trunc(date_d)+rownum - 1 date_d
from dba_objects a,(
select trunc(in_date,'mm') date_d from dual
) b
where rownum <= to_number(to_char(last_day(date_d),'dd'))
)
)
group by date_w
) loop
date_o.sun := rs.sun;
date_o.mon := rs.mon;
date_o.tue := rs.tue;
date_o.wed := rs.wed;
date_o.thu := rs.thu;
date_o.fri := rs.fri;
date_o.sat := rs.sat;
pipe row (date_o);
end loop;
return;
end;


实例:

SQL> select * from table(get_date_str());

MONTH SU MO TU WE TH FR SA
-------------------- -- -- -- -- -- -- --
April 1 2
April 3 4 5 6 7 8 9
April 10 11 12 13 14 15 16
April 17 18 19 20 21 22 23
April 24 25 26 27 28 29 30

SQL> select * from table(get_date_str(sysdate-10));

MONTH SU MO TU WE TH FR SA
-------------------- -- -- -- -- -- -- --
March 1 2 3 4 5
March 6 7 8 9 10 11 12
March 13 14 15 16 17 18 19
March 20 21 22 23 24 25 26
March 27 28 29 30 31

SQL>


jametong 发表于:2005.04.07 16:37 ::分类: ( Oracle tips ) ::阅读:(491次) :: 评论 (5)
===========================================================
如何得到钱币的大写形式
===========================================================
今天在cnoug上看到一个朋友问, 如何将对应的数字转换成对应的大写字母, 所以想到了这个..
http://www.cnoug.org/viewthread.php?tid=53058

function        getBigMoneyStr(money In number) return varchar2 is
    tmp_str varchar2(20);
    money_str varchar2(20);
    val_j        varchar2(20);
    len_j        number;
    k                number;
    i                number;
    j                number;
  m       number;
    result    varchar2(40);
    type         my_type     is varray(20) of varchar2(4);
    num         constant     my_type := my_type('1','2','3','4','5','6','7','8','9','0');
    num_str constant     my_type := my_type('壹','贰','叁','肆','伍','陆','柒','捌','玖','零');
begin
    tmp_str := to_char(money * 100);
    len_j    := length(tmp_str);
    k := 11 - len_j;
    result := substr(tmp_str,1,1);
  m := 2;
    for i in 1..len_j  loop
    begin
        if k = 1 then money_str := '仟';
        elsif k = 2 then money_str :='佰';
        elsif k = 3 then money_str :='拾';
        elsif k = 4 then money_str :='万';
        elsif k = 5 then money_str :='仟';
        elsif k = 6 then money_str :='佰';
        elsif k = 7 then money_str :='拾';
        elsif k = 8 then money_str :='元';
        elsif k = 9 then money_str :='角';
        elsif k = 10 then money_str :='分';
    end if;

        k := k + 1;
    m := i + 1;
        val_j := nvl(substr(tmp_str,m,1),'');
        if len_j = m + 5 and substr(result,length(result),1) = '0' then
            result := substr(result,0,length(result)-1) ||'万0';
        end if;

        if len_j = m + 1 and substr(result,length(result) ,1) = '0' then
            result := substr(result,0,length(result)-1) ||'元0';
        end if;

        if val_j = '0' and substr(result,length(result),1) = '0' then
            goto TheEnd;
        end if;

        if substr(result,length(result) ,1) != '0' then
            result := result || money_str;
        end if;

        result := result || val_j ;

    <<TheEnd>>
    null;
  end;
    end loop;
--除去最后的0
    for j in 1..3 loop
        begin
      if substr(result,length(result),1) = '0' then
              result := substr(result,0,length(result) -1);
      end if;
        end;
    end loop;
    for i in 1..10 loop
        result := replace(result,num(i),num_str(i));
    end loop;

    return result||'整';
end;
/

例子


SQL> select getBigMoneyStr(2124324.34) from dual;

GETBIGMONEYSTR(2124324.34)
--------------------------------------------------------------------

贰佰壹拾贰万肆仟叁佰贰拾肆元叁角肆分整

SQL> select getBigMoneyStr(2129874.34) from dual;

GETBIGMONEYSTR(2129874.34)
--------------------------------------------------------------------

贰佰壹拾贰万玖仟捌佰柒拾肆元叁角肆分整

SQL>



jametong 发表于:2005.04.07 16:27 ::分类: ( Oracle tips ) ::阅读:(653次) :: 评论 (1)
===========================================================
使用with处理报表处理一例
===========================================================
with sum_obj as(
    select
        nvl(county_code,'合计') county_code,
        sum(case when color_flag = 0 then objective else 0 end) t_red,
        sum(case when color_flag = 3 then objective else 0 end) t_yellow,
        sum(objective) t_total,
        sum(case when kind = 1 and color_flag = 0 then objective else 0 end) a_red,
        sum(case when kind = 1 and color_flag = 3 then objective else 0 end) a_yellow,
        sum(case when kind = 1 then objective else 0 end) a_total,
        sum(case when kind = 2 and color_flag = 0 then objective else 0 end) b_red,
        sum(case when kind = 2 and color_flag = 3 then objective else 0 end) b_yellow,
        sum(case when kind = 2 then objective else 0 end) b_total
    from tjw_core_bind_objective
    group by rollup(county_code)
  ),
  sum_real as (
      select /*+full(b)*/
        nvl(county_code,'合计') county_code,
        sum(case when b.march_flag = 0 then 1 else 0 end) t_red,
        sum(case when b.march_flag = 3 then 1 else 0 end) t_yellow,
        sum(1) t_total,
        sum(case when b.kind = 1 and b.march_flag = 0 then 1 else 0 end) a_red,
        sum(case when b.kind = 1 and b.march_flag = 3 then 1 else 0 end) a_yellow,
        sum(case when b.kind = 1 then 1 else 0 end) a_total,
        sum(case when b.kind = 2 and b.march_flag = 0 then 1 else 0 end) b_red,
        sum(case when b.kind = 2 and b.march_flag = 3 then 1 else 0 end) b_yellow,
        sum(case when b.kind = 2 then 1 else 0 end) b_total
    from tjw_core_bind_final a,tjw_core_bind_5 b
    where a.user_id = b.user_id
    and a.color_flag in (1,2)
    and b.march_flag in (0,3)
    group by rollup(county_code)
  )
  select '所有用户',a.county_code,
      a.t_red,a.t_red - b.t_red,trunc((a.t_red - b.t_red)/a.t_red * 100, 2 ) t_red_ratio,
    a.t_yellow,a.t_yellow - b.t_yellow,trunc((a.t_yellow - b.t_yellow)/a.t_yellow * 100, 2 ) t_yellow_ratio,
    a.t_total,a.t_total - b.t_total,trunc((a.t_total - b.t_total)/a.t_total * 100, 2 ) t_total_ratio
  from sum_obj a,sum_real b
  where a.