2016-08-15 34 views
1

私はC#アプリケーションで作業しており、SQL文をSQL ServerからOracleに変換しています。私は値がメインテーブルと関連テーブルのいくつかのレコードに挿入されている1つのブロックを持っています。メインテーブルに重複レコードが存在するかどうかを確認し、C#ページにフラグ値を返します。そうでない場合はレコードを挿入し、メインテーブルのPKを取得して関連テーブルへの挿入に使用します。これまでのところ、ブロック内のOracleから値を返すための最良の方法は、InputOutputパラメータを使用することでした。 (ステートメントのどこにでもBEGIN/ENDブロックがあれば、INTOなしでSELECTすることはできません)Oracleブロック内のバインド変数(C#出力パラメータ)にリテラルを割り当てます。

SQL Serverでは、レコードを返さないSELECTステートメントから変数をロードしようとすると、変わらない。 Oracleでは、これを処理するためにNO_DATA_FOUND例外を設定する必要があることがわかりました。復帰フラグを設定する例外が必要です。 「ORA-06502:PL/SQL:数値エラーまたは値エラー」が表示されます。

BEGIN 
    SELECT ID INTO :REPORTID FROM Report WHERE ExtractDt=:EXTRACTDT 
     AND REGION=:RGN; 
    EXCEPTION WHEN NO_DATA_FOUND THEN 
     SELECT -1 INTO :REPORTID FROM DUAL; 
END; 

これは私が来た最も近いものです。 SELECT -1 ...行でエラーが発生します。

REPORTIDはNUMBER型のパラメータとして渡され、InputOutputの方向に渡されます。 EXTRACTDTは有効な値を持つ日付で、RGNはvarchar(2)文字列です。両方の入力パラメータ。

EDIT:ブロックは、C#からOracleに送られているかのサンプル:

OracleCommand psCmd = new OracleCommand(); 
psCmd.Connection = Conn; //Previously defined, valid & opened 
psCmd.CommandType = CommandType.Text; 
psCmd.CommandText = "{SQL STRING CONTAINING BLOCK, AS ABOVE}"; 
psCmd.Parameters.Add(new OracleParameter("REPORTID", OracleType.Number, 10) { Direction = ParameterDirection.InputOutput, Value = DBNull.Value }); 
psCmd.Parameters.Add(new OracleParameter("EXTRACTDT", OracleType.DateTime) { Value = dtExtract }); //C# DateTime with valid date 
psCmd.Parameters.Add(new OracleParameter("RGN", OracleType.VarChar, 2) { Value = sRegion }); //C# String, 2 characters 
psCmd.ExecuteNonQuery(); 
Int32 iID = (Int32)psCmd.Parameters["REPORTID"].Value; 
//Cleanup, etc. 
+0

これは大きなブロックの単純化された部分です。完全なステートメントは戻り値をテストし、重複が見つからない場合は挿入し、フラグまたはIDをC#ページに返します。 – BlueKnot

+0

REPORTIDの方向はInputOutputです(私はあなたのC#コードを参照していると思います)。 REPORTIDはどのようにPL/SQLコードで定義されていますか?これがプロシージャーの場合は、INまたはIN OUTと定義されていますか? 1つのコードスニペットに基づいて明確ではありません – tbone

+0

@tboneあらかじめ定義された手順ではありません。ブロックはSQL文(C#文字列)として作成され、parametercollectionとともにOracleCommandオブジェクトに渡されます。 (文字列は、関連するテーブルのエントリ数[スニペットには表示されていません]が可変なので動的に作成されます)。 SQL Serverのバージョンでは、ブロックの先頭にDECLAREがありました。しかし、オラクルは私に 'Not all paramters bound'というエラーを出し、それを削除して代わりにパラメータ・コレクションの一部として渡す必要がありました。 – BlueKnot

答えて

0

問題はOracleDbTypeの代わりのDbTypeのを使用しているということはおそらくです。私は通常、OracleDbTypeを使用していますが、この場合、ある変数に数字を選択しています(-1を選択...)し、Intの代わりにDecimal型を戻しています。以下の簡単な例は私のために働きます:

string connStr = "User Id=myuser;Password=mypass;Data Source=myinstance;"; 
       using (OracleConnection con = new OracleConnection(connStr)) 
       { 
        string s = @"BEGIN 
        select 1 into :TESTID from dual where 1=0; 
        EXCEPTION 
        when no_data_found then 
        select -1 into :TESTID from dual; 
        END;"; 

        using (OracleCommand cmd = new OracleCommand(s, con)) 
        { 
         con.Open(); 
         Console.WriteLine("Running statement"); 

         OracleParameter prm = new OracleParameter(); 
         cmd.Parameters.Clear(); 
         cmd.BindByName = true; 

         //prm = new OracleParameter("TESTID", OracleDbType.Int32, ParameterDirection.InputOutput); prm.Value = 0; cmd.Parameters.Add(prm); 
         prm = new OracleParameter(); 
         prm.ParameterName = "TESTID"; 
         prm.DbType = DbType.Int32; // don't use OracleDbType, will return decimal in some cases, not int 
         prm.Direction = ParameterDirection.InputOutput; 
         prm.Value = 0; 
         cmd.Parameters.Add(prm); 

         cmd.ExecuteNonQuery(); 

         // may have cast/conversion issues here if using OracleDbType 
         int id = Convert.ToInt32(cmd.Parameters["TESTID"].Value); 

         Console.WriteLine("ID is: " + id); 

         con.Close(); 
        } 
       } 
+0

ありがとう!それは私をそこに入れた。 DBTypeがオプションであることは知られていませんでしたが(コンストラクタでは機能しませんが、私は以下のように書き直すことができました) 'psCmd.Parameters.Add(新しいOracleParameter(){ParameterName =" REPORTID " 、DbType = System.Data.DbType.Int32、Direction = ParameterDirection.InputOutput、Value = DBNull.Value}); ' – BlueKnot

関連する問題