Plsql Oracle PL/SQL-ORA-01403使用“选择到”时“未找到数据”

Plsql Oracle PL/SQL-ORA-01403使用“选择到”时“未找到数据”,plsql,oracle11g,Plsql,Oracle11g,我有一个pl sql代码,它按顺序执行三个查询以确定匹配级别并执行一些逻辑 问题是-当第一次查询没有结果时,在完全有效的情况下,我得到ORA-01403未找到任何数据。 我知道我需要合并[Exception子句when NO_DATA_FOUND]——但是如何添加它并继续下一个查询 PL/SQL Code SELECT A into PARAM A FROM SAMPLE WHERE SOME CONDITION; -- GOT ORA-01403 No data fou

我有一个pl sql代码,它按顺序执行三个查询以确定匹配级别并执行一些逻辑 问题是-当第一次查询没有结果时,在完全有效的情况下,我得到ORA-01403未找到任何数据。 我知道我需要合并[Exception子句when NO_DATA_FOUND]——但是如何添加它并继续下一个查询

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
只需将您的选择围绕在开始和结束之间

这类似于PL/Sql的try块

使用此技术,您可以记录语句失败的原因。

对于选择。。。进入语句,则PL/SQL引擎假定将有一行,并且查询只返回一行。如果没有行或多行,将引发异常

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;
FWIW,您可以通过使用聚合函数来处理此类情况,而无需求助于异常处理。这样,结果集中始终只有一行

假设行中的A不能为NULL:

如果可能出现空值,只需添加一个额外的COUNT*列:


Oracle不允许您打开隐式游标,即代码块体中不返回行的select语句。这里有两个选项3,计算@Sylvain的答案,但这是一种不寻常的方法:使用显式游标或处理错误

显式光标

显式游标是在DECLARE部分找到的游标,必须手动或在FOR循环中打开和获取它。这还有一个额外的优点,即如果正确地参数化查询,可以编写一次并多次使用它

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;
处理错误

如果选择处理错误,则需要在将引发错误的代码周围创建一个BEGIN…END块。当忽略一个错误时,确保只忽略您希望避免的特定错误是非常重要的,因为它是从您期望的特定语句生成的。例如,如果您只是将EXCEPTION部分添加到现有的BEGIN…END块中,您就不知道是哪个语句生成了它,甚至不知道它是否真的是您所期望的错误

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;

虽然我不鼓励这样做,但您可以在相同的异常块中捕获任何其他错误。然而,根据定义,这些错误是意外的,所以丢弃它们是一种糟糕的做法,你永远不会知道它们甚至发生过!。一般来说,如果在异常处理中使用WHEN OTHERS子句,则该子句应始终以RAISE;,这样错误就可以传递到下一个级别,而不会丢失。

如果块的目标是捕获未找到的数据,那么当其他数据充其量是毫无意义的,充其量是危险的时。这只是为了展示技术。无论如何,危险是什么?会处理其他错误吗?如果您将其写入日志,然后重新抛出呢?当然,您不仅需要设计Sql块本身,还需要设计错误处理。危险在于,阅读该示例的人实际上在该部分什么也不做:当其他人为NULL;,这会导致代码忽略No.DaaAuthBug以外的所有错误。我们不应该认为人们是白痴。大多数程序员都知道如何用示例编写程序。我们展示了技术,他们从那里得到了。巴顿将军说,告诉人们该做什么,而不是怎么做。你会惊讶于他们的聪明才智。我不认为任何人是白痴。但是,如果有人没有足够的经验来搜索未发现数据错误的解决方案,那么很可能他们不知道在PL/SQL中处理错误的最佳实践。在这种情况下,您的指令在此处执行某些操作,否则就无法读取任何内容,这可能会导致错误代码。这似乎值得一提,肯定是其中一条路要走。仅当您想知道并记录选择失败的原因时才适用。@T.S.一般情况下我同意。但是,引用OP的话:当第一个查询没有结果时,这个场景是完全有效的。。。据我所知,在特定的用例中,没有必要记录未找到的数据或太多的行异常。这就是我们在这里的原因。我们让OP决定他或她需要做什么我看到这种方法的性能问题,6 db的fetch而不是3 db,匹配查询非常昂贵…只是一个评论,匹配查询很昂贵-当第一个查询返回匹配时-我不需要获取查询2和查询3…对于第一个方法显式游标-我需要在声明部分执行所有三个匹配查询吗?如果是这样,这是不可能的。@user648026游标或查询没有在declare块中执行:游标cur_参数某些列的值是。。。但仅当打开时:open cur_params match_level。仍然在打开以读取第一个匹配项后,它将执行所有三个匹配项,对吗?每次打开查询时,都将使用指定的参数运行查询。这里的关键是对查询进行参数化,以便每次使用时,您提供的参数都会给出不同的结果。这假设 每次运行类似的查询时,只有WHERE子句不同。
 SELECT MAX(A), COUNT(*) into A, HAS_FOUND_ROW FROM SAMPLE WHERE SOME CONDITION;

 if HAS_FOUND_ROW > 0 then
     ...
 end if;
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;
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;