动态游标

时间:2012-04-15 13:56:08

标签: sql oracle select plsql cursor

我使用游标作为语句:

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.

3 个答案:

答案 0 :(得分:4)

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

NOT NULL

其次,虽然可以像@Gaurav Soni建议的那样使用动态SQL,但这样做会产生一堆不可共享的SQL语句。这将淹没共享池,可能会使其他语句从缓存中老化,并且每次都使用大量CPU对语句进行硬解析。 Oracle的前提是您要解析SQL语句一次,通常使用绑定变量,然后使用绑定变量的不同值多次执行该语句。 Oracle可以通过解析查询,生成查询计划,将查询放在共享池中等只执行一次,然后在再次执行查询时重用所有这些。如果你生成了一堆永远不再使用的SQL语句,因为你使用的是没有绑定变量的动态SQL,那么Oracle最终将花费大量时间来缓存永远不会再次执行的SQL语句,从而推动有用的缓存语句将在共享池中再次使用,这意味着您将在下次遇到这些查询时重新解析这些查询。

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

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

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

答案 1 :(得分: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;

创建了程序

运行procedure dynamic_cur

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

<强>输出

ALLEN
WARD
JONES

注意:正如XQbert所述,dynamic cursor会导致SQL injection,但如果您没有处理任何关键要求,那么安全性不会然后你可以使用它。

答案 2 :(得分:1)

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

因此光标 从学生中选择姓名(滚动);

将被评估为 从学生中选择姓名('1','2');

希望有所帮助