IN節のパラメーターを持つOracleストアドプロシージャ
-
04-07-2019 - |
質問
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機能と互換性がある必要があります。
ありがとう、 ロバート
解決
CSVを使用するのがおそらく最も簡単な方法です。要素に文字列が含まれないことを100%確信できる場合は、
これを行うための、おそらくより堅牢な代替方法は、文字列のテーブルとしてカスタムタイプを作成することです。あなたの文字列が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()
関数は、カスタムタイプを単一の列&quot; COLUMN_VALUE&quot;を持つテーブルに変換します。これにより、他のテーブルと同様に処理できます(結合、またはこの場合、サブセレクト)。
この利点は、Oracleがコンストラクタを作成することです。そのため、ストアドプロシージャを呼び出すときは、次のように記述できます。
execute_update(string_table('foo','bar','baz'), 32);
このコマンドをC#からプログラムで作成できると想定しています。
余談ですが、私の会社では、文字列、倍精度、整数などのリストの標準として定義されたこれらのカスタムタイプがいくつかあります。また、 Oracle JPublisher を使用して、これらのタイプから対応するJavaオブジェクトに直接マップします。ざっと見て回ったのですが、C#に直接相当するものが見つかりませんでした。 Java開発者がこの質問に出くわした場合に備えて言及すると思いました。
他のヒント
Mark A. Williamsによる次の記事を見つけました。この記事は、このスレッドに役立つと思います。この記事は、連想配列(TYPE myType IS TABLE OF mytable.row%TYPE INDEX BY PLS_INTEGER)を使用して、C#からPL / SQLプロシージャに配列を渡す良い例を示しています。
可変数のパラメータを持つプロシージャを直接作成する方法はないと思います。 ただし、こちら。
- 典型的な呼び出しタイプがある場合、プロシージャのオーバーロードが役立つ場合があります。
- パラメーターの数に上限がある場合(およびそのタイプも事前にわかっている場合)、パラメーターのデフォルト値が役立つ場合があります。
- 最適なオプションは、データベースカーソルへのポインターであるカーソル変数の使用です。
残念ながら、.NET環境の経験はありません。
長いパラメーターリストを使用して、値をテーブルコンストラクターに読み込むだけではどうですか?これがこのトリックの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);
なぜストアドプロシージャである必要があるのですか?プログラムで準備済みステートメントを作成できます。
Oracleでこれを行ったことはありませんが、SQL Serverでは、関数を使用してCSV文字列をテーブルに変換し、IN句で使用できます。これをOracle用に書き直すのは簡単です(私は思う!)
CREATE Function dbo.CsvToInt ( @Array varchar(1000))
returns @IntTable table
(IntValue nvarchar(100))
AS
begin
declare @separator char(1)
set @separator = ','
declare @separator_position int
declare @array_value varchar(1000)
set @array = @array + ','
while patindex('%,%' , @array) <> 0
begin
select @separator_position = patindex('%,%' , @array)
select @array_value = left(@array, @separator_position - 1)
Insert @IntTable
Values (Cast(@array_value as nvarchar))
select @array = stuff(@array, 1, @separator_position, '')
end
return
end
その後、CSV文字列(例: '0001,0002,0003')を渡して、次のような操作を実行できます
UPDATE table1 SET
col1 = col1 - value
WHERE id in (SELECT * FROM csvToInt(@myParam))
AskTom Webサイトには、CSV文字列を解析する関数を作成し、これをSQL Serverの例と同様の方法でステートメントで使用する方法を示す記事があります。