web-dev-qa-db-ja.com

OracleDataAdapter.Fill()からDataTableにデータを入力するときに、「指定されたキャストは無効です」

私はこの質問をGoogle(またはStackOverflow)のどこにも見つけることができないようで、本当に驚いたので、同じ状況にいる他の人を助けるために、ここに置いておきます。

Oracle Sql Developerで正常に実行されるSQLクエリがありますが、_C#_ usingadapter.Fill(table)を使用して結果を取得すると、_Specified cast is not valid_エラー(_System.InvalidCastException_)が発生します。 )。

C#コードの縮小版は次のとおりです。

_var resultsTable = new DataTable();

using (var adapter = new OracleDataAdapter(cmd))
{
    var rows = adapter.Fill(resultsTable);  // exception thrown here, but sql runs fine on Sql Dev

    return resultsTable;
}
_

そして、これがSQLの簡略版です。

_SELECT acct_no, market_value/mv_total
FROM myTable
WHERE NVL(market_value, 0) != 0
AND NVL(mv_total, 0) != 0
_

除算句を削除しても、エラーにはなりません。そのためです。ただし、market_valueと_mv_total_はどちらもタイプNumber(19,4)であり、Oracleアダプターが10進数を予期していることがわかります。 SqlDevでは機能するのにC#では機能しないのはなぜですか?

21
namford

私自身の質問に答える:

したがって、Oracleの数値タイプはC#の小数点以下の桁数よりもはるかに多くの小数点以下の桁数を保持できるようです。OracleがC#の小数点以下の桁数を超えて返そうとすると、InvalidCastExceptionがスローされます。

解決?

SQLで、小数点以下の桁数が多すぎる可能性のある結果を適切なものに丸めます。だから私はこれをしました:

SELECT acct_no, ROUND(market_value/mv_total, 8)  -- rounding this division solves the problem
FROM myTable
WHERE NVL(market_value, 0) != 0
AND NVL(mv_total, 0) != 0

そしてそれはうまくいった。

要点は次のとおりです。Oracleの数値タイプとC#の10進数の間の非互換性。無効なキャスト例外を回避するために、Oracleの小数点以下の桁数を制限してください。

これが他の誰かに役立つことを願っています!

39
namford

私はこのスレッドが本当に古いことを知っています。しかし、同様の問題がありました。

OracleDecimal列でOracleメソッドTO_BINARY_DOUBLEを使用する必要がある最善の解決策

7
AAGF

私はこれがすでに答えられていることを知っていますが、私が使用する別の選択肢も見つけました。困っていたフィールドでCASTを使用しました。

OPのSELECTコマンドに基づく:

SELECT acct_no, CAST((market_value/mv_total) AS DECIMAL(14,4))  -- CAST to decimal here
FROM myTable
WHERE NVL(market_value, 0) != 0
AND NVL(mv_total, 0) != 0
1