PL/SQL が OracleCommand オブジェクトの CommandText であり、ストアド プロシージャまたは関数ではなく、複数のレコード/値の ReturnValue パラメータとして Ref Cursor を使用しようとしている方法が偶数であるかどうかを理解するのに助けが必要です可能。
それが不可能な場合、私がしようとしているのは、不明な数のレコードを更新する PL/SQL ステートメントを発行する方法を見つけることです (WHERE 句に一致するレコードの数によって異なります)。ストアド プロシージャや関数を使用せずに、データベースへの 1 回のラウンドトリップを使用して、OracleDataReader で更新されます。
SQL接続を使用してデータを取得/変更する既存のC#.NET 4.0コードベースとの通信にODP.NETを使用してOracle 11gを使用しています。私が使用している簡略化されたテスト テーブル定義は次のようになります。
CREATE TABLE WorkerStatus
(
Id NUMERIC(38) NOT NULL
,StateId NUMERIC(38) NOT NULL
,StateReasonId NUMERIC(38) NOT NULL
,CONSTRAINT PK_WorkerStatus PRIMARY KEY ( Id )
)
次のように、テーブルに 3 つのテスト値を事前に入力します。
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO WorkerStatus (Id, StateId, StateReasonId)
VALUES (1, 0, 0)';
EXECUTE IMMEDIATE 'INSERT INTO WorkerStatus (Id, StateId, StateReasonId)
VALUES (2, 0, 0)';
EXECUTE IMMEDIATE 'INSERT INTO WorkerStatus (Id, StateId, StateReasonId)
VALUES (3, 0, 0)';
END;
Oracle_UpdateWorkerStatus2 という名前のスクリプト ファイルからロードされ、OracleCommand.CommandText に含まれる既存の SQL ステートメントは次のようになります。
DECLARE
TYPE id_array IS TABLE OF WorkerStatus.Id%TYPE INDEX BY PLS_INTEGER;
t_ids id_array;
BEGIN
UPDATE WorkerStatus
SET
StateId = :StateId
,StateReasonId = :StateReasonId
WHERE
StateId = :CurrentStateId
RETURNING Id BULK COLLECT INTO t_Ids;
SELECT Id FROM t_Ids;
END;
ORA-01036「不正な変数名/番号」エラーが発生している場所を特定するために、小さな C# テスト プログラムを作成しました。本体は次のようになります。
using System;
using System.Configuration;
using System.Data;
using System.Text;
using Oracle.DataAccess.Client;
using Oracle.DataAccess.Types;
namespace OracleDbTest
{
class Program
{
static void Main(string[] args)
{
// Load the SQL command from the script file.
StringBuilder sql = new StringBuilder();
sql.Append(Properties.Resources.Oracle_UpdateWorkerStatus2);
// Build and excute the command.
OracleConnection cn = new OracleConnection(ConfigurationManager.ConnectionStrings["OracleSystemConnection"].ConnectionString);
using (OracleCommand cmd = new OracleCommand(sql.ToString(), cn))
{
cmd.BindByName = true;
cn.Open();
OracleParameter UpdatedRecords = new OracleParameter();
UpdatedRecords.OracleDbType = OracleDbType.RefCursor;
UpdatedRecords.Direction = ParameterDirection.ReturnValue;
UpdatedRecords.ParameterName = "rcursor";
OracleParameter StateId = new OracleParameter();
StateId.OracleDbType = OracleDbType.Int32;
StateId.Value = 1;
StateId.ParameterName = "StateId";
OracleParameter StateReasonId = new OracleParameter();
StateReasonId.OracleDbType = OracleDbType.Int32;
StateReasonId.Value = 1;
StateReasonId.ParameterName = "StateReasonId";
OracleParameter CurrentStateId = new OracleParameter();
CurrentStateId.OracleDbType = OracleDbType.Int32;
CurrentStateId.Value = 0;
CurrentStateId.ParameterName = "CurrentStateId";
cmd.Parameters.Add(UpdatedRecords);
cmd.Parameters.Add(StateId);
cmd.Parameters.Add(StateReasonId);
cmd.Parameters.Add(CurrentStateId);
try
{
cmd.ExecuteNonQuery();
OracleDataReader dr = ((OracleRefCursor)UpdatedRecords.Value).GetDataReader();
while (dr.Read())
{
Console.WriteLine("{0} affected.", dr.GetValue(0));
}
dr.Close();
}
catch (OracleException e)
{
foreach (OracleError err in e.Errors)
{
Console.WriteLine("Message:\n{0}\nSource:\n{1}\n", err.Message, err.Source);
System.Diagnostics.Debug.WriteLine("Message:\n{0}\nSource:\n{1}\n", err.Message, err.Source);
}
}
cn.Close();
}
Console.WriteLine("Press Any Key To Exit.\n");
Console.ReadKey(false);
}
}
}
パラメータ名の変更、UpdatedRecords パラメータの命名と非命名、順序を変更して UpdatedRecords が最初または最後になるようにしました。私がこれまでに見つけた最も近いものは、次の StackOverflow の質問 ( C# から Out-parameter として Ref Cursor を使用して Oracle 関数を呼び出す方法は? ) ですが、私が知る限り、それでもストアド関数を使用しています。
Oracle_UpdateWorkerStatus2 PL/SQLスクリプトをSQL Developerから実行すると、「Enter Binds」ダイアログが開き、上記のコードのようにCurentStateId、StateIdおよびStateReasonIdの値を入力しますが、次のエラー・レポートが表示されます:
Error report:
ORA-06550: line 13, column 17:
PL/SQL: ORA-00942: table or view does not exist
ORA-06550: line 13, column 2:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
WorkerStatus テーブルを定義し、id_array 型の t_Ids 変数もテーブルとして宣言したときに、テーブルが存在しないと表示される理由がよくわかりません。ここで何か助けていただければ幸いです。