1

我对语句使用游标:

SELECT NAME FROM STUDENT WHERE ROLL = 1;

我用了:

CURSOR C IS SELECT NAME FROM STUDENT WHERE ROLL = roll;
--roll is a variable I receive via a procedure, and the procedure works fine for the received parameter.

执行此操作后,我可以检索 roll = 1 的所有记录。

现在,我需要检索一个组的记录(可能通过游标),就像:

SELECT NAME FROM STUDENT WHERE ROLL IN (2, 4, 6);

但是 IN 子句中的值只有在运行时才知道。我该怎么做?也就是说,有什么方法可以将参数分配给游标的WHERE子句?

我尝试在游标的声明中使用数组,但弹出一个错误,告诉类似:标准类型不能使用

我用了:

CURSOR C IS SELECT NAME FROM STUDENT WHERE ROLL IN (rolls);
--rolls is an array initialized with the required roll numbers.
4

3 回答 3

4

首先,我假设您的过程的参数实际上与STUDENT表中列的名称不匹配。如果您实际编写了您发布的语句,roll将被解析为列的名称,而不是参数或局部变量,因此该语句将返回该列STUDENT所在的表中的每一行。ROLLNOT NULL

CURSOR C 
    IS SELECT NAME 
         FROM STUDENT 
        WHERE ROLL = roll;

其次,虽然可以像@Gaurav Soni 建议的那样使用动态 SQL,但这样做会生成一堆不可共享的 SQL 语句。这将淹没共享池,可能会使缓存中的其他语句老化,并且每次都使用大量 CPU 硬解析语句。Oracle 构建的前提是你要解析一次 SQL 语句,一般使用绑定变量,然后以不同的绑定变量值多次执行该语句。Oracle 可以只执行一次解析查询、生成查询计划、将查询放入共享池等过程,然后在您再次执行查询时重用所有这些。如果您生成了一堆永远不会再次使用的 SQL 语句,因为您使用的是没有绑定变量的动态 SQL,

此外,您已经向 SQL 注入攻击敞开了大门。攻击者可以利用该过程从任何表中读取任何数据或执行存储过程所有者有权访问的任何函数。即使您的应用程序没有特别的安全意识,这也将是一个主要的安全漏洞。

你最好使用一个集合。这可以防止 SQL 注入攻击并生成单个可共享的 SQL 语句,因此您不必进行持续的硬解析。

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

Type created.

SQL> create or replace procedure get_emps( p_empno_arr in empno_tbl )
  2  is
  3  begin
  4    for e in (select *
  5                from emp
  6               where empno in (select column_value
  7                                 from table( p_empno_arr )))
  8    loop
  9      dbms_output.put_line( e.ename );
 10    end loop;
 11  end;
 12  /

Procedure created.

SQL> set serveroutput on;
SQL> begin
  2    get_emps( empno_tbl( 7369,7499,7934 ));
  3  end;
  4  /
SMITH
ALLEN
MILLER

PL/SQL procedure successfully completed.
于 2012-04-15T17:52:21.693 回答
1
create or replace procedure dynamic_cur(p_empno VARCHAR2) IS
cur     sys_refcursor;
v_ename emp.ename%type;
 begin
  open cur for 'select ename from emp where empno in (' || p_empno || ')';
  loop
   fetch cur into v_ename;
   exit when cur%notfound;
    dbms_output.put_line(v_ename);
  end loop;
  close cur;
end dynamic_cur;

创建的程序

运行proceduredynamic_cur

declare
v_empno   varchar2(200) := '7499,7521,7566';
begin
  dynamic_cur(v_empno);
end; 

输出

ALLEN
WARD
JONES

注意:如前所述XQbertdynamic cursor导致SQL injection,但如果您没有处理任何关键要求,并且不涉及安全性,那么您可以使用它。

于 2012-04-15T16:28:19.487 回答
1

也许您可以将 rolls 作为一组带引号的逗号分隔值传递。例如'1'、'2'等如果这个值被传递到一个varchar输入变量的过程中,它可以用来根据表匹配来获取多行。

因此光标 SELECT NAME FROM STUDENT WHERE ROLL IN (rolls);

将被评估为 SELECT NAME FROM STUDENT WHERE ROLL IN ('1','2');

希望能帮助到你

于 2012-04-15T16:37:06.920 回答