
《.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 として取得する
まとめ
ロケールはあんま関係なかったけど知れてよかった。