【ODP.NET】NUMBER項目をNVLで取得して文字列にキャストすると、定義された小数桁以下にゼロが追加されてしまう

【ODP.NET】NUMBER項目をNVLで取得して文字列にキャストすると、定義された小数桁以下にゼロが追加されてしまう
ODP.NET経由で取得したNUMBER項目をToStringで文字列にキャストすると、データベースに定義した小数桁以下に、ゼロが勝手に付いてきてしまうという現象が発生しました。

言葉で説明するとちょっとわかりにくいのですが、データベース上では「1.2」と格納されているのに、VB.NETで文字列にすると「1.20」と表示されてしまう、という感じです。

環境

実行環境は以下の通りです。
  • Oracle 12c
  • Oracle.DataAccess 4.122.1.0
  • .NET Framework 4.6
  • Visual Studio 2015 Professional Update3
  • 言語:VB.NET

発生条件

発生条件は以下の通りです。
  • テーブル項目はNUMBER型で小数あり、小数部の桁数が奇数桁の場合
  • ODP.NETを使ってVB.NETアプリから検索
  • SELECT文の項目にNVL関数を使用
  • 検索結果をToStringで文字列として表示

検証

簡単なテーブルを作って検証してみました。

テーブルは以下の通りです。
CREATE TABLE A(
    N1 NUMBER(5,1)
  , N2 NUMBER(5,2)
  , N3 NUMBER(5,3)
  , N4 NUMBER(5,4)
)

格納するデータは以下の通りです。

N1 N2 N3 N4
1.2 1.2 1.234 1.234

問題なしのパターン

まずは以下のSELECT文をアプリから実行して、実行結果をToStringで文字で表示してみます。

<SELECT文>
SELECT N1, N2, N3, N4 FROM A;


<検索結果>
N1 N2 N3 N4
1.2 1.2 1.234 1.234
これは問題ありませんでした。

問題ありのパターン

次に、問題が発生したパターンです。
SELECT文の項目をNVLにしたSQLを実行して、実行結果をToStringで文字で表示します。

<SELECT文>
SELECT
NVL(N1,0) AS N1_NVL
, NVL(N2,0) AS N2_NVL
, NVL(N3,0) AS N3_NVL
, NVL(N4,0) AS N4_NVL
FROM A;

<検索結果>
N1 N2 N3 N4
1.20 1.20 1.2340 1.2340
各項目の小数点以下について、データベース上では末尾にゼロは登録されていないのですが、勝手にゼロが付いてきます。
さらに、N1のカラム定義では小数部は1桁のはずですが、2桁で表示されてしまいます。(N3も定義上では小数部3桁ですが、4桁になってしまいます。)


対応方法

根本原因はわかっていませんが、対応方法としては二通りの候補があります。

NVLの第二引数に数値書式を指定する

SELECT文のNVL関数で、第二引数のゼロを数値書式にすると、期待した結果が得られました。
この結果を見ると、NVLの内部的なキャストで何か起こっているのかなぁという印象です。

以下のようにSQLを修正します。

<SELECT文>
SELECT
NVL(N1,0D) AS N1_NVLD
, NVL(N2,0D) AS N2_NVLD
, NVL(N3,0D) AS N3_NVLD
, NVL(N4,0D) AS N4_NVLD
FROM A;
NVLの第二引数に数値書式を指定しています。
「0D」はDecimalの略です。

<検索結果>
N1 N2 N3 N4
1.2 1.2 1.234 1.234

ToStringに書式設定する

VB側で対応するとしたら、以下のような感じでしょうか。
CDec(ds.Tables(0).Rows(i)("N1_NVL")).ToString("#.#") 
CDec(ds.Tables(0).Rows(i)("N1_NVL")).ToString("#.###")

まとめ

今回の対応方針としては、NVLの第二引数に数値書式を指定する方法を選択しました。

ゼロがあっても無くても数値としては同値だから問題ないでしょ、という意見もありましたが、有効桁数が変わるし文字としては同値にならないということで、対応方法を考えてみました。

以上

<スポンサーリンク>


0 件のコメント :

コメントを投稿