web-dev-qa-db-ja.com

SQLで小数点以下の桁数を数えるにはどうすればよいですか?

私は0(小数なし)から6(最大)の範囲の小数位の浮動小数点数でいっぱいの列Xを持っています。小数点以下6桁を超える浮動小数点はないという事実を当てにすることができます。それを踏まえて、小数点以下の桁数がわかるように新しい列を作成するにはどうすればよいですか?

CASTを使用して浮動小数点数を文字列に変換し、文字列を解析して10進数の後に続く文字列の長さをカウントすることを提案するいくつかのスレッドを見てきました。これは最善の方法ですか?

13
phan

次のようなものを使用できます。

declare @v sql_variant

set @v=0.1242311

select SQL_VARIANT_PROPERTY(@v, 'Scale') as Scale

これは7を返します。


上記のクエリをfloat列で機能させようとしましたが、期待どおりに機能しませんでした。ここで確認できるように、これはsql_variant列でのみ機能します。 http://sqlfiddle.com/#!6/5c62c/2

それで、私は別の方法を見つけてこれに基づいて構築しました answer 、私はこれを得ました:

SELECT value,
LEN(
    CAST(
         CAST(
              REVERSE(
                      CONVERT(VARCHAR(50), value, 128)
                     ) AS float
             ) AS bigint
        )
   ) as Decimals
FROM Numbers

これがSQL Fiddleです: http://sqlfiddle.com/#!6/23d4f/29


その小さな癖を説明するために、float値に小数部がない場合を処理する修正バージョンを次に示します。

SELECT value,
       Decimals = CASE Charindex('.', value)
                    WHEN 0 THEN 0
                    ELSE
           Len (
            Cast(
             Cast(
              Reverse(CONVERT(VARCHAR(50), value, 128)) AS FLOAT
                 ) AS BIGINT
                )
               )
                    END
FROM   numbers

これは、付随するSQL Fiddleです。 http://sqlfiddle.com/#!6/10d54/11

22

Floatは実数を表すだけです。実数の小数点以下の桁数に意味はありません。特に、実数3は小数点以下6桁、つまり3.000000になる可能性があります。小数点以下がすべてゼロであるだけです。

10進数で最も右側のゼロ値を表示していない表示変換がある場合があります。

小数点以下6桁まである理由は、7桁目が不正確であるため、表示変換では小数点以下7桁の値が確定されないことにも注意してください。

また、floatはバイナリで格納され、実際にはバイナリポイントの右側にバイナリの場所があることに注意してください。 10進表示は、実数の近似値であるfloatストレージ内の2進有理数の近似値です。

つまり、ポイントは、float値の小数点以下の桁数が実際に意味をなさないということです。文字列に変換する場合(たとえばCASTを使用する場合)、小数点以下の桁数を数えることができます。それは本当にあなたがやろうとしていることに対して最善のアプローチでしょう。

3
Marlin Pierce

このスレッドもCASTを使用していますが、興味深い答えが見つかりました。

http://www.sqlservercentral.com/Forums/Topic314390-8-1.aspx

DECLARE @Places INT
 SELECT TOP 1000000 @Places = FLOOR(LOG10(REVERSE(ABS(SomeNumber)+1)))+1
   FROM dbo.BigTest

そしてOracleでは:

SELECT FLOOR(LOG(10,REVERSE(CAST(ABS(.56544)+1 as varchar(50))))) + 1 from DUAL
3
vbaranov

私は以前にこれに答えましたが、コメントからは少し不明確であることがわかります。時間をかけて私はこれを表現するより良い方法を見つけました。

Piを

(a) 3.141592653590

これは、piを小数点以下11桁で示しています。ただし、これは小数点以下12桁に丸められ、piとして14桁になります。

(b) 3.1415926535897932

コンピューターまたはデータベースは、値をバイナリーで保管します。単精度浮動小数点の場合、piは次のように格納されます。

(c) 3.141592739105224609375

これは、(a)で丸めたのと同じように、単精度で格納できる最も近い値に実際に丸められます。単精度が格納できる次に低い数は

(d) 3.141592502593994140625

したがって、小数点以下の桁数を数えようとする場合、小数点以下の桁数を調べようとすると、残りの小数点以下がすべてゼロになります。ただし、数値を格納するために四捨五入する必要がある場合があるため、正しい値を表していません。

また、数値を入力すると10進数から2進数に変換したり、値を表示するときに2進数から10進数に変換したりするなど、数学的演算が行われるときに数値によって丸め誤差が発生します。

データベース内の数値の小数点以下の桁数を正確に見つけることはできません。これは、限られた量のストレージに格納するために四捨五入するために概算されるためです。実際の値、またはデータベース内の正確なバイナリ値の違いも、10進数で表すために丸められます。丸めから欠落している10進数字が常に存在する可能性があるため、ゼロの後に続く非ゼロ数字がなくなる時期はわかりません。

1
Marlin Pierce

Oracleのソリューションですが、アイデアは思い付きました。 trunc()は、Oracleの小数部分を削除します。

select *
from your_table
where (your_field*1000000 - trunc(your_field*1000000)) <> 0;

クエリのアイデア:1 000 000を掛けた後、小数点以下が残りますか?.

1
DenisS

次に、別のOracleの例を示します。オラクル以外のユーザーが私に向かって怒鳴ったり、反対票を投じたりする前に常に警告するので、SUBSTRINGとINSTRINGはANSI SQL標準関数であり、どのSQLでも使用できます。デュアルテーブルは、他のテーブルと置き換えるか、作成することができます。デュアルテーブルコードをコピーしたSQL Serverブログへのリンクは次のとおりです。 http://blog.sqlauthority.com/2010/07/20/sql-server-select-from-dual-dual-equivalent/

CREATE TABLE DUAL
(
 DUMMY VARCHAR(1)
)
GO
INSERT INTO DUAL (DUMMY)
VALUES ('X')
GO

このクエリでは、ドットまたは小数点以下の長さが返されます。 strは、必要に応じて、_number(str)に変換できます。ドット10進数の前の文字列の長さを取得することもできます。コードをLENGTH(SUBSTR(str、1、dot_pos))-1に変更し、INSTR部分の+1を削除します。

SELECT str, LENGTH(SUBSTR(str, dot_pos)) str_length_after_dot FROM
(
 SELECT '000.000789' as str
      , INSTR('000.000789', '.')+1 dot_pos 
   FROM dual
)
/

SQL>

STR           STR_LENGTH_AFTER_DOT
----------------------------------
000.000789    6

あなたはすでにキャストなどに関する答えと例を持っています...

0
Art