Sql 动态游标

Sql 动态游标,sql,oracle,select,plsql,cursor,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. CURSOR C IS SELECT NAME FROM ST

我对语句使用光标

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.
CURSOR C IS SELECT NAME FROM STUDENT WHERE ROLL IN (rolls);
--rolls is an array initialized with the required roll numbers.
执行此操作后,我能够检索roll=1的所有记录

现在,我需要检索组的记录(可能通过光标),如下所示:

SELECT NAME FROM STUDENT WHERE ROLL IN (2, 4, 6);
但是in子句中的值只有在运行时才知道。我该怎么做?也就是说,是否有任何方法可以将参数指定给游标的WHERE子句

我尝试在游标声明中使用数组,但出现了一个错误,提示:无法使用标准类型

我用过:

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.
CURSOR C IS SELECT NAME FROM STUDENT WHERE ROLL IN (rolls);
--rolls is an array initialized with the required roll numbers.
创建的过程

运行
过程
dynamic\u cur

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

ALLEN
WARD
JONES
注意:正如
XQbert
所述,
动态光标
会导致
SQL注入
,但如果您没有处理任何关键需求,而不涉及安全性,则可以使用此功能

创建的过程

运行
过程
dynamic\u cur

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

ALLEN
WARD
JONES

注意:如
XQbert
所述,
动态光标
会导致
SQL注入
,但如果您没有处理任何关键需求,在不涉及安全性的情况下,您可以使用它。

也许您可以将滚动作为一组引号分隔的值传递。 e、 g.“1”、“2”等 如果将此值传递到varchar输入变量中的过程中,则可以使用它根据表匹配获取多行

因此光标 从登记的学生中选择姓名(转学)

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


希望它有帮助

也许您可以将rolls作为一组带引号的逗号分隔值传递。 e、 g.“1”、“2”等 如果将此值传递到varchar输入变量中的过程中,则可以使用它根据表匹配获取多行

因此光标 从登记的学生中选择姓名(转学)

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


希望对您有所帮助首先,我假设您的过程的参数实际上与
STUDENT
表中的列名称不匹配。如果您确实对发布的语句进行了编码,
roll
将解析为列的名称,而不是参数或局部变量,因此此语句将返回
STUDENT
表中
roll
列为
非空的每一行

CURSOR C 
    IS SELECT NAME 
         FROM STUDENT 
        WHERE ROLL = roll;
其次,虽然可以像@Gaurav Soni所建议的那样使用动态SQL,但这样做会生成一系列不可共享的SQL语句。这将淹没共享池,可能会使缓存中的其他语句老化,并且每次都会使用大量CPU硬解析语句。Oracle是建立在这样一个前提之上的:您将只解析一次SQL语句,通常使用绑定变量,然后使用不同的绑定变量值多次执行该语句。Oracle可以只执行一次查询解析、生成查询计划、将查询放入共享池等过程,然后在再次执行查询时重用所有这些过程。如果由于使用的是不带绑定变量的动态SQL,因此生成了一组永远不会再次使用的SQL语句,Oracle将花费大量时间缓存永远不会执行的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.

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

CURSOR C 
    IS SELECT NAME 
         FROM STUDENT 
        WHERE ROLL = roll;
其次,虽然可以像@Gaurav Soni所建议的那样使用动态SQL,但这样做会生成一系列不可共享的SQL语句。这将淹没共享池,可能会使缓存中的其他语句老化,并且每次都会使用大量CPU硬解析语句。Oracle是建立在这样一个前提之上的:您将只解析一次SQL语句,通常使用绑定变量,然后使用不同的绑定变量值多次执行该语句。Oracle可以只执行一次查询解析、生成查询计划、将查询放入共享池等过程,然后在再次执行查询时重用所有这些过程。如果由于使用的是不带绑定变量的动态SQL,因此生成了一组永远不会再次使用的SQL语句,Oracle将花费大量时间缓存永远不会执行的SQL语句,将有用的缓存语句从共享池中推出,这意味着您将不得不在下次遇到这些查询时重新解析它们

此外,您还面临SQL注入攻击。攻击者可以利用该过程从任何表读取任何数据或执行存储过程所有者有权访问的任何函数。这将是一个重大的安全漏洞,即使您的应用程序不是partic