web-dev-qa-db-ja.com

IN句のパラメータを使用したOracleストアドプロシージャ

IN句のフィードに使用される可変数のパラメータ値を受け入れるOracleストアドプロシージャを作成するにはどうすればよいですか?

これが私が達成しようとしていることです。更新する行の主キーの変数リストを渡すためにPLSQLで宣言する方法がわかりません。

FUNCTION EXECUTE_UPDATE
  ( <parameter_list>
   value IN int)
  RETURN  int IS
BEGIN 
    [...other statements...]
    update table1 set col1 = col1 - value where id in (<parameter_list>) 

    RETURN SQL%ROWCOUNT ;
END;

また、このプロシージャをC#から呼び出したいので、.NET機能と互換性がある必要があります。

ありがとう、ロバート

13
Robert Mircea

要素自体に文字列が含まれないことを100%確信できると仮定すると、CSVを使用するのがおそらく最も簡単な方法です。

これを行う別の、おそらくより堅牢な方法は、文字列のテーブルとしてカスタム型を作成することです。文字列が100文字を超えることはないと仮定すると、次のようになります。

_CREATE TYPE string_table AS TABLE OF varchar2(100);
_

次に、このタイプの変数をストアドプロシージャに渡して、直接参照できます。あなたの場合、次のようなものです。

_FUNCTION EXECUTE_UPDATE(
    identifierList string_table,
    value int)
RETURN int
IS
BEGIN

    [...other stuff...]

    update table1 set col1 = col1 - value 
    where id in (select column_value from table(identifierList));

    RETURN SQL%ROWCOUNT;

END
_

table()関数は、カスタムタイプを単一の列「COLUMN_VALUE」を持つテーブルに変換します。このテーブルは、他のテーブルと同じように扱うことができます(結合、この場合は副選択も同様です)。

これの利点は、Oracleがコンストラクタを作成することです。したがって、ストアドプロシージャを呼び出すときは、次のように記述できます。

_execute_update(string_table('foo','bar','baz'), 32);
_

このコマンドのビルドは、C#からプログラムで処理できると思います。

余談ですが、私の会社では、文字列、double、intなどのリストの標準として定義されているこれらのカスタムタイプがいくつかあります。また、 Oracle JPublisher を使用して、これらのタイプから対応するJavaオブジェクトに直接マップできるようにします。ざっと見てみましたが、何も見つかりませんでした。 C#に直接相当します。Java開発者がこの質問に出くわした場合に備えて言及したいと思いました。

27
Ashley Mercer

Mark A. Williamsによる次の記事を見つけました。これは、このスレッドへの追加として役立つと思いました。この記事では、連想配列(TYPE myType IS TABLE OF mytable.row%TYPE INDEX BY PLS_INTEGER)を使用してC#からPL/SQLプロシージャに配列を渡す良い例を示しています。

マークA.ウィリアムズによる素晴らしい記事

2
bowthy

可変数のパラメータを持つプロシージャを直接作成する方法はないと思います。ただし、この問題には少なくとも部分的な解決策がいくつかあり、 ここ で説明されています。

  1. いくつかの典型的な呼び出しタイプがある場合、プロシージャのオーバーロードが役立つ場合があります。
  2. パラメータの数に上限がある場合(およびそのタイプも事前にわかっている場合)、パラメータのデフォルト値が役立つ場合があります。
  3. 最良のオプションは、データベースカーソルへのポインタであるカーソル変数の使用です。

残念ながら、私は.NET環境の経験がありません。

1
rics

長いパラメーターリストを使用して、値をテーブルコンストラクターにロードしないのはなぜですか?これがこのトリックのSQL/PSMです

UPDATE Foobar
   SET x = 42
 WHERE Foobar.keycol
      IN (SELECT X.parm
            FROM (VALUES (in_p01), (in_p02), .., (in_p99)) X(parm)
           WHERE X.parm IS NOT NULL);
0
Joe Celko