1

これは、パラメーターとして州コードが 1 つしかない場合に機能します。

parm_list に複数の state_code がある場合、コードを機能させるにはどうすればよいですか?

要件:

(1)カーソル定義に状態コードをハードコーディングしたくない

(2) where 句で複数の州コードを許可したい

例: parm_list = ('NY','NJ','NC')に対してこのコードを実行します。parm_list の単一引用符と「where state_code in 」クエリの単一引用符を調整する際に問題が発生しています。

set serveroutput on;

DECLARE
parm_list varchar2(40);

cursor get_state_codes(in_state_codes varchar2)
is
select state_name, state_code from states
where state_code in (in_state_codes);

BEGIN
 parm_list := 'NY';
 for get_record in get_state_codes(parm_list) loop
  dbms_output.put_line(get_record.state_name || get_record.state_code);
 end loop;
END;
4

2 に答える 2

11

コーディングの観点からは、動的 SQL を使用するのが最も簡単な方法です。ただし、動的 ​​SQL の問題は、クエリのすべての異なるバージョンをハード解析する必要があることです。これは、CPU に負担をかける可能性があるだけでなく、共有プールを共有不可能な多数の SQL ステートメントで溢れさせる可能性があり、プッシュします。キャッシュしたいステートメントがなくなると、よりハードな解析と共有プールの断片化エラーが発生します。これを 1 日 1 回実行している場合、それはおそらく大きな問題ではありません。何百人もの人々が 1 日に何千回も実行している場合、それはおそらく大きな問題です。

動的 SQL アプローチの例

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    l_deptnos  varchar2(100) := '10,20';
  3    l_rc       sys_refcursor;
  4    l_dept_rec dept%rowtype;
  5  begin
  6    open l_rc for 'select * from dept where deptno in (' || l_deptnos || ')';
  7    loop
  8      fetch l_rc into l_dept_rec;
  9      exit when l_rc%notfound;
 10      dbms_output.put_line( l_dept_rec.dname );
 11    end loop;
 12    close l_rc;
 13* end;
SQL> /
ACCOUNTING
RESEARCH

PL/SQL procedure successfully completed.

または、コレクションを使用することもできます。これには、単一の共有可能なカーソルが生成されるという利点があるため、ハード解析や共有プールのフラッディングについて心配する必要はありません。ただし、おそらくもう少しコードが必要です。コレクションを扱う最も簡単な方法

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    l_deptnos  tbl_deptnos := tbl_deptnos(10,20);
  3  begin
  4    for i in (select *
  5                from dept
  6               where deptno in (select column_value
  7                                  from table(l_deptnos)))
  8    loop
  9      dbms_output.put_line( i.dname );
 10    end loop;
 11* end;
SQL> /
ACCOUNTING
RESEARCH

PL/SQL procedure successfully completed.

一方、コンマ区切りの値のリストから実際に開始する必要がある場合は、その文字列を使用する前にコレクションに解析する必要があります。区切られた文字列を解析するにはさまざまな方法があります。私の個人的なお気に入りは、階層クエリで正規表現を使用することですが、手続き型のアプローチを書くこともできます。

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    l_deptnos     tbl_deptnos;
  3    l_deptno_str  varchar2(100) := '10,20';
  4  begin
  5    select regexp_substr(l_deptno_str, '[^,]+', 1, LEVEL)
  6      bulk collect into l_deptnos
  7      from dual
  8   connect by level <= length(replace (l_deptno_str, ',', NULL));
  9    for i in (select *
 10                from dept
 11               where deptno in (select column_value
 12                                  from table(l_deptnos)))
 13    loop
 14      dbms_output.put_line( i.dname );
 15    end loop;
 16* end;
 17  /
ACCOUNTING
RESEARCH

PL/SQL procedure successfully completed.
于 2012-06-14T21:48:10.050 に答える
7

1 つのオプションは、IN の代わりに INSTR を使用することです。

SELECT uo.object_name
      ,uo.object_type
FROM   user_objects uo
WHERE  instr(',TABLE,VIEW,', ',' || uo.object_type || ',') > 0;

これは見苦しく見えますが、うまく機能し、テスト対象の列のインデックスが使用されない限り (これによりインデックスの使用が妨げられるため)、パフォーマンスはそれほど低下しません。たとえば、テスト対象の列が主キーである場合、これは絶対に使用しないでください。

別のオプションは次のとおりです。

SELECT uo.object_name
      ,uo.object_type
FROM   user_objects uo
WHERE  uo.object_type IN
       (SELECT regexp_substr('TABLE,VIEW', '[^,]+', 1, LEVEL)
        FROM   dual
        CONNECT BY regexp_substr('TABLE,VIEW', '[^,]+', 1, LEVEL) IS NOT NULL);

この場合、値のリストを単一の varchar 変数に連結し、カンマ (または任意のもの) で区切る必要があります。

于 2012-06-15T04:28:38.830 に答える