PL/SQL 过程未返回预期结果

Posted

技术标签:

【中文标题】PL/SQL 过程未返回预期结果【英文标题】:PL/SQL procedure not returning expected results 【发布时间】:2014-05-22 14:01:37 【问题描述】:

我有一个在 shell 脚本中运行的 PL/SQL 过程。

我提取了逻辑,但它没有运行内部 BEGIN-END;部分:

DECLARE
model_exists NUMBER(1);
BEGIN 
  SELECT COUNT(*) INTO model_exists from mdsys.rdf_model$ WHERE model_name='XCLOVER';
  BEGIN 
      EXECUTE IMMEDIATE 'CREATE table SEMANTIC.RDF_STAGE_TABLE_XCLOVER(RDF$STC_sub  VARCHAR(4000) not null,RDF$STC_pred VARCHAR(4000) not null,RDF$STC_obj VARCHAR(4000) not null)'; COMMIT;
      EXECUTE IMMEDIATE 'CREATE TABLE SEMANTIC.XCLOVER_TPL (TRIPLE SDO_RDF_TRIPLE_S)'; COMMIT;
      EXCEPTION
      WHEN OTHERS THEN
      IF SQLCODE != -955 THEN
        EXECUTE IMMEDIATE 'TRUNCATE TABLE SEMANTIC.XCLOVER_TPL';
        EXECUTE IMMEDIATE 'TRUNCATE TABLE SEMANTIC.RDF_STAGE_TABLE_XCLOVER';
      END IF;
  END; 
EXECUTE IMMEDIATE 'GRANT ALL ON SEMANTIC.XCLOVER_TPL to MDSYS'; 
IF model_exists = 0 THEN
    SEM_APIS.CREATE_SEM_MODEL('XCLOVER', 'XCLOVER_TPL','TRIPLE'); 
END IF;
COMMIT; 
END;
/

在shell脚本中的写法如下:

#!/bin/bash
. /etc/profile.d/oracle.sh

MODEL=$1

echo "DECLARE" > createxmodel.tmp
echo "model_exists NUMBER(1);" >> createxmodel.tmp
echo "BEGIN" >> createxmodel.tmp
echo "SELECT COUNT(*) INTO model_exists from mdsys.rdf_model\$ WHERE model_name='$MODEL';" >> createxmodel.tmp
echo "BEGIN" >> createxmodel.tmp
echo "EXECUTE IMMEDIATE 'CREATE table SEMANTIC.RDF_STAGE_TABLE_$MODEL(RDF\$STC_sub  VARCHAR(4000) not null,RDF\$STC_pred VARCHAR(4000) not null,RDF\$STC_obj VARCHAR(4000) not null)';" >> createxmodel.tmp
echo "EXECUTE IMMEDIATE 'CREATE TABLE SEMANTIC.$MODEL""_TPL (TRIPLE SDO_RDF_TRIPLE_S)'; " >> createxmodel.tmp
echo "EXCEPTION" >> createxmodel.tmp
echo "WHEN OTHERS THEN" >> createxmodel.tmp
echo "IF SQLCODE != -955 THEN" >> createxmodel.tmp
echo "EXECUTE IMMEDIATE 'TRUNCATE TABLE SEMANTIC.$MODEL""_TPL';" >> createxmodel.tmp
echo "EXECUTE IMMEDIATE 'TRUNCATE TABLE SEMANTIC.RDF_STAGE_TABLE_$MODEL';" >> createxmodel.tmp
echo "END IF;" >> createxmodel.tmp
echo "END;" >> createxmodel.tmp
echo "EXECUTE IMMEDIATE 'GRANT ALL ON SEMANTIC.$MODEL""_TPL to MDSYS';" >> createxmodel.tmp 
echo "IF model_exists = 0 THEN" >> createxmodel.tmp
echo "SEM_APIS.CREATE_SEM_MODEL('$MODEL', '$MODEL""_TPL','TRIPLE');" >> createxmodel.tmp
echo "END IF;" >> createxmodel.tmp
echo "COMMIT;" >> createxmodel.tmp
echo "END;" >> createxmodel.tmp
echo "/" >> createxmodel.tmp
echo "exit;" >> createxmodel.tmp

sqlplus -S user/password < createxmodel.tmp

它现在抛出的错误是:

DECLARE
*
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at line 15

这告诉我内部的 BEGIN 永远不会被执行......

这个用得上:(

有人看到我做错了吗?

【问题讨论】:

您确定了able或view存在吗? 这就是第一个 BEGIN-END 代码块正在做的事情。如果其中任何一个已经存在,它会创建两个表并捕获异常。然后,当它到达 GRANT 选项时,表格应该在那里。 mdsys.rdf_model$ 是否存在(并且它对运行脚本的用户帐户可见)? 【参考方案1】:

我认为你最好将每个表的创建放在它自己的 BEGIN...END 块中,如下所示:

echo "DECLARE" > createxmodel.tmp
echo "  model_exists NUMBER(1);" >> createxmodel.tmp
echo "  excp_table_exists EXCEPTION;" >> createxmodel.tmp
echo "  PRAGMA EXCEPTION_INIT(excp_table_exists, -955);" >> createxmodel.tmp
echo "BEGIN" >> createxmodel.tmp
echo "  SELECT COUNT(*) INTO model_exists from mdsys.rdf_model\$ WHERE model_name='$MODEL';" >> createxmodel.tmp

echo "  BEGIN" >> createxmodel.tmp
echo "    EXECUTE IMMEDIATE 'CREATE table SEMANTIC.RDF_STAGE_TABLE_$MODEL(RDF\$STC_sub  VARCHAR(4000) not null,RDF\$STC_pred VARCHAR(4000) not null,RDF\$STC_obj VARCHAR(4000) not null)';" >> createxmodel.tmp
echo "  EXCEPTION" >> createxmodel.tmp
echo "    WHEN excp_table_exists THEN" >> createxmodel.tmp
echo "      EXECUTE IMMEDIATE 'TRUNCATE TABLE SEMANTIC.RDF_STAGE_TABLE_$MODEL';" >> createxmodel.tmp
echo "  END;" >> createxmodel.tmp
echo "  BEGIN" >> createxmodel.tmp
echo "    EXECUTE IMMEDIATE 'CREATE TABLE SEMANTIC.$MODEL""_TPL (TRIPLE SDO_RDF_TRIPLE_S)'; " >> createxmodel.tmp
echo "  EXCEPTION" >> createxmodel.tmp
echo "    WHEN excp_table_exists THEN" >> createxmodel.tmp
echo "      EXECUTE IMMEDIATE 'TRUNCATE TABLE SEMANTIC.$MODEL""_TPL';" >> createxmodel.tmp
echo "  END;" >> createxmodel.tmp
echo "  EXECUTE IMMEDIATE 'GRANT ALL ON SEMANTIC.$MODEL""_TPL to MDSYS';" >> createxmodel.tmp 
echo "  IF model_exists = 0 THEN" >> createxmodel.tmp
echo "    SEM_APIS.CREATE_SEM_MODEL('$MODEL', '$MODEL""_TPL','TRIPLE');" >> createxmodel.tmp
echo "  END IF;" >> createxmodel.tmp
echo "  COMMIT;" >> createxmodel.tmp
echo "END;" >> createxmodel.tmp
echo "/" >> createxmodel.tmp
echo "exit;" >> createxmodel.tmp

希望这会有所帮助。

分享和享受。

【讨论】:

【参考方案2】:

您需要做的就是在创建后移动 GRANT 语句 - 没有理由将它放在块之外 - 您收到的错误来自编辑器,而不是实际的 PL/SQL 错误,对吗?

    DECLARE
    model_exists NUMBER(1);
    BEGIN 
      SELECT COUNT(*) INTO model_exists from mdsys.rdf_model$ WHERE model_name='XCLOVER';
      BEGIN 
          EXECUTE IMMEDIATE 'CREATE table SEMANTIC.RDF_STAGE_TABLE_XCLOVER(RDF$STC_sub  VARCHAR(4000) not null,RDF$STC_pred VARCHAR(4000) not null,RDF$STC_obj VARCHAR(4000) not null)'; COMMIT;
          EXECUTE IMMEDIATE 'CREATE TABLE SEMANTIC.XCLOVER_TPL (TRIPLE SDO_RDF_TRIPLE_S)'; COMMIT;

EXECUTE IMMEDIATE 'GRANT ALL ON SEMANTIC.XCLOVER_TPL to MDSYS';
          EXCEPTION
          WHEN OTHERS THEN
          IF SQLCODE != -955 THEN
            EXECUTE IMMEDIATE 'TRUNCATE TABLE SEMANTIC.XCLOVER_TPL';
            EXECUTE IMMEDIATE 'TRUNCATE TABLE SEMANTIC.RDF_STAGE_TABLE_XCLOVER';
          END IF;
      END; 

    IF model_exists = 0 THEN
        SEM_APIS.CREATE_SEM_MODEL('XCLOVER', 'XCLOVER_TPL','TRIPLE'); 
    END IF;
    COMMIT; 
    END;

【讨论】:

实际发生的是我有 2 个 CREATE 语句,如果一个抛出异常,它永远不会执行其他 CREATE TABLE 语句。所以当它要 GRANT 表时,它不能因为第二个 CREATE 语句从未被执行。【参考方案3】:

这是一个为什么正确的异常处理很重要的例子。 如果您至少有一个 dbms_output,可能会省去很多麻烦:

DECLARE
model_exists NUMBER(1);
BEGIN 
  SELECT COUNT(*) INTO model_exists from mdsys.rdf_model$ WHERE model_name='XCLOVER';
  BEGIN 
      EXECUTE IMMEDIATE 'CREATE table SEMANTIC.RDF_STAGE_TABLE_XCLOVER(RDF$STC_sub  VARCHAR(4000) not null,RDF$STC_pred VARCHAR(4000) not null,RDF$STC_obj VARCHAR(4000) not null)'; COMMIT;
      EXECUTE IMMEDIATE 'CREATE TABLE SEMANTIC.XCLOVER_TPL (TRIPLE SDO_RDF_TRIPLE_S)'; COMMIT;
      EXCEPTION
      WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE('Some error has occurred'):
      IF SQLCODE != -955 THEN
        EXECUTE IMMEDIATE 'TRUNCATE TABLE SEMANTIC.XCLOVER_TPL';
        EXECUTE IMMEDIATE 'TRUNCATE TABLE SEMANTIC.RDF_STAGE_TABLE_XCLOVER';
      END IF;
  END; 
EXECUTE IMMEDIATE 'GRANT ALL ON SEMANTIC.XCLOVER_TPL to MDSYS'; 
IF model_exists = 0 THEN
    SEM_APIS.CREATE_SEM_MODEL('XCLOVER', 'XCLOVER_TPL','TRIPLE'); 
END IF;
COMMIT; 
END;
/

【讨论】:

以上是关于PL/SQL 过程未返回预期结果的主要内容,如果未能解决你的问题,请参考以下文章

从 PL/SQL 中的过程返回值数组

PL/SQL 匿名块已完成”但未显示结果

为啥这个 PL/SQL 过程不起作用?

PL/SQL: ORA-29481: 隐式结果不能返回给客户端

Oracle PL SQL:比较两个存储过程返回的引用游标结果

ORA-06504: PL/SQL: 执行时返回结果集变量的类型