几种使用动态SQL做游标的总结

--个人网站同步更新 www.dbaleading.com

前些天,有个朋友问我关于动态SQL做游标的题,他有一个存储过程,使用了动态SQL做游标,可是怎么调试都没有结果出来,请我帮忙看看.等他把文件发给我一看,呵呵,他这个动态SQL是类似这么用的:

DECLARE
  V_ID NUMBER ;
  v_1  NUMBER ;
  CURSOR CUR_1 IS
    SELECT ID FROM TEST WHERE ID = V_ID ;
BEGIN
   V_ID := 3 ;
   OPEN cur_1 ;
   LOOP
     FETCH cur_1
       INTO v_1 ;
     EXIT WHEN cur_1%NOTFOUND;
     DBMS_OUTPUT.PUT_LINE(v_1);
   END LOOP;
   CLOSE cur_1;
END;

    看起来没什么问题,可是在他的机器上就是调试不出结果,我把V_ID给他换成常量后,马上就有返回值,同时,我在我自己的库上做DEMO测试,也是可以通过的,这就奇怪了,他的数据库也是9206的,而且也不报错,就是没有output,邪门了,呵呵,再试,给他换一种写法,变成下面这样:
DECLARE
   v_1 NUMBER ;
   v_2 NUMBER ;
   CURSOR cur_2(v_id NUMBER ) IS
     SELECT ID FROM test2 WHERE ID=v_id;
BEGIN
   v_1 := 1 ;
   OPEN cur_2(v_1) ;
   LOOP
     FETCH cur_2
       INTO v_2 ;
     EXIT WHEN cur_2%NOTFOUND;
     DBMS_OUTPUT.PUT_LINE(v_2);
   END LOOP;
   CLOSE cur_2;
END;

    这样总没问题了吧,我可是找了9i和10g几套库测试过都通过的呵,给他再测试,还是没结果,这下子郁闷了,这时候已经是夜里12点了,跟他卯上了,再换写法,就不信这个邪了,上面的两种写法都是基于PL/SQL语法的,下面我用DBMS_SQL这个ORACLE提供的包来做,虽然麻烦点,只要有用,咱就试试吧,改成下面这样:
declare
  v_curId   integer;
  v_sql     varchar2(1000);
  v_well_id varchar2(100);
  v_ret     number(3);
  v_id      varchar2(10);
begin
  v_id  := 'abcdefgh';
  v_sql := 'SELECT ID FROM TEST3 WHERE ID = LOWER('||chr(39)||v_id||chr(39)||')';
  v_curId := DBMS_SQL.OPEN_CURSOR;
  DBMS_SQL.PARSE(v_curId, v_Sql, DBMS_SQL.V7);
  DBMS_SQL.DEFINE_COLUMN(v_curId, 1, v_well_id, 128);
  v_ret := DBMS_SQL.EXECUTE(v_curId);

  loop
    if DBMS_SQL.FETCH_ROWS(v_curId) = 0 then
      exit;
    end if;
    DBMS_SQL.COLUMN_VALUE(v_curId, 1, v_well_id);
    DBMS_OUTPUT.PUT_LINE(v_well_id);
  end loop;
  DBMS_SQL.CLOSE_CURSOR(v_curid);
end;

    哈哈,这次oracle老实了,在他那边可以返回结果集了,OK,就这样,让朋友按照这个方法去改存储过程了,夜也深了,没精力再折腾了,就这么了结了, 估计是因为他那边有些选件没装吧,后来因为我自己没环境,没再做更深的研究,上面几种,就当是使用动态SQL做游标的总结吧,呵呵.