ORA-01403未找到任何数据select into问题分析

ORA-01403未找到任何数据select into问题分析_第1张图片


引言:

今天看到的一句很有哲理的话: Dont blame the Car- Learn to be a Good Driver 


1.为什么产生ORA-01403

ORA-01403: 未找到任何数据 异常主要是由于SQL中使用了SELECT INTO 但是根据条件没有查询到结果引起.

例如下数据表producten表中不存在名称为国内共享套餐的产品,此时获取DI就会得到报错

DECLARE
  V_ID NUMBER;
BEGIN
  SELECT P.PRODUCTID_PK
    INTO V_ID
    FROM PRODUCTEN P
   WHERE P.PRODUCTNAMESTR = '国内共享套餐';

  DBMS_OUTPUT.put_line('产品ID=' || V_ID);

END;
 
ORA-01403: 未找到任何数据
ORA-06512: 在 line 5

2. 如何解决ORA-01403

如果只是解决报错问题,有两种常见方式

2.1 第一种方式就是提前检测

DECLARE
  V_COUNT NUMBER;
  V_ID    NUMBER;
BEGIN
  --先检查数据存在
  SELECT COUNT(*)
    INTO V_COUNT
    FROM PRODUCTEN P
   WHERE P.PRODUCTNAMESTR = '国内共享套餐';

  --然后处理
  IF V_COUNT > 0 THEN
    SELECT P.PRODUCTID_PK
      INTO V_ID
      FROM PRODUCTEN P
     WHERE P.PRODUCTNAMESTR = '国内共享套餐';
  
  END IF;
  --做其他的事情
  DBMS_OUTPUT.put_line('产品ID=' || V_ID);
END;

2.2 第二种方式通过异常处理

begin
  select x into v from t where ...
  
exception 
  when no_data_found then
    
end

所以上面的例子可以修改为下面的SQL

DECLARE
  V_ID NUMBER;
BEGIN

  BEGIN
    SELECT P.PRODUCTID_PK
      INTO V_ID
      FROM PRODUCTEN P
     WHERE P.PRODUCTNAMESTR = '国内共享套餐';
  exception
    when no_data_found then
      V_ID := NULL;
  END;
  DBMS_OUTPUT.put_line('产品ID=' || V_ID);
END;
 
--执行结果:PL/SQL procedure successfully completed

3. 针对此问题的思考

想想上面的两种处理方式让脚本很难看并且很笨拙,用SELECT INTO前先COUNT(*)检测,感觉浪费性能, 用Exception异常块来处理,程序脚本中可能就会有很多begin/exception/end块语句块看着很傻很笨拙, 很多人提出了为什么Oracle 不能改善ORA-01403,比如当查询不到数据的时候返回NULL 来替换‘no data found.’异常

ORA-01403未找到任何数据select into问题分析_第2张图片

     仔细思考,先使用查询语句检查不仅会增加将开销,由于Oracle的语句读一致性,如果其他人在count(*)后删除了该行, 那么再执行select into 也可能得到no_data_found异常;所以使用count(*) 检查并不安全。

     而在一个存储过程中有很多个select语句, 把这些语句又包装到begin/exception/end块中会很麻烦,更好的解决方法是

  • 编写更小的程序, 尽可能让代码在一个屏幕中
  • 通过将查询链接在一起减少查询语句

 

     这是我从网上看到的一位国外的程序员对此问题的观点,原文如下

Absolutely best method is to handle exception what you are trying to avoid. This is safest, fastest, uses least resources and is most readable and uderstandable. If someone will look at your "SELECT min(x) INTO a" he will not puzzle out your intents, he will uderstand code exactly the way it is written. Do not teach your programmers bad things. It is lame what you want to do. Oracle do not need to change anythig about this one. NEVER! This is the way it should be.

And never say "exeption block takes extra lines of code".
It is absolutely dumbest argument I've ever heard.
You should judge programm by the way it woks, not by the count of lines. 

我觉得他说的很有道理

  • 最安全最快最省资源的方式就是处理你方法上的异常,同时教别人也这样做,养成好习惯
  • 应该通过程序运行的方式来判断程序好坏而不是行数

   

  

  

前一篇:Oracle 如何MD5加密

你可能感兴趣的:(数据存储,dba,oracle,sql)