我们如何定义存储过程中的输出参数大小?

发布于 2024-09-08 11:15:49 字数 26 浏览 3 评论 0原文

我们如何定义存储过程中的输出参数大小?

How can we define output parameter size in stored procedure?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

☆獨立☆ 2024-09-15 11:15:49

你不能。当然,您可以控制在存储过程的 OUT 参数中放入多少数据。如果需要,可以创建一个指定大小的局部变量来保存数据,然后将该变量的值分配给 OUT 参数。

调用程序确定接收 OUT 参数的变量的大小。

You can't. Of course, you are in control of how much data you put into the OUT parameter in the stored procedure. If you want you can create a sized local variable to hold the data and then assign the value of that variable to the OUT parameter.

The calling program determines the size of the variable that receives the OUT parameter.

等风来 2024-09-15 11:15:49

这是一个声明并使用子类型的简单包:

SQL> create or replace package my_pkg as
  2      subtype limited_string is varchar2(10);
  3      procedure pad_string (p_in_str varchar
  4                          , p_length number
  5                          , p_out_str out limited_string);
  6  end my_pkg;
  7  /

Package created.

SQL> create or replace package body my_pkg as
  2      procedure pad_string
  3          (p_in_str varchar
  4              , p_length number
  5              , p_out_str out limited_string)
  6      as
  7      begin
  8          p_out_str := rpad(p_in_str, p_length, 'A');
  9      end  pad_string;
 10  end my_pkg;
 11  /

Package body created.

SQL>

但是,如果我们以输出字符串超出子类型精度的方式调用 PAD_STRING(),它仍然会成功完成。打扰!

SQL> var out_str varchar2(128)
SQL>
SQL> exec my_pkg.pad_string('PAD THIS!', 12, :out_str)

PL/SQL procedure successfully completed.

SQL>
SQL> select length(:out_str) from dual
  2  /

LENGTH(:OUT_STR)
----------------
              12

SQL>

这很烦人,但这就是 PL/SQL 的工作方式,所以我们必须忍受它。

解决这种情况的方法基本上是应用 DBC 原则 并验证我们的参数。因此,我们可以像这样针对输入断言业务规则:

SQL> create or replace package body my_pkg as
  2      procedure pad_string
  3          (p_in_str varchar
  4              , p_length number
  5              , p_out_str out limited_string)
  6      as
  7      begin
  8          if length(p_in_str) + p_length > 10 then
  9              raise_application_error(
 10                      -20000
 11                      , 'Returned string cannot be longer than 10 characters!');
 12          end if;
 13          p_out_str := rpad(p_in_str, p_length, 'A');
 14      end  pad_string;
 15  end my_pkg;
 16  /

Package body created.

SQL>
SQL> exec my_pkg.pad_string('PAD THIS!', 12, :out_str)
BEGIN my_pkg.pad_string('PAD THIS!', 12, :out_str); END;

*
ERROR at line 1:
ORA-20000: Returned string cannot be longer than 10 characters!
ORA-06512: at "APC.MY_PKG", line 9
ORA-06512: at line 1


SQL>

或者我们可以像这样针对输出断言业务规则:

SQL> create or replace package body my_pkg as
  2      procedure pad_string
  3          (p_in_str varchar
  4              , p_length number
  5              , p_out_str out limited_string)
  6      as
  7          l_str limited_string;
  8      begin
  9          l_str := rpad(p_in_str, p_length, 'A');
 10          p_out_str := l_str;
 11      end  pad_string;
 12  end my_pkg;
 13  /

Package body created.

SQL>
SQL> exec my_pkg.pad_string('PAD THIS!', 12, :out_str)
BEGIN my_pkg.pad_string('PAD THIS!', 12, :out_str); END;

*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at "APC.MY_PKG", line 9
ORA-06512: at line 1

SQL>

在大多数情况下,我们应该同时执行这两种操作。这是构建接口的礼貌方式,因为这意味着其他例程可以调用我们的过程,并确信它们将返回它们所说的值。

Here is a simple package which declares and uses a subtype:

SQL> create or replace package my_pkg as
  2      subtype limited_string is varchar2(10);
  3      procedure pad_string (p_in_str varchar
  4                          , p_length number
  5                          , p_out_str out limited_string);
  6  end my_pkg;
  7  /

Package created.

SQL> create or replace package body my_pkg as
  2      procedure pad_string
  3          (p_in_str varchar
  4              , p_length number
  5              , p_out_str out limited_string)
  6      as
  7      begin
  8          p_out_str := rpad(p_in_str, p_length, 'A');
  9      end  pad_string;
 10  end my_pkg;
 11  /

Package body created.

SQL>

However, if we call PAD_STRING() in such a way that the output string exceeds the subtype's precision it still completes successfully. Bother!

SQL> var out_str varchar2(128)
SQL>
SQL> exec my_pkg.pad_string('PAD THIS!', 12, :out_str)

PL/SQL procedure successfully completed.

SQL>
SQL> select length(:out_str) from dual
  2  /

LENGTH(:OUT_STR)
----------------
              12

SQL>

This is annoying but it's the way PL/SQL works so we have to live with it.

The way to resolve the situaton is basically to apply DBC principles and validate our parameters. So, we can assert business rules against the inputs like this:

SQL> create or replace package body my_pkg as
  2      procedure pad_string
  3          (p_in_str varchar
  4              , p_length number
  5              , p_out_str out limited_string)
  6      as
  7      begin
  8          if length(p_in_str) + p_length > 10 then
  9              raise_application_error(
 10                      -20000
 11                      , 'Returned string cannot be longer than 10 characters!');
 12          end if;
 13          p_out_str := rpad(p_in_str, p_length, 'A');
 14      end  pad_string;
 15  end my_pkg;
 16  /

Package body created.

SQL>
SQL> exec my_pkg.pad_string('PAD THIS!', 12, :out_str)
BEGIN my_pkg.pad_string('PAD THIS!', 12, :out_str); END;

*
ERROR at line 1:
ORA-20000: Returned string cannot be longer than 10 characters!
ORA-06512: at "APC.MY_PKG", line 9
ORA-06512: at line 1


SQL>

Or we can assert business rules against the output like this:

SQL> create or replace package body my_pkg as
  2      procedure pad_string
  3          (p_in_str varchar
  4              , p_length number
  5              , p_out_str out limited_string)
  6      as
  7          l_str limited_string;
  8      begin
  9          l_str := rpad(p_in_str, p_length, 'A');
 10          p_out_str := l_str;
 11      end  pad_string;
 12  end my_pkg;
 13  /

Package body created.

SQL>
SQL> exec my_pkg.pad_string('PAD THIS!', 12, :out_str)
BEGIN my_pkg.pad_string('PAD THIS!', 12, :out_str); END;

*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at "APC.MY_PKG", line 9
ORA-06512: at line 1

SQL>

In most scenarios we should do both. This is the polite way to build interfaces, because it means other routines can call our procedures with the confidence that they will return the values they say they will.

染火枫林 2024-09-15 11:15:49

您可以在包头中使用子类型并在主体中进行类型检查...

CREATE OR REPLACE PACKAGE my_test
AS
   SUBTYPE   my_out   IS   VARCHAR2( 10 ); 

   PROCEDURE do_something( pv_variable IN OUT my_out );
END;
/

CREATE OR REPLACE PACKAGE BODY my_test
AS 
   PROCEDURE do_something( pv_variable IN OUT my_out )
   IS
      lv_variable   my_out;
   BEGIN
      -- Work on a local copy of the variable in question
      lv_variable := 'abcdefghijklmnopqrstuvwxyz';

      pv_variable := lv_variable;
   END do_something;

END;
/

然后当您运行此命令时

DECLARE
   lv_variable VARCHAR2(30);
BEGIN
   my_test.do_something( lv_variable );
   DBMS_OUTPUT.PUT_LINE( '['||lv_variable||']');
END;
/

您会收到错误

ORA-06502: PL/SQL: numeric or value error: character string buffer too small

似乎违背了使用输出参数的精神,但在托尼的评论之后这是唯一的事情我可以想到在调用的代码中控制数据。

You could use a subtype in a package header and type check that in the body...

CREATE OR REPLACE PACKAGE my_test
AS
   SUBTYPE   my_out   IS   VARCHAR2( 10 ); 

   PROCEDURE do_something( pv_variable IN OUT my_out );
END;
/

CREATE OR REPLACE PACKAGE BODY my_test
AS 
   PROCEDURE do_something( pv_variable IN OUT my_out )
   IS
      lv_variable   my_out;
   BEGIN
      -- Work on a local copy of the variable in question
      lv_variable := 'abcdefghijklmnopqrstuvwxyz';

      pv_variable := lv_variable;
   END do_something;

END;
/

Then when you run this

DECLARE
   lv_variable VARCHAR2(30);
BEGIN
   my_test.do_something( lv_variable );
   DBMS_OUTPUT.PUT_LINE( '['||lv_variable||']');
END;
/

You would get the error

ORA-06502: PL/SQL: numeric or value error: character string buffer too small

Seems to go against the spirit of using an out parameter, but after Tony's comment this was the only thing I could think of to control data within the called code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文