重温 oracle存储过程和定时器

时间:2020-11-26 23:30:51

好长时间没写过存储过程了,这几天项目中刚好要用到存储过程,没想到一点都记不起来了,又翻了翻以前记录的资料,才算完成。


--创建一个存储过程  传入两个参数, in 表示传入的参数,返回的参数用out表示

create or replace procedure count1(starttime in varchar2,endtime in varchar2 ) as
-- 用游标接收数据
cursor mycu is select t1.* ,b1.name
from (
select p.duty ,sum(p.invest) as num_ztz ,sum(b.accumulatinvest) as num_ljwc,sum(b.planinvest) as num_dnjh ,sum(b.completedinvest) as num_dnwc ,
sum(b.monthinvest) as num_dywc , count(p.id) as lj_xm,
count(case when (s2.name='已投产' or s2.name='已开工' or s2.name='已竣工' or s2.name='试生产') then p.id end ) as lj_kg ,
count(case when s.name='新建' then p.id end ) as xj_xm ,
count(case when s.name='新建' and (s2.name='已投产' or s2.name='已开工' or s2.name='已竣工' or s2.name='试生产') then p.id end ) as xj_kg,
count(case when s.name='续建' then p.id end ) as xjs_xm,
count(case when s.name='续建' and (s2.name='已投产' or s2.name='已开工' or s2.name='已竣工' or s2.name='试生产') then p.id end ) as xjs_kg
from pro_project p left join pro_build b on b.proid=p.id left join pro_basevalue s on (s.id=p.protype ) left join pro_basevalue s2 on s2.id=p.prostatus left join pro_basevalue s3 on s3.id=p.duty
where delstate is null and s.name!='在谈' and s.name!='后续' and to_char(p.dynamictime,'yyyy-MM')>=starttime and to_char(p.dynamictime,'yyyy-MM')<=endtime
group by p.duty,s3.priority order by s3.priority
) t1 left join pro_basevalue b1 on b1.id=t1.duty ;
per_ndwc_ number(16,4):=0;
per_wcztz_ number(16,4):=0;
lj_kgl_ number(16,4):=0;
xj_kgl_ number(16,4):=0;
xjs_kgl_ number(16,4):=0;
begin
  for cu in mycu   --  开始循环    还有其它的循环方式,个人觉得这种比较方便
loop
if cu.num_dnjh!=0 then
per_ndwc_:=cu.num_dnwc/cu.num_dnjh;
end if;
if cu.num_ztz!=0 then
per_wcztz_:=cu.num_ljwc/cu.num_ztz;
end if;
if cu.lj_xm!=0 then
lj_kgl_:=cu.lj_kg/cu.lj_xm;
end if;
if cu.xj_xm!=0 then
xj_kgl_:=cu.xj_kg/cu.xj_xm;
end if;
if cu.xjs_xm!=0 then
xjs_kgl_:=cu.xjs_kg/cu.xjs_xm;
end if;
insert into pro_statement(id,num_ztz,num_ljwc,num_dnjh,num_dnwc,num_dywc,per_ndwc,per_wcztz,
lj_xm,lj_kg,lj_kgl,xj_xm,xj_kg,xj_kgl,xjs_xm,xjs_kg,xjs_kgl,create_time,data_type,tname)
values(seq_pro_statement.nextval,cu.num_ztz,cu.num_ljwc,cu.num_dnjh,cu.num_dnwc,cu.num_dywc,per_ndwc_,per_wcztz_,
cu.lj_xm,cu.lj_kg,lj_kgl_,cu.xj_xm,cu.xj_kg,xj_kgl_,cu.xjs_xm,cu.xjs_kg,xjs_kgl_,sysdate,'1',cu.name);
end loop;
end;

-- 同样也是一个存储过程,返回两个参数,一个是游标类型,一个数据列数(因为列数是动态的,在resultset中取值时无法确定有几列)

create or replace procedure execByJb_type(synch_cursor out synch.synch_cursor,column_count out number) as
cursor mycu is select jb_type from rep_synch group by jb_type ;
jb_type_ varchar2(50):='';
sql_ varchar2(2000):=' select to_char(to_date(sj_time,''yyyy-mm-dd hh24:mi:ss''),''mm'') 月份 ';
begin
for cu in mycu
loop
jb_type_:=cu.jb_type ;
column_count:=mycu%rowcount;
sql_:=sql_||', count(case when jb_type='''||jb_type_||''' then id end) '||jb_type_;
end loop;
sql_:=sql_||',count(id) 总计 from rep_synch group by to_char(to_date(sj_time,''yyyy-mm-dd hh24:mi:ss''),''mm'') order by to_char(to_date(sj_time,''yyyy-mm-dd hh24:mi:ss''),''mm'') ';
open synch_cursor for sql_;
end;

//java代码中调用存储过程

CallableStatement cs=null;
try {
   
  String sql="{ call pro(?,?) }";
cs=conn.prepareCall(sql);
//调用存储过程,一共有两个返回值,第一个返回游标,第二个返回 列数

cs.registerOutParameter(1,oracle.jdbc.OracleTypes.CURSOR);
  cs.registerOutParameter(2,oracle.jdbc.OracleTypes.NUMBER);
result=cs.execute();

int count=cs.getBigDecimal(2).intValue();
rs=(ResultSet) cs.getObject(1);
ResultSetMetaData metaData=rs.getMetaData();
while (rs!=null&&rs.next()) {
Map<String,Object> map=new HashMap<String, Object>();
for (int i = 1; i <=count+2; i++) {
map.put(metaData.getColumnName(i), rs.getObject(i)); //以当前列名为key,当前值为value保存当前行 
columns.add(metaData.getColumnName(i)); //获取当前列的列名
}
list.add(map);//将一整行完整数据放入list中
}
}

//最终将列名与数据集都返回,在前台只需要循环就好了



--------------------------以下部分转自  http://www.cnblogs.com/mingforyou/archive/2012/06/06/2538063.html  写的很详细


declare

jobno number;

begin dbms_job.submit(

  jobno,--定时器ID,系统自动获得

  'PRC_INSERT;', --what执行的过程名

   sysdate,--next_date,定时器开始执行的时间,这样写表示立即执行

  'sysdate + 15/1440'--interval,设置定时器执行的频率,这样写每隔15分钟执行一次

);

commit;

end;



这里第一个参数是任务编号,系统自动赋值。也可以采用isubmit来手动指定

第二个参数是需要执行的任务过程,代码长的话,可以将它写到一个存储过程里,再放到里面调用,比如'pro_test;' (pro_test假定为一个存储过程名)

第三个参数是,自动任务第一次执行的时间,如果需要它立即执行,则使用sysdate

最后一个参数,系统根据该参数的值指定下一次的执行时间。





declare

jobno

number;

begin

dbms_job.remove(45);

commit;

end;



exec dbms_job.remove(83);--删除一个定时器
exec dbms_job.run(84);--运行一个定时器
exec DBMS_JOB.BROKEN(83,SYS.DIUTIL.INT_TO_BOOL(1));--停止一个定时器
exec DBMS_JOB.INTERVAL(84, 'sysdate + 60/1440');--改变一个定时器的执行频率成每隔一小时执行一次


select * from user_jobs;——查看调度任务

select * from dba_jobs_running;——查看正在执行的调度任务

select * from dba_jobs;——查看执行完的调度任务





定时器的参数说明:

myjob参数是由Submit()过程返回的binary_ineger。这个值用来唯一标识一个工作;

what参数是将被执行的PL/SQL代码块,这里指的是一个存储过程,注意名字后面的分号;

next_date参数指识何时将运行这个工作。写Job的时候可以不指定该值;

interval参数何时这个工作将被重执行。

关于interval的设置,参考以下几个例子:

1、 每分钟执行

Interval => TRUNC(sysdate,’mi’) + 1 / (24*60)

2、 每天定时执行

例如:每天的凌晨2点执行

Interval => TRUNC(sysdate) + 1 +2 / (24)

3、 每周定时执行

例如:每周一凌晨2点执行

Interval => TRUNC(next_day(sysdate,2))+2/24 --星期一,一周的第二天

4、 每月定时执行

例如:每月1日凌晨2点执行

Interval =>TRUNC(LAST_DAY(SYSDATE))+1+2/24

5、 每季度定时执行

例如每季度的第一天凌晨2点执行

Interval => TRUNC(ADD_MONTHS(SYSDATE,3),'Q') + 2/24

6、 每半年定时执行

例如:每年7月1日和1月1日凌晨2点

Interval => ADD_MONTHS(trunc(sysdate,'yyyy'),6)+2/24

7、 每年定时执行

例如:每年1月1日凌晨2点执行

Interval =>ADD_MONTHS(trunc(sysdate,'yyyy'),12)+2/24