如何将数字列表传递到存储过程?

时间:2011-03-11 03:39:27

标签: oracle stored-procedures

所以我有以下存储过程:

CREATE OR REPLACE PROCEDURE stored_p
(
 ntype IN NUMBER          ,
 p_ResultSet OUT  TYPES.cursorType
)
AS
BEGIN
OPEN p_ResultSet FOR
select * from table where ttype in ntype;
END stored_p

并且,我可以这样称呼它:

VARIABLE resultSet  REFCURSOR
EXEC stored_p(80001, :resultSet);
PRINT :resultSet

但我希望能够这样称呼它:

VARIABLE resultSet  REFCURSOR
EXEC stored_p([80001,80002], :resultSet);
PRINT :resultSet

我应该如何相应地修改我的存储过程?我正在这样做,以便我可以在Crystal Report中显示结果...(以防万一会影响任何事情)..谢谢!!

3 个答案:

答案 0 :(得分:10)

最好的选择是传递集合

SQL> create type empno_tbl
  2  is
  3  table of number;
  4  /

Type created.


SQL> create or replace procedure stored_p
  2  (
  3    empnos in empno_tbl,
  4    p_rc  out sys_refcursor )
  5  as
  6  begin
  7    open
  8   p_rc for select * from emp where empno in (select * from table(empnos));
  9  end;
 10  /

Procedure created.

SQL> var rc refcursor;

SQL> ed
Wrote file afiedt.buf

  1  create or replace procedure stored_p
  2  (
  3    empnos in empno_tbl,
  4    p_rc  out sys_refcursor )
  5  as
  6  begin
  7    open
  8   p_rc for select * from emp where empno in (select * from table(empnos));
  9* end;
SQL> begin
  2    stored_p( new empno_tbl(7902,7934), :rc );
  3  end;
  4  /

PL/SQL procedure successfully completed.

SQL> print rc

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM
---------- ---------- --------- ---------- --------- ---------- ----------
    DEPTNO   FAKE_COL        FOO
---------- ---------- ----------
      7902 FORD       ANALYST         7566 03-DEC-81       3000
        20          1

      7934 MILLER     CLERK           7782 23-JAN-82       1300
        10          1

不幸的是,Crystal Reports可能无法将正确的集合传递给存储过程。如果是这种情况,则必须传入以逗号分隔的数字列表。然后,您的过程必须将逗号分隔的字符串解析为集合。您可以使用(或修改)Tom Kyte's in_list函数来实现此

SQL> ed
Wrote file afiedt.buf

  1    create or replace function in_list(
  2        p_string in varchar2
  3    )
  4      return empno_tbl
  5    as
  6        l_string        long default p_string || ',';
  7        l_data          empno_tbl := empno_tbl();
  8        n               number;
  9    begin
 10      loop
 11          exit when l_string is null;
 12          n := instr( l_string, ',' );
 13          l_data.extend;
 14          l_data(l_data.count) :=
 15                ltrim( rtrim( substr( l_string, 1, n-1 ) ) );
 16          l_string := substr( l_string, n+1 );
 17      end loop;
 18      return l_data;
 19*   end;
SQL> /

Function created.

SQL> ed
Wrote file afiedt.buf

  1  create or replace procedure stored_p
  2  (
  3    empnos in varchar2,
  4    p_rc  out sys_refcursor )
  5  as
  6  begin
  7    open p_rc
  8     for select *
  9           from emp
 10          where empno in (select *
 11                            from table(in_list(empnos)));
 12* end;
SQL> /

Procedure created.

SQL> ed
Wrote file afiedt.buf

  1  begin
  2    stored_p( '7902,7934', :rc );
  3* end;
SQL> /

PL/SQL procedure successfully completed.

SQL> print rc

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM
---------- ---------- --------- ---------- --------- ---------- ----------
    DEPTNO   FAKE_COL        FOO
---------- ---------- ----------
      7902 FORD       ANALYST         7566 03-DEC-81       3000
        20          1

      7934 MILLER     CLERK           7782 23-JAN-82       1300
        10          1

答案 1 :(得分:0)

较新的版本可能有不同的选项。我使用Oracle 9和10工作,我通常会传入一串逗号分隔的值并动态构建SQL。但是,SQL注入存在一些重大危险。

答案 2 :(得分:0)

您需要创建一个类型..

create or replace type NUMBER_ARRAY as table of number;

CREATE OR REPLACE PROCEDURE stored_p
(
 ntype IN NUMBER_ARRAY          ,
 p_ResultSet OUT  TYPES.cursorType
)

你可以使用..

循环它
for i in 1 .. ntype.count
loop
    dbms_output.put_line( ntype(i) );
end loop;

要测试它,

DECLARE
   ntypetest                     NUMBER_ARRAY := NUMBER_ARRAY ();
BEGIN
   FOR i IN 1 .. 5
   LOOP
      ntypetest.EXTEND;
      ntypetest (i) := i;
   END LOOP;


   stored_p(ntypetest,..)

语法可能有些变化。

当然,您也可以传入逗号分隔值,但这会以字符串形式出现。你的字符串应该是'val1','val2','val3'。你有数字时需要小心,因为整个字符串看起来像in ('2343,3444,2222'),它将被视为一个值而不是多个数字in (2343,3444,2222)