繁体   English   中英

为什么我的SQL代码无法正确计算小数点后的小数位数?

[英]How come my SQL code does not correctly count the number of decimal places after the decimal?

SET COUNTDECIMALPLACES =  
    CASE Charindex('.', NEWNUMBER)
        WHEN 0 THEN 0
        ELSE
          LEN(
            CAST(
                 CAST(
                    REVERSE( NEWNUMBER ) AS float
                     ) AS bigint
                ) 
           )
    END   

如果数字是222.9375,则将错误地说COUNTDECIMALPLACES =3。但是,如果数字是17.5548,则将正确地说COUNTDECIMALPLACES =4。有人知道为什么吗?

编辑1:要回答评论中的问题,我正在使用SQL Server 2008(MS)。 看起来Gordon Linoff遇到了与我相同的错误。 另外,NEWNUMBER的数据类型为float。 鉴于我有浮点数,所以我的最终目标是计算小数点右边的小数位数。

您的222.9375中有3个,这是因为REVERSE接受字符串表达式。 通过传递浮点数,SQL Server必须执行从浮点数到varchar的隐式转换。

根据在线书籍:

CAST和CONVERT(Transact-SQL)

浮动和真实风格
当expression为float或real时,style可以是下表中显示的值之一。 其他值被处理为0。


0(默认)

产量
最多6位数字。 适当时以科学计数法使用。

可以使用以下示例将上述定义可视化:

declare @a float = 222.9375, @b float = 12.34564, @c float = 1234564.123456
select convert(varchar, @a, 0) -- Returns 222.938 -- Notice only 6 digits are displayed
    , convert(varchar, @b, 0) -- Returns 12.3456 -- Notice only 6 digits are displayed
    , convert(varchar, @c, 0) -- Returns 1.23456e+006 -- Notice only 6 digits are displayed

如果您继续使用float作为数据类型,那么即使将float转换为varchar并执行字符串操作,也无法期望获得确切的编号。

您甚至不能简单地将float转换为decimal因为您不知道要为小数分配多少小数位(小数位)。

或者,如果您以小数开头作为数据类型,则您将自动知道一个数字有多少个小数位,因为您必须声明它。

例如

declare @number decimal(19, 4) = 222.9375
select @number -- 222.9375

让我们更进一步。 要在某种计算后得出小数位数(小数位数),可以使用下面的函数获得答案:

declare @newnumber decimal(19, 4) = 222.9375    

select @newnumber * @newnumber -- Returns 49701.1289063
    , sql_variant_property(@newnumber * @newnumber, 'scale') -- Returns 7

但是,您很可能无法控制所使用的数据类型,我想到的一种方法是通过结合使用decimalvarchar来实现所需的数据。

declare @newnumber float = 222.9375

-- The first 6 columns are just the working steps, solution is in the last column.
select 
    @newnumber as 'original'
    , cast(@newnumber as decimal(38, 18)) as 'decimal' -- Assuming all your numbers can fit in decimal(38, 18).
    , cast(cast(@newnumber as decimal(38, 18)) as varchar(max)) as 'varchar'
    , reverse(cast(cast(@newnumber as decimal(38, 18)) as varchar(max))) as 'reverse'
    , cast(reverse(cast(cast(@newnumber as decimal(38, 18)) as varchar(max))) as decimal(38, 0)) as 'decimal'
    , len(cast(reverse(cast(cast(@newnumber as decimal(38, 18)) as varchar(max))) as decimal(38, 0))) as 'len'

    , case charindex('.', @newnumber)
        when 0 then 0
        else len(cast(reverse(cast(cast(@newnumber as decimal(38, 18)) as varchar(max))) as decimal(38, 0)))
    end as 'All In One Step'

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM