14

I have a column X which is full of floats with decimals places ranging from 0 (no decimals) to 6 (maximum). I can count on the fact that there are no floats with greater than 6 decimal places. Given that, how do I make a new column such that it tells me how many digits come after the decimal?

I have seen some threads suggesting that I use CAST to convert the float to a string, then parse the string to count the length of the string that comes after the decimal. Is this the best way to go?

4

9 回答 9

25

你可以使用这样的东西:

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

所以,我开始寻找另一种方法并在这个答案的基础上,我得到了这个:

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


为了解决这个小怪癖,这里有一个修改版本,可以处理浮点值没有小数部分的情况:

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

于 2013-02-05T19:26:12.637 回答
5

该线程也在使用 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

在甲骨文中:

SELECT FLOOR(LOG(10,REVERSE(CAST(ABS(.56544)+1 as varchar(50))))) + 1 from DUAL
于 2013-02-05T19:31:03.720 回答
3

浮点数只是代表一个实数。实数的小数位数没有意义。特别是实数 3 可以有六个小数位,3.000000,只是所有小数位都为零。

您可能有一个显示转换未在十进制中显示最右边的零值。

另请注意,最多有 6 个小数位的原因是第 7 个不精确,因此显示转换不会使用第 7 个小数位值。

另请注意,浮点数以二进制形式存储,它们实际上在二进制点的右侧有二进制位置。十进制显示是浮点存储中二进制有理数的近似值,而浮点数又是实数的近似值。

所以关键是,浮点值有多少个小数位真的没有意义。如果您转换为字符串(例如使用 CAST),您可以计算小数位。这真的是你想要做的最好的方法。

于 2013-02-05T19:24:35.673 回答
1

Oracle 的解决方案,但你明白了。trunc() 删除 Oracle 中的小数部分。

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

查询的思路:乘以 1 000 000 后是否还有小数。

于 2016-12-16T14:23:04.893 回答
1

我之前回答过这个问题,但我可以从评论中看出它有点不清楚。随着时间的推移,我找到了一种更好的方式来表达这一点。

将 pi 视为

(a) 3.141592653590

这将 pi 显示为 11 位小数。然而,这被四舍五入到小数点后 12 位,如 pi,到 14 位是

(b) 3.1415926535897932

计算机或数据库以二进制形式存储值。对于单精度浮点数,pi 将存储为

(c) 3.141592739105224609375

这实际上是四舍五入到单个精度可以存储的最接近的值,就像我们在 (a) 中四舍五入一样。单精度可以存储的下一个最小数字是

(d) 3.141592502593994140625

因此,当您尝试计算小数位数时,您正在尝试找出小数位数,在这之后所有剩余的小数都将为零。但是,由于数字可能需要四舍五入才能存储,它并不代表正确的值。

数字在进行数学运算时也会引入舍入误差,包括在输入数字时从十进制转换为二进制,在显示值时从二进制转换为十进制。

您无法可靠地找到数据库中数字的小数位数,因为它被近似为四舍五入以存储在有限的存储空间中。实际值之间的差异,甚至数据库中的精确二进制值将四舍五入以十进制表示。四舍五入时总会缺少更多的十进制数字,因此您不知道零之后何时不再有非零数字。

于 2016-11-16T20:24:02.943 回答
1

我发现的另一种方法是

选择 1.110000 , LEN(PARSENAME(Cast(1.110000 as float),1)) 作为 Count_AFTER_DECIMAL

于 2021-05-27T07:07:30.817 回答
1

我注意到 Kshitij Manvelikar 的答案有一个错误。如果没有小数位,则不返回 0,而是返回数字中的字符总数。

所以改进它:

Case When (SomeNumber = Cast(SomeNumber As Integer)) Then 0 Else LEN(PARSENAME(Cast(SomeNumber as float),1)) End
于 2021-07-07T05:08:35.627 回答
0

这是另一个 Oracle 示例。正如我总是在非 Oracle 用户开始对我大喊大叫和投票等之前警告他们...... SUBSTRING 和 INSTRING 是 ANSI SQL 标准函数,可以在任何 SQL 中使用。Dual 表可以用任何其他表替换或创建。这是我从以下位置复制双表代码的 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)。您还可以在点小数位之前获取字符串的长度 - 将代码更改为 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

你已经有了关于铸造等的答案和例子......

于 2013-02-05T20:00:08.900 回答
0

这个问题询问常规 SQL,但我需要SQLite的解决方案。SQLite 既没有 log10 函数,也没有内置的反向字符串函数,所以这里的大多数答案都不起作用。我的解决方案类似于Art 的 answer,事实上,类似于 phan 在问题正文中描述的内容。它的工作原理是将浮点值(在 SQLite 中,一个“REAL”值)转换为文本,然后计算小数点后的字符。

对于名为“Table”的表中名为“Column”的列,以下查询将生成每行小数位数的计数:

select
length(
    substr(
        cast(Column as text),
        instr(cast(Column as text), '.')+1
    )
) as "Column-precision" from "Table";

代码会将列转换为文本,然后获取文本中句点 ( .) 的索引,并获取从该点到文本末尾的子字符串。然后,它计算结果的长度。

limit 100如果您不希望它在整个桌子上运行,请记住!

显示两列的数据库视图; 第一个叫

这不是一个完美的解决方案;例如,它认为“10.0”有 1 个小数位,即使它只是一个 0。但是,这实际上是我需要的,所以这不是我关心的问题。

希望这对某人有用:)

于 2021-12-27T20:24:37.850 回答