关于cursor的rowcount

前几天写了一个procedure,然后job调用它,通过dblink从第三方数据库获取数据.写完手动运行了一次,一切正常数据也取到了,但是第二天上班,我却发现了奇怪现象(注job晚上1点执行),我的数据不见了。为此我还调查了,谁动了我的数据,结果是nobody.那结论只有一个问题出现在那个procedure身上了.

procedure主要有两个功能1.从第三方数据库表中取数据;2.对于取来的数据执行完插入之后,要将其重复的数据全部删除(注意是全部删除而不是删掉一条留一条),正是这个两个功能造成我的数据没有了。现将的sql语句贴出来,分析一下

 

create or replace procedure test_proc is

 

    p_lasttime_stamp date;

    --游标export_time_cur获取最后导数据的时间
   cursor export_time_cur is   .....; 

 

  --从上次读取数据的时间点开始再读取数据
     cursor export_data_cur is .....
                    where time_stamp> p_lasttime_stamp;
--删除重复记录的游标
  cursor repeat_rec_cur 
      is  ......;

  begin

  --获取上次导入的时间
    open export_time_cur;
           if export_time_cur%rowcont=0 then

               --则向记录拉取数据的时间戳表中插入一条记录来记录拉取时间戳
            insert into ...

 

                  commit;
           p_lasttime_stamp:=to_date('2000-01-01','yyyy-MM-dd'); --从这个日期开始取数据

   else

        fetch export_time_cur  into p_lasttime_stamp;
       end if;
    close export_time_cur;

  --现在从p_lasttime_stamp开始读这次的数据,全部读过来
  for rec in export_data_cur loop

     --执行处理及插入
        end loop;
 commit;
 
--删除重复的记录
for rec in repeat_rec_cur loop  

--执行数据删除  
end loop;
commit;

           --更新导数据的最后的时间戳
       update .....         commit;


      EXCEPTION
           WHEN OTHERS THEN
              raise_application_error(......);

end;
/

这个procedure看起起功能会完善呀,但是问题主要出现在export_time_cur 这个游标上,游标的

%ROWCOUNT属性用来返回迄今为止已经从游标中提取的记录数目。
在游标或游标变量被打开而没有被执行FETCH(提取)之前,%ROWCOUNT的值为0;
这以后,%ROWCOUNT的值就是从结果集中提取出来的记录数,FETCH每成功执行一次
%ROWCOUNT的值就增加一个.

所以现在再来分析一下我写的procedure,就会发现问题,无论何时执行这个procedure,它的拉取数据日期都是

 p_lasttime_stamp:=to_date('2000-01-01','yyyy-MM-dd');

然后拉取来的数据就会有大量的重复,如果从job上次执行到下一次执行(第二天早上1点),第三方数据库没有更新一条记录,则这两次取到的数据完全一样(现在是2011年了),而后面的我的procedure则要干的一件事就是干掉自本次拉取的重复数据,这样阴差阳错,拉过来的数据则会被全部干掉,所以表中一条数据也没有了.所以知道问题的所在说可以修改了.所以这就是知其然而不知其所以然的我犯的一个错,要记住下次不能再犯了,现将cursor的其他属性也罗列在此:(这里用到的表是我业务数据库表)

--1。%FOUND属性

/**当游标或游标变量被打开且在执行FETCH语句之前时,
%FOUND为NULL。其后,如果最后的FETCH语句返回一行记录,
则%FOUND为TRUE,如果FETCH语句没有返回记录,
则%FOUND为FALSE。如下例所示。

*/
-- Created on 2011/4/14 by XIAO-CAINIAO
declare
  p_steward_name varchar2(20);
  cursor steward_cur is
    select s.steward_name from steward s where s.steward_id = '1194';
begin

  open steward_cur;
  if steward_cur%found is null then
    dbms_output.put_line('当前游标mycursor的属性%FOUND为NULL!');
  end if;
  fetch steward_cur
    into p_steward_name;
  if steward_cur%FOUND then
 
    dbms_output.put_line('p_steward_name= ' || p_steward_name);
  else
    dbms_output.put_line('没有从游标mycursor中提取出数据!');
  end if;
  close steward_cur;

end;
/

 

 

--2。%ISOPEN
/**
当游标或游标变量被打开时,%ISOPEN属性为TRUE,
否则%ISOPEN属性为FALSE。
我们可以用这个属性来判断一个游标是否已被打开。
*/
-- Created on 2011/4/14 by XIAO-CAINIAO
declare

  p_steward_name varchar2(20);
  cursor steward_cur is
    select s.steward_name from steward s where s.steward_id = '1194';

begin
open steward_cur;
if steward_cur%ISOPEN then

dbms_output.put_line('cursor mycursor is already opened!');

else

open steward_cur;

end if;

  fetch steward_cur
    into p_steward_name;

close steward_cur;

dbms_output.put_line('p_steward_name' ||' 在 '|| p_steward_name);

end;
    --与下例比较注意其中的区别
  
declare
  p_steward_name varchar2(20);
  cursor steward_cur is
    select s.steward_name from steward s where s.steward_id = '1194';
begin
 --open steward_cur;
if steward_cur%ISOPEN then
dbms_output.put_line('cursor mycursor is already opened!');
else

open steward_cur;

end if;

  fetch steward_cur
    into p_steward_name;

close steward_cur;

dbms_output.put_line('p_steward_name' ||' 在 '|| p_steward_name);

end;

 

 

--3。%NOTFOUND
/**
%NOTFOUND属性和%FOUND属性正好相反。当游标或游标变量被打开但是在执行FETCH语句之前时,
%NOTFOUND也是为NULL。其后,如果最后的FETCH语句返回一行记录,
则%NOTFOUND为FALSE,如果FETCH语句没有返回记录,则%NOTFOUND为TRUE。
该属性在循环从一个游标中提取出数据时很有作用。如下面的例子。
*/
declare
  p_steward_name varchar2(20);
  cursor steward_cur is
    select s.steward_name from steward s where s.steward_id = '1194';
  v_classes varchar2(30);
begin

  v_classes := '运输98-12';

  open steward_cur;
  loop
    fetch steward_cur
            into p_steward_name;
             dbms_output.put_line(p_steward_name || ' 在 ' || v_classes); 

        exit when steward_cur%NOTFOUND; 
  end loop;

  close steward_cur;

end;
/

 

对于这个例子,你可以会发现dbms_output.put_line(p_steward_name || ' 在 ' || v_classes); 这个输出2次,而steward_cur却只有一条记录,这是为什么呢?这个问题也让我纳了很长时间的闷,直到上次在oracle培训问了teacher才解开,这个是因为pl/sql没有即时flush,可以通过下例来测试一下:

begin
 for i in 1..10 loop
 dbms_output.put_line('A');
 dbms_lock.sleep(1);--休息1秒钟
 end loop;
 
end;
/

在sql/plus下执行,并没有一行一行输出,而是等了10秒一下子输出10行.

你可能感兴趣的:(oracle)