SQL ServerでFloatをDecimal(28,10)に変換する必要があります。私の問題は、floatの性質と変換の方法により、floatをキャストするだけで、ユーザーには間違った数値のように見える可能性があることです。
例えば:
Float: 280712929.22
Cast as Decimal: 280712929.2200000300
What I think I want: 280712929.2200000000
Floatの動作(おおよそのデータ型など)については少し理解していますが、最後に300が追加される理由を理解するには確かに十分ではありません。それは変換の副作用としての単なるゴミですか、それともフロートが実際に保存しているものをより正確に表現したものですか?私には、それは薄い空気から正確に引き出されたように見えます。
最終的には、正確であるだけでなく、「正しく」見える必要があります。末尾のゼロを追加したように見えるので、その一番下の数値を取得する必要があると思います。これは可能ですか?これは良い考えですか、それとも悪い考えですか。その理由は何ですか。他の提案は大歓迎です。
他のいくつかの例:
Float: 364322379.5731
Cast as Decimal: 364322379.5730999700
What I want: 364322379.5731000000
Float: 10482308902
Cast as Decimal: 10482308901.9999640000
What I want: 10482308902.0000000000
補足:これらの値を入力する新しいデータベーステーブルは、ユーザーが読み取ることができます。現在、実際には小数点以下2桁しか必要ありませんが、将来変更される可能性があるため、Decimal(28,10)を使用することにしました。長期的な目標は、データを取得しているfloat列も10進数に変換することです。
編集:時々、私が持っている浮動小数点数は、私がこれまでに必要とするよりも多くの小数点以下の桁数を持っています、例えば:-0.628475064730907。この状況では、-0.6284750647へのキャストで問題ありません。基本的に、小数点以下10桁になるまで、フロートの最後にゼロを追加する結果が必要です。
丸めるために1回キャストし、小数点以下の桁数を戻すために1回キャストする必要があります(確かに、STR
、ROUND
などを使用する他の方法もあります):
DECLARE @c TABLE(x FLOAT);
INSERT @c SELECT 280712929.22;
INSERT @c SELECT 364322379.5731;
INSERT @c SELECT 10482308902;
SELECT x,
d = CONVERT(DECIMAL(28,10), x),
rd = CONVERT(DECIMAL(28,10), CONVERT(DECIMAL(28,4), x))
FROM @c;
結果:
x d rd
-------------- ---------------------- ----------------------
280712929.22 280712929.2200000300 280712929.2200000000
364322379.5731 364322379.5730999700 364322379.5731000000
10482308902 10482308902.0000000000 10482308902.0000000000
正確で見栄えを良くしたい場合は、FLOAT
の使用をやめてください。これはおおよそのデータ型であり、厳密な数学のバックグラウンド以外のほとんどの人にとっては論理に反します。必要以上のスケールでDECIMAL
を使用し、現在必要な小数点以下の桁数にフォーマットします(クエリで、ビューを作成するか、計算列を作成します)。現在必要以上の情報を保存している場合は、いつでも後で公開できます。また、ユーザーにテーブルへの直接アクセスを許可しないように選択することもできます。
これがネクロポスティングに該当するかどうかはわかりませんが、最近同様の問題が発生したので、投稿するかもしれないと思いました。
これは罪として醜いかもしれませんが、うまくいくように見えました(上記のアーロンの応答から変更されました)。
DECLARE @myTable TABLE(x FLOAT);
INSERT INTO @myTable VALUES
(280712929.22),
(364322379.5731),
(10482308902),
(-0.628475064730907);
SELECT x,
d = CONVERT(DECIMAL(28,10), x),
NewDec = CONVERT(DECIMAL(28,10),
CONVERT(DECIMAL(16,15),
LEFT(CONVERT(VARCHAR(50), x, 2),17))
* POWER(CONVERT(DECIMAL(38,19),10),
RIGHT(CONVERT(varchar(50), x,2),4)))
FROM @myTable;
結果:
x d NewDec
------------------ ---------------------- ----------------------
280712929.22 280712929.2200000300 280712929.2200000000
364322379.5731 364322379.5731000300 364322379.5731000000
10482308902 10482308902.0000000000 10482308902.0000000000
-0.628475064730907 -0.6284750647 -0.6284750647
ビッグデータテーブルをfloatからdecimal(28,15)に変換する必要があるときに、この問題が発生しました。 @Danの回答のコメントで指定されているように、彼の回答は一部の値で期待どおりに機能していませんでした。
これがアップデートに使用した私の最終バージョンです
DECLARE @myTable TABLE(x FLOAT);
INSERT INTO @myTable VALUES
(280712929.22),
(364322379.5731),
(10482308902),
(-0.628475064730907),
(-0.62847506473090752665448522),
(8.828),
(8.9),
(8.999),
(8),
(9),
(0.000222060864421707),
(5.43472210425371E-323),
(1.73328282953587E+81);
SELECT x,
d = CONVERT(DECIMAL(28,15), ROUND( CONVERT(DECIMAL(28,15),
CONVERT(DECIMAL(16,15),
LEFT(CONVERT(VARCHAR(50), x, 2),17))
* POWER(CONVERT(DECIMAL(38,19),10),
CASE
WHEN RIGHT(CONVERT(varchar(50), x,2),4) > 12 THEN 12
ELSE RIGHT(CONVERT(varchar(50), x,2),4)
END)), 14 )),
SimpleVarchar = TRY_CONVERT(VARCHAR(50), x),
AnsiVarchar = TRY_CONVERT(VARCHAR(50), x, 2)
FROM @myTable;
小数14を四捨五入したため、精度のごく一部が失われました。しかし、私の場合は許容範囲です。