【问题标题】:Procedure call inside a PL/SQL blockPL/SQL 块内的过程调用
【发布时间】:2013-02-23 19:33:03
【问题描述】:

我有一些 SQL 代码来填充数据库,效果很好:

INSERT INTO PDF_DOCUMENT_ELEMENT (DOCUMENT_ELEMENT_ID, DOCUMENT_ID, ELEMENT_ID) VALUES (1, 1, 1);
INSERT INTO PDF_DOCUMENT_ELEMENT (DOCUMENT_ELEMENT_ID, DOCUMENT_ID, ELEMENT_ID) VALUES (2, 1, 1);
INSERT INTO PDF_DOCUMENT_ELEMENT (DOCUMENT_ELEMENT_ID, DOCUMENT_ID, ELEMENT_ID) VALUES (3, 1, 2);

EXECUTE RESET_SEQUENCE('DOCUMENT_ELEMENT_ID_SEQ', 4);

为了提高可维护性,我尝试用变量替换一些幻数。我以前从未使用过变量,但我读过我需要使用 PL/SQL 块,所以:

DECLARE
    ELEMENT_TEXT SMALLINT := 1;
    ELEMENT_IMAGE SMALLINT := 2;
BEGIN

INSERT INTO PDF_DOCUMENT_ELEMENT (DOCUMENT_ELEMENT_ID, DOCUMENT_ID, ELEMENT_ID) VALUES (1, 1, ELEMENT_TEXT);
INSERT INTO PDF_DOCUMENT_ELEMENT (DOCUMENT_ELEMENT_ID, DOCUMENT_ID, ELEMENT_ID) VALUES (2, 1, ELEMENT_TEXT);
INSERT INTO PDF_DOCUMENT_ELEMENT (DOCUMENT_ELEMENT_ID, DOCUMENT_ID, ELEMENT_ID) VALUES (3, 1, ELEMENT_IMAGE);

EXECUTE RESET_SEQUENCE('DOCUMENT_ELEMENT_ID_SEQ', 4);

END;
/

这工作得很好,除了过程调用:

EXECUTE RESET_SEQUENCE('DOCUMENT_ELEMENT_ID_SEQ', 4);
           *
ERROR en lÝnea 45:
ORA-06550: lÝnea 45, columna 9:
PLS-00103: Se ha encontrado el sÝmbolo "RESET_SEQUENCE" cuando se esperaba uno
de los siguientes:
:= . ( @ % ; immediate
El sÝmbolo ":=" ha sido sustituido por "RESET_SEQUENCE" para continuar.

PLS-00103 错误翻译为:

PLS-00103:找到“字符串”,但预期为以下之一:“字符串”

如果我将调用更改为:

EXECUTE IMMEDIATE RESET_SEQUENCE('DOCUMENTO_ELEMENTO_ID_SEQ', 4);

...我明白了:

PLS-00222: en este ßmbito no existe ninguna funci¾n cuyo nombre sea
'RESET_SEQUENCE'
ORA-06550: lÝnea 45, columna 1:
PL/SQL: Statement ignored

...翻译为:

PLS-00222:此范围内不存在名称为“字符串”的函数

我的问题是:

  1. 我是否正确使用了变量,或者对于我的初始目标有更好的解决方案?
  2. 我需要在我的过程调用语法中修正什么以及为什么?

【问题讨论】:

  • execute immediate 需要一个字符串:EXECUTE IMMEDIATE 'RESET_SEQUENCE(''DOCUMENT_ELEMENT_ID_SEQ'', 4)';
  • 谢谢大家。我已将所有信息收集到一个新答案中,并接受了为我提供线索的答案。

标签: oracle plsql oracle-xe


【解决方案1】:
  1. IMO,如果您有一个带有 3 个参数的过程会更好,其中您将有 1 个插入...然后使用该过程进行插入。这样你就可以添加异常处理,如果发生了什么你就会知道。

  2. 在使用代码的块版本时尝试删除 EXECUTE。我认为你不需要它:)

【讨论】:

    【解决方案2】:

    过程调用不是普通的 SQL,而是 PL/SQL。因此,您需要从 PL/SQL 上下文中运行它。选项包括:

    • 创建一个 PL/SQL 块并直接调用该过程:

      BEGIN
          RESET_SEQUENCE('DOCUMENT_ELEMENT_ID_SEQ', 4);
      END;
      /
      
    • 如果您使用的是 SQL*Plus,则可以使用EXECUTE internal command

      EXECUTE RESET_SEQUENCE('DOCUMENT_ELEMENT_ID_SEQ', 4);
      

    我的问题是我在 PL/SQL 块内发出 SQL*Plus 命令。

    (截至EXECUTE IMMEDIATE,它是一个PL/SQL command 来运行动态生成的SQL 语句或匿名PL/SQL 块。它需要一个字符串,与这个问题无关。Oracle 只是建议它,因为它的名字类似于 SQL*Plus 命令。)

    【讨论】:

      【解决方案3】:

      如果最初的目标是避免使用幻数,那么解决方案是使用具有这些数字含义的表格并引用它。

      所以...

       create table element (
         element_id   integer primary key,
         element_name varchar2(30) not null unique);
      
       insert into element values (1,'Text');
       insert into element values (2,'Image');
      
       INSERT INTO PDF_DOCUMENT_ELEMENT (DOCUMENT_ELEMENT_ID, DOCUMENT_ID, ELEMENT_ID)
       Select 1, 1, element_id
       from   elements
       where  element_name = 'Text';
      
       INSERT INTO PDF_DOCUMENT_ELEMENT (DOCUMENT_ELEMENT_ID, DOCUMENT_ID, ELEMENT_ID)
       Select 1, 1, element_id
       from   elements
       where  element_name = 'Text';
      
       INSERT INTO PDF_DOCUMENT_ELEMENT (DOCUMENT_ELEMENT_ID, DOCUMENT_ID, ELEMENT_ID)
       Select 1, 1, element_id
       from   elements
       where  element_name = 'Image';
      

      【讨论】:

      • 这样的表已经存在。但这是执行一系列插入的一种非常复杂的方式,不是吗? xD
      • 如果目标是通过在代码中使用幻数来避免出错的可能性,那么将它们定义为变量并不能真正解决问题。可以想象,代码可以通过查询数据库来填充变量,然后在其他地方使用变量。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-25
      • 1970-01-01
      • 1970-01-01
      • 2013-01-17
      • 2020-12-27
      • 2014-09-30
      • 2017-08-05
      相关资源
      最近更新 更多