在ORACLE存储过程或函数中,若含有以下语句SELECT xxx INTO xxx FROM XXX where 时,若SELECT出来没有记录时,将产生NO_DATA_FOUND错误,因为该句带WHERE 条件,很有可能SELECT 出来是没有记录的,有什么好办法避免NO_DATA_FOUND错误呢?以下有两种方法,但我觉得不好
方法一:
先SELECT 一将,判断有没记录。这样将会SELECT 两次,如果是复杂的SELECT 语句,如SELECT ....FROM A INNER JOIN b ........LEFT JOIN Z ON..... WHERE .......一大堆的那种,这会严重影响效率。方法二:(我暂时用的)
SELECT A.xxx INTO xxx
FROM DUAL LEFT JOIN(
SELECT xxx
FROM xxx
WHERE xxxxxxxxx) A ON 1 = 1;
但LEFT JOIN后面很复杂或SELECT 字段比较多且复杂的话,好像比较麻烦。请教高手还有其它好办法吗?

解决方案 »

  1.   

    关于NO_DATA_FOUND出现异常的询问简约代码如下
    /* Oracle settings */
    set pagesize 0
    set feedback off
    ...
    /*DECLARE variables*/
    ...
    begin
       LOOP
                    
                   UTL_FILE.GET_LINE(V_INPUT_HANDLE,V_LINE);
    --get input file line by line
    V_POS_1 := INSTR(V_LINE, ',', 1,1);
    V_RGISNO := SUBSTR(V_LINE,0, V_POS_1-1);
    --get first filed of line 
    SELECT ACCOUNT_NO INTO V_ARBOR_ACCT_NO FROM CUSTOMER_ID_ACCT_MAP@arbor1
                    WHERE external_id = V_RGISNO
                    AND EXTERNAL_ID_TYPE IN ( 2, 3, 5, 6, 7, 13, 16, 530, 531, 532, 533, 534, 535 )
                    AND INACTIVE_DATE IS NULL;  IF  V_IGNORE != 1 THEN 
                   SELECT CUSTOMERID INTO V_TALLYMAN_CUS_NO FROM RL_CUSTOMERS 
                            WHERE TMC_CMF_11 = V_ARBOR_ACCT_NO;
    IF  V_IGNORE != 1 THEN 
                            SELECT ID INTO V_TALLYMAN_ACCT_NO FROM ACCOUNTS
                            WHERE CUSTOMERID = V_TALLYMAN_CUS_NO 
                            AND LEADER = 'Y';
                            UTL_FILE.PUT_LINE(V_ACTLOG_HANDLE,'V_TALLYMAN_ACCT_NO=' || V_TALLYMAN_ACCT_NO);
                    END IF;/*UPDATE TABLE ADN INSERT TABLE */
    ...
    ...
    EXCEPTION
    WHEN NO_DATA_FOUND THEN        V_IGNORE := 1; 
            V_NOUPDATE_COUNTER := V_NOUPDATE_COUNTER + 1;
            UTL_FILE.PUT_LINE(V_ERROR_HANDLE, V_LINE);
    WHEN OTHERS THEN
    ...
    END;
      

  2.   

    思路:先查记录数,再发出sql语句
      

  3.   

    感谢yown(yong)
    我之前已经提到,对于简单语句,可先查记录数,再发出SQL语句。若是复杂语句,会严重影响效率,因为有些存储过程的SQL语句非常复杂(逻辑很多,整个存储过程有1K多行),执行一次需要花费大量时间。而且,发生NO_DATA_FOUND时,我并不想终止程序执行,下面还有一堆SQL语句要执行,所以未用EXCEPTION。在MSSQL里,若SELECT没有数据,会自动赋NULL值给变量。不知道哪位高人还有更好的建议
      

  4.   

    另,ORACLE是不是不能自动转换数据类型呀,一定要强制转换。以前用MSSQL是可以自动转换的,如数字字符一整数之间就能自动转换。
      

  5.   

    使用exception一样可以继续执行的。在csdn资料搜索中可以找到。
      

  6.   

    declare 
      -- Local variables here
      i INT;
      b INT:=5;
      c INT:=0;
      d INT:=0;
        
    BEGIN
      FOR i IN 1.. 10 LOOP
        dbms_output.put_line('the number is '||i);
        begin
           IF i>5 THEN
             d:=b/c;
           END IF;  
        exception
           --异常在内部处理了。
           when others then
              Dbms_Output.put_line('------Divided by Zero');
        end;
      END LOOP;
    exception
      WHEN OTHERS THEN
      BEGIN
      dbms_output.put_line('OtherError');
      END;end;
      

  7.   

    感谢dobetterthatnthink(饥不择食) 
    我的异常全部抛出,暂不讨论异常问题,主题问题有何高见。。
    你们一般是如何处理这类情况的呢?
      

  8.   

    exception 
      when no_data_found then
       ...oracle 自带的no_data_found 异常抛出不可以处理么
      

  9.   

    不需要进行左连接或者右连接,直接判断内连接出的数据集是否为空,如果为空,直接进入no_data_found 的异常处理不可以么
      

  10.   


    select ... into ............;
    的地方改写成:
    begin 
       select ... into ............;
    exception
       when no_data_found then
        .......
    end;
    看看怎么样???还有一种方法是利用游标处理
    select ... into ............;
    这样的语句。比较麻烦,主要是利用游标可以返回%notfound的特性。以上两种方法在实际开发过程中都用到过。可以参考一下。
      

  11.   

    先定义游标 
    FETCH m_Pjer1401_Cursor  
    INTO m_recordTemp;
    EXIT WHEN m_Pjer1401_Cursor%NOTFOUND;
      

  12.   

    多谢各位了
    看错了dobetterthatnthink(饥不择食) 后面的例子。我想你那种方法应该可以的。不过还没试。定义游标方式也可以,但感觉比较麻烦。要滚动,浪费资源比较多(估计,呵呵)。xiaoxiao1984(潇潇) 说的方式也是指饥不择食的那种处理方式吧。
      

  13.   

    一般都是用dobetterthatnthink(饥不择食) 和xiaoxiao1984(潇潇)说的那种处理方式。