Oracle PL/SQL - ORA-01403 “No data found” when using “SELECT INTO”

心不动则不痛 提交于 2019-12-12 12:22:00

问题


I have a pl sql code that execute three queries sequentially to determine a match level and do some logic
The issue is - when first query has no results (completely valid scenario) I get ORA-01403 No data found.
I understand that I need to incorporate [ Exception clause when NO_DATA_FOUND ]- but how to add it and continue to the next query?

PL/SQL Code
     SELECT A into PARAM A FROM SAMPLE WHERE SOME CONDITION;
     --  GOT ORA-01403  No data found HERE 

     MATCH_LEVEL =1;
     if A is null then 
          do some logic;
     end if


     SELECT A INTO PARAM_B FROM SAMPLE WHERE SOME OTHER CONDITION
     MATCH_LEVEL =2
     if A is null then 
          do some logic 2;
     end if



     SELECT A INTO PARAM_B FROM SAMPLE WHERE SOME OTHER CONDITION
     MATCH_LEVEL =3
     if A is null then 
          do some logic 3;
     end if

END    PL/SQL Code

回答1:


Just surround your SELECT INTO with begin-end;

begin 

    -- your faulty statement here
Exception
When NO_DATA_FOUND Then
    -- Do what you want or nothing 
WHEN TOO_MANY_ROWS THEN
    -- what if you get more then one row? and need specific handler for this 
When OTHERS Then
    -- do something here or nothing (optional - may happen if you have more than your SELECT INTO between 'begin' and 'Exception')

end;

This is like try block of PL/Sql

With this technique you can log the reason your statement failed.




回答2:


Declare
--your declarations 
begin
SELECT A into PARAM A FROM SAMPLE WHERE SOME CONDITION;
 --  GOT ORA-01403  No data found HERE 

 Begin

   MATCH_LEVEL =1;
   if A is null then 
        do some logic;
   end if;
 EXCEPTION 
 WHEN NO_DATA_FOUND THEN 
  dbms_output.put_line ('Error...'); 
 END; 
 --- and son on for other blocks

end;



回答3:


For a SELECT ... INTO ... statement, the PL/SQL engine assume there will be one, and only one row returned by your query. If there is no row, or more than one, an exception is raised.

FWIW, you can handle such cases without resorting on exception handling by using aggregate functions. That way, there will always be only one row in the result set.

Assuming A can't be NULL in your rows:

 SELECT MAX(A) into PARAM A FROM SAMPLE WHERE SOME CONDITION;
 -- A would be NULL if there was *no* row. Otherwise, it is *the* value for *the* row

 MATCH_LEVEL =1;
 if A is null then 
      do some logic;
 end if

If the NULL value is a possible case, just add an extra COUNT(*) column:

 SELECT MAX(A), COUNT(*) into A, HAS_FOUND_ROW FROM SAMPLE WHERE SOME CONDITION;

 if HAS_FOUND_ROW > 0 then
     ...
 end if;



回答4:


Oracle will not allow you to open an implicit cursor (i.e. a select statement in the body of a code block) that returns no rows. You have two options here (3 really, counting @Sylvain's answer, but that is an unusual approach): use an explicit cursor or handle the error.

Explicit Cursor

An explicit cursor is one found in the DECLARE section it must be opened and fetched manually (or in a FOR loop). This has the added advantage that, if you parameterize the query properly, you can write it once and use it multiple times.

DECLARE
   a sample.a%type;
   MATCH_LEVEL number;
   cursor cur_params (some_column_value number) is
     SELECT A FROM SAMPLE WHERE some_column = some_column_value;
BEGIN
   MATCH_LEVEL := 1;
   open cur_params (match_level);
   fetch cur_params into a;
   close cur_params;
   if A is null then 
        null;  --some logic goes here
   end if;

   MATCH_LEVEL := 2;
   open cur_params (match_level);
   fetch cur_params into a;
   close cur_params;
   if A is null then 
        null;  --some logic goes here
   end if;
end;

Handle the error

If you choose to handle the error, you'll need to create a BEGIN...END block around the code that is going to throw the error. When disregarding an error, it's crucial that you ensure that you are only disregarding the specific error you want avoid, when generated from the specific statement you expect it from. If you simply add the EXCEPTION section to your existing BEGIN...END block, for instance, you couldn't know which statement generated it, or even if it was really the error you expected.

DECLARE
   a sample.a%type;
   MATCH_LEVEL number;
BEGIN
   MATCH_LEVEL := 1;
   BEGIN
      SELECT A into A FROM SAMPLE WHERE some_column = MATCH_LEVEL;
   EXCEPTION
      WHEN NO_DATA_FOUND THEN
         null; --Do nothing
   END;
   if A is null then 
        null;  --some logic goes here
   end if;

   MATCH_LEVEL := 2;
   BEGIN
      SELECT A into A FROM SAMPLE WHERE some_column = MATCH_LEVEL;
   EXCEPTION
      WHEN NO_DATA_FOUND THEN
         null; --Do nothing
   END;
   if A is null then 
        null;  --some logic goes here
   end if;
end;

While I'd discourage it, you can catch any other errors in the same exception blocks. However, by definition, those errors would be unexpected, so it would be a poor practice to discard them (you'll never know they even happened!). Generally speaking, if you use a WHEN OTHERS clause in your exception handling, that clause should always conclude with RAISE;, so that the error gets passed up to the next level and is not lost.



来源:https://stackoverflow.com/questions/27258204/oracle-pl-sql-ora-01403-no-data-found-when-using-select-into

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!