PL / SQL:ORA-00942,在逻辑上无法到达的else块中报告了错误需要添加立即执行才能正常工作为什么?

问题描述

我正在尝试编写一个PL / sql脚本,如果某个表存在/不存在,该脚本将执行一些sql语句。

例如:

SET SERVEROUTPUT ON;
DECLARE
  cnt NUMBER := 0;
  cnt_2 NUMBER := 0;
BEGIN
  SELECT count(*) INTO cnt FROM all_tables where TABLE_NAME='DOES_NOT_EXIST';
  IF cnt = 0 THEN
    dbms_output.put_line('Table does not exist');
  ELSE
    dbms_output.put_line('Table exists ' || cnt);
    SELECT COUNT(*) INTO cnt_2 from DOES_NOT_EXIST;
  END IF;
END;
/

执行此操作时,出现错误

    SELECT COUNT(*) INTO cnt_2 from DOES_NOT_EXIST;
                                    *
ERROR at line 10:
ORA-06550: line 10,column 37:
PL/sql: ORA-00942: table or view does not exist
ORA-06550: line 10,column 5:
PL/sql: sql Statement ignored

但是,如果我在第11行中添加EXECUTE IMMEDIATE,那么它将正常工作。

SET SERVEROUTPUT ON;
DECLARE
  cnt NUMBER := 0;
  cnt_2 NUMBER := 0;
BEGIN
  SELECT count(*) INTO cnt FROM all_tables where TABLE_NAME='DOES_NOT_EXIST';
  IF cnt = 0 THEN
    dbms_output.put_line('Table does not exist');
  ELSE
    dbms_output.put_line('Table exists ' || cnt);
    EXECUTE IMMEDIATE 'SELECT COUNT(*) INTO cnt_2 from DOES_NOT_EXIST';
  END IF;
END;
/

现在可以了

Table does not exist

PL/sql procedure successfully completed.
  1. 能否请您帮助我理解为什么无法在逻辑上到达ELSE块时报告错误的原因? cnt变量将始终为0,那么,我认为永远不会到达ELSE块。

  2. 为什么添加EXECUTE IMMEDIATE不会产生错误

  3. 这是否意味着我应该在EXECUTE IMMEDIATE块中为所有此类语句添加ELSE

我在SO和其他地方进行了搜索,但找不到答案。老实说,我不知道还要使用哪些其他搜索词。所有搜索命中都会导致一般性错误。所以,我在问这个问题。如果已经回答了,请指向我并关闭它。

谢谢。

解决方法

您缺少的是语句分两个步骤处理;在执行 之前先对其进行编译

在编译阶段,将识别并查找标识符(表和列等)。如果找不到表名(或列名或其他名称),则会出现编译错误。

使用execute immediate可使此过程短路。与其说“立即执行”,不如说是“延迟编译”。该语句在运行时同时编译和执行。这就是execute immediate防止错误发生的原因。

,

看起来您需要这样的东西:

select
  owner,table_name,xmlcast(
    xmlquery(
      '/ROWSET/ROW/CNT' 
      passing xmltype(dbms_xmlgen.getXML('select count(*) cnt from "'||owner||'"."'||table_name||'"'))
      returning content null on empty
      )
      as int
   ) as cnt
from all_tables
where owner in ('XTENDER',user);

此查询从通过谓词过滤的all_tables中返回每个表的行数