2

パラメータの受け渡し中にこのコードブロックを実行すると問題が発生します。パラメータrfは、WHERE句に入力される変数のリストです。入力する変数の数は静的ではありません。

create or replace
procedure test_pl(rf in varchar2)
IS 
counter number;

BEGIN
  select count(*) into counter from test_pl_imp where column_name in (rf);
  dbms_output.put_line(counter);
END;

実行コードは次のとおりです。

declare 
inparam varchar2(20) := 'xyz,ran,dom';
begin
goku.test_pl(inparam);
end;
/

WHERE条件を次のように実行したい:

where column_name in ('xyz','ran','dom');

xyz,ran,domただし、文字列そのものと見なして実行されます。

それを達成する方法はありますか?

4

4 に答える 4

5

文字列を分解するか、最も簡単な方法は INSTR を使用することです。

rf := ',' || rf || ',';

SELECT
    COUNT(*)
INTO
    counter
FROM
    test_pl_imp
WHERE
    INSTR(rf, ',' || column_name || ',') > 0;

これを少し再設計するオプションがある場合は、文字列の配列を取得し、それを TABLE にキャストして test_pl_imp に結合できるようにする方がクリーンな設計になると思います。

これは次のように行うことができます。

DECLARE
    l_array   goku.t_type := goku.t_type();
BEGIN
    l_array.extend(3);
    l_array(1) := 'xzy';
    l_array(2) := 'abc';
    l_array(2) := '123';

    goku.test_pl(l_array);
END;

そして、上記の呼び出しでタイプとプロシージャを公開する必要があるため、パッケージ仕様には次のものが含まれます。

CREATE OR REPLACE PACKAGE goku
    TYPE r_type IS RECORD (
        search_term    VARCHAR2 (30)
    );

    TYPE t_type IS TABLE OF r_type;

    PROCEDURE test_pl(l_array IN t_type);
END goku;

そして、パッケージ本体は次のようになります。

CREATE OR REPLACE PACKAGE BODY goku
    PROCEDURE test_pl(l_array IN t_type) IS
        v_counter NUMBER;
    BEGIN

        SELECT
            COUNT(tpi.*)
        INTO
            v_counter
        FROM
            test_pl_imp tpi
            , TABLE( CAST(l_array as r_type)) la
        WHERE
            tpi.column_name = la.search_term;

        DBMS_OUTPUT.PUT_LINE('Count :' || v_counter);
    END;
END goku;
于 2012-07-03T12:34:06.773 に答える
1

入力文字列を分割して、一時テーブルまたはテーブル オブジェクトを使用できます。これにより、オプティマイザーが列でインデックスを使用できるようになります。バインドなしで動的 SQL を使用しないでください (セキュリティとパフォーマンス上の理由から)。

テーブル オブジェクトの例を次に示します。セットアップ ( REGEXP_SUBSTRを使用するため 10g ):

CREATE TYPE tab_varchar2 IS TABLE OF VARCHAR2(100);-- longest string
/
CREATE OR REPLACE PROCEDURE test_pl(rf IN VARCHAR2) IS
   lt tab_varchar2;
   counter NUMBER;
BEGIN
   -- split parameter
   SELECT rtrim(regexp_substr(str, '[^,]*,', 1, level), ',')
     BULK COLLECT INTO lt
     FROM (SELECT rf || ',' str FROM dual)
  CONNECT BY level <= length(str) - length(replace(str, ',', ''));
   -- your query
   SELECT count(*)
     INTO counter
     FROM test_pl_imp
    WHERE column_name IN (SELECT column_value FROM TABLE(lt));
   dbms_output.put_line(counter);
END;
/
于 2012-07-03T13:20:49.970 に答える
1

パラメータを単一の文字列(varchar)として宣言すると、一意の文字列として扱われます。パラメータを分割してみることができます: http://www.codeproject.com/Articles/7938/SQL-User-Defined-Function-to-Parse-a-Delimited-Str

于 2012-07-03T12:40:44.027 に答える
1

できるよ:

  1. ストアド プロシージャ クエリを動的クエリに変換し、値を '''abc'',''etc''' として渡します
  2. 文字列を一時テーブルに分割し、それに対して結合/クエリする分割関数を実装します。
  3. INSTR を使用できますが、これにはコツがあります。

私が働いている分割関数を作成しましたが、このようなものにはうまく機能します。


INSTR のトリック: 現在、セパレータとしてコンマを渡しているので、「トリック」で使用したのはカンマですが、セミコロンを使用することもできます。基本的に、'abc,def' ですべてを検索したいとしましょう。文字列を ',abc,def' のようにパディングしてから、検索対象の値を ',abc,' のようにパディングします。このように、「abctest」と「testabc」は見つかりませんが、「abc」は見つかります。

SELECT 
    COUNT(*) 
INTO 
    counter 
FROM 
    test_pl_imp 
WHERE 
    INSTR(',' + rf + ',', ',' + column_name + ',') > 0;

PL/SQL についてよくわからない場合は申し訳ありません... + 記号は || である必要があると思いますが、おわかりいただけると思います。

于 2012-07-03T12:38:15.430 に答える