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句にパラメーターを割り当てる方法はありますか?

カーソルの宣言で配列を使用しようとしましたが、次のようなエラーがポップアップ表示されます: standard types cannot be used

私が使用した:

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ステートメントを1回解析し、通常はバインド変数を使用してから、バインド変数の値を変えてステートメントを何度も実行することを前提としています。Oracleは、クエリの解析、クエリプランの生成、共有プールへのクエリの配置などのプロセスを1回だけ実行し、クエリを再度実行するときにそれらすべてを再利用できます。バインド変数なしで動的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

:で述べたようにXQbert、にdynamic cursorつながりSQL injectionますが、セキュリティが関与していない重要な要件に取り組んでいない場合は、これを使用できます。

于 2012-04-15T16:28:19.487 に答える
1

おそらく、引用符で囲まれたコンマ区切りの値のセットとしてロールを渡すことができます。例: '1'、'2' など この値が varchar 入力変数でプロシージャに渡される場合、テーブル マッチに従って複数の行を取得するために使用できます。

したがって、カーソル SELECT NAME FROM STUDENT WHERE ROLL IN (ロール);

SELECT NAME FROM STUDENT WHERE ROLL IN ('1','2'); として評価されます。

それが役に立てば幸い

于 2012-04-15T16:37:06.920 に答える