見出し画像

《.Net》NpgsqlでPostgreSQL接続時のmoney型の扱いに困った

〈筆者環境はASP.NETです〉
〈備忘録的に簡単な書き留めです〉
〈データベース初心者です〉

.NETのPostgreSQL接続管理をしてくれるNpgsqlでmoney型のカラムのフィールドを取得すると、何故か1/100になって返ってくる……

・まず、日本語環境でデータベースを作成すると普通はロケール情報が'Japanese_Japan.932'(日本語:UTF8)となる。
・SET lc_monetary = ~;は現セッションでのロケール設定のみの設定(セッションを再接続するとデフォルト(DB)の設定に戻る?)
・'C'(非地域依存:ASCII なんですかね?)

create table tbl(
    mny money
);

set lc_monetary = 'C';
insert into tbl values('10.256');
set lc_monetary = 'Japanese_Japan.932';
insert into tbl values('10.256');

set lc_monetary = 'C';
select mny from tbl;

↓↓↓↓↓↓↓↓
  mny
--------
  $10.26    $ → $
  $0.10     円 → $


set lc_monetary = 'Japanese_Japan.932';
select mny from tbl;

↓↓↓↓↓↓↓↓
  mny
--------
  \1026     $ → 円
  \10       円 → 円

まず小数の概念を捨てる。

内部で整数で扱ってるってどこかで見たけど公式ソースは不明
許容範囲から?
moeny:-92233720368547758.08 から +92233720368547758.07
bigint:-9223372036854775808から+9223372036854775807

$ロケールでINSERTする時、数値の小数第3位以降は"丸められる"
$ロケールでSELECTする時、数値の1桁目が"小数第二位になる"
INSERT($)         内部             SELECT($)
10.256      →      1026      →      $10.26
           round
INSERT(円)         内部             SELECT($)
10.256      →        10        →       $0.10

円ロケールでINSERTする時、数値の小数は"丸められる"
円ロケールでSELECTする時、数値の1桁目が"1の位になる"
INSERT(円)         内部           SELECT(円)
10.256       →       10       →       \10
             round
INSERT($)         内部           SELECT(円)
10.256      →      1026      →      \1026

問題のNpgsql

たぶん整数通貨単位を考慮してないので返ってきたmoney型(DB内部の整数の状態のまま)を何でもかんでも1/100にしてる。
参考サイト:

テーブル取得クエリで set lc_monetary = 'Japanese_Japan.932'; しても、Npgsqlで読み取る時に1/100にされる。
→ データベースのロケールパラメータを小数通貨ロケールにする、
 カラムの型をdecimalにする、
 クエリで [money型カラム]::decimal として取得する

まとめ

ロケールはあんま関係なかったけど知れてよかった。

いいなと思ったら応援しよう!