查看: 4453|回复: 6

[PL/SQL] 请问一下一个语句为什么会进入死循环

[复制链接]
论坛徽章:
0
跳转到指定楼层
1#
发表于 2011-6-5 23:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在一个forall的语句中:
  OPEN CUR_MEMBER_EXT_TMP;
  LOOP
    BEGIN
      FETCH CUR_MEMBER_EXT_TMP BULK COLLECT
        INTO V_ADA_ARRAY, V_DTE1_ARRAY, V_DTE2_ARRAY, V_DTE3_ARRAY, V_NUM1_ARRAY, V_NUM2_ARRAY, V_C1_ARRAY, V_C2_ARRAY LIMIT V_LIMIT_NUMBERS;
   
      IF V_ADA_ARRAY.COUNT = 0 THEN
        EXIT;
      END IF;
   
      FORALL i in V_ADA_ARRAY.FIRST .. V_ADA_ARRAY.LAST
        UPDATE MEMBER
           SET PIN_LVL_AFT_APR = GetQVSPinCode(V_ADA_ARRAY(i), V_GRADING_D);
      COMMIT;
    END;
  END LOOP;
  CLOSE CUR_MEMBER_EXT_TMP;


运行到update的部分,引用了一个函数GetQVSPinCode

我用plsql调试的时候,不断在这个函数中执行,而且传入的参数都是V_ADA_ARRAY(i)的第一个值,i的值没有增加,调试的过程就是不断在函数里面传入同一个值V_ADA_ARRAY(1),,return自然也是一样的。

我看了很久,都想不到为什么i不会增加,而且函数GetQVSPinCode为什么不退出来。恳请各位指点一下,谢谢。

GetQVSPinCode函数具体代码如下:

create or replace function GetQVSPinCode(V_ADA       in NUMBER,
                                         V_GRADING_D IN NUMBER) return CHAR as
  /*
   * 获取QVS审核职级
   * Author: cobe
   * Date:   20110526
  */

  V_PIN CHAR(1);

  --存放上一年度信息
  V_YEAR1    NUMBER(4);
  V_PIN1     CHAR(1);
  V_GRADING1 NUMBER(2);
  --存放本年度信息
  V_YEAR2    NUMBER(4);
  V_PIN2     CHAR(1);
  V_GRADING2 NUMBER(2);

  V_CNT NUMBER(1);

  TYPE rc IS REF CURSOR; --定义游标类型
  cur rc; --定义游标变量

begin
  V_PIN := NULL;
  V_CNT := 0;

  --查询最新两年数据
  OPEN CUR FOR 'SELECT A.FIS_YEAR,A.PIN,B.PIN_GRADING FROM (SELECT ADA, FIS_YEAR, PIN, ROWNUM IROW FROM QVS_AUDIT_DTL WHERE ADA=:ADA ORDER BY FIS_YEAR DESC) A,PIN_TABLE B WHERE A.IROW<3 AND A.PIN=B.PIN_CDE'
    USING V_ADA;
  LOOP
    FETCH cur
      INTO V_YEAR1, V_PIN1, V_GRADING1;
    EXIT WHEN cur%NOTFOUND;
  
    --若为第一条记录,则为最新年度信息,赋值到变量2中  
    V_CNT := V_CNT + 1;
    IF V_CNT = 1 THEN
      V_YEAR2    := V_YEAR1;
      V_PIN2     := V_PIN1;
      V_GRADING2 := V_GRADING1;
    END IF;
  END LOOP;
  CLOSE CUR;

  IF V_CNT = 1 THEN
    V_PIN := V_PIN2;
  ELSIF V_CNT = 2 THEN
    --若上一年职级为高级主任或以上,则取去年与今年较大职级
    IF V_GRADING1 >= V_GRADING_D AND V_GRADING1 > V_GRADING2 THEN
      V_PIN := V_PIN1;
    ELSE
      --否则取今年职级
      V_PIN := V_PIN2;
    END IF;
  END IF;

  return V_PIN;
exception
  when others then
    return null;
end;
论坛徽章:
51
ITPUB十周年纪念徽章
日期:2011-11-01 16:25:22铁扇公主
日期:2012-02-21 15:03:13最佳人气徽章
日期:2012-03-13 17:39:18ITPUB季度 技术新星
日期:2012-05-22 15:10:11ITPUB 11周年纪念徽章
日期:2012-10-09 18:13:332013年新春福章
日期:2013-02-25 14:51:24ITPUB社区12周年站庆徽章
日期:2013-08-12 09:34:36itpub13周年纪念徽章
日期:2014-09-28 10:55:55
2#
发表于 2011-6-6 09:40 | 只看该作者
OPEN CUR FOR 'SELECT A.FIS_YEAR,A.PIN,B.PIN_GRADING FROM (SELECT ADA, FIS_YEAR, PIN, ROWNUM IROW FROM QVS_AUDIT_DTL WHERE ADA=:ADA ORDER BY FIS_YEAR DESC) A,PIN_TABLE B WHERE A.IROW<3 AND A.PIN=B.PIN_CDE'
    USING V_ADA;
  LOOP
    FETCH cur
      INTO V_YEAR1, V_PIN1, V_GRADING1;
    EXIT WHEN cur%NOTFOUND;
  
    --若为第一条记录,则为最新年度信息,赋值到变量2中  
    V_CNT := V_CNT + 1;
    IF V_CNT = 1 THEN
      V_YEAR2    := V_YEAR1;
      V_PIN2     := V_PIN1;
      V_GRADING2 := V_GRADING1;
    END IF;
  END LOOP;
  CLOSE CUR;

PL/SQL写得很少~但觉得是这个循环有问题导致你出不来~单独执行下这个看看?

使用道具 举报

回复
论坛徽章:
0
3#
 楼主| 发表于 2011-6-6 11:21 | 只看该作者
原帖由 iori809 于 2011-6-6 09:40 发表
OPEN CUR FOR 'SELECT A.FIS_YEAR,A.PIN,B.PIN_GRADING FROM (SELECT ADA, FIS_YEAR, PIN, ROWNUM IROW FROM QVS_AUDIT_DTL WHERE ADA=:ADA ORDER BY FIS_YEAR DESC) A,PIN_TABLE B WHERE A.IROW

请问您是否怀疑函数有问题?我试过单独调用函数,传固定的参数进去,能出来正确的返回值。但是在过程里面调用这个函数,传的参数值并没有变化。
所以我不知道是否forall的值传入函数里面,是不是要用其它的办法才行呢?否则forall的值V_ADA_ARRAY(i)我在plsql里面调试的时候都只是第一个V_ADA_ARRAY(1)的值,没有变化的。很奇怪。

使用道具 举报

回复
论坛徽章:
226
BLOG每日发帖之星
日期:2010-02-11 01:01:06紫蛋头
日期:2013-01-12 23:45:222013年新春福章
日期:2013-02-25 14:51:24问答徽章
日期:2013-10-17 18:06:40优秀写手
日期:2013-12-18 09:29:10马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:14
4#
发表于 2011-6-6 13:58 | 只看该作者
UPDATE MEMBER
           SET PIN_LVL_AFT_APR = GetQVSPinCode(V_ADA_ARRAY(i), V_GRADING_D);

UPDATE语句加上WHERE条件
WHERE CONDITION = V_CONDITION(I);

使用道具 举报

回复
论坛徽章:
0
5#
 楼主| 发表于 2011-6-6 16:39 | 只看该作者
原帖由 yangtingkun 于 2011-6-6 13:58 发表
UPDATE MEMBER
           SET PIN_LVL_AFT_APR = GetQVSPinCode(V_ADA_ARRAY(i), V_GRADING_D);

UPDATE语句加上WHERE条件
WHERE CONDITION = V_CONDITION(I);

谢谢您指点,原来是这样的问题,我以后记住了。

使用道具 举报

回复
论坛徽章:
226
BLOG每日发帖之星
日期:2010-02-11 01:01:06紫蛋头
日期:2013-01-12 23:45:222013年新春福章
日期:2013-02-25 14:51:24问答徽章
日期:2013-10-17 18:06:40优秀写手
日期:2013-12-18 09:29:10马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:14
6#
发表于 2011-6-7 10:22 | 只看该作者

使用道具 举报

回复
论坛徽章:
0
7#
 楼主| 发表于 2011-6-7 16:02 | 只看该作者
原帖由 yangtingkun 于 2011-6-7 10:22 发表
参考:http://yangtingkun.itpub.net/post/468/518933

再次感谢您的指点,从文章我看到了具体的执行细节,也学到了一些定位的办法,再次感谢。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表