繁体   English   中英

如何计算 SQL 中的小数位?

[英]How do I count decimal places in SQL?

我有一个 X 列,它充满了浮点数,小数位数从 0(无小数)到 6(最大值)。 我可以指望没有超过 6 位小数的浮点数。 鉴于此,我如何创建一个新列,以便告诉我小数点后有多少位数字?

我看到一些线程建议我使用 CAST 将浮点数转换为字符串,然后解析字符串以计算小数点后的字符串长度。 这是最好的方法吗?

你可以使用这样的东西:

declare @v sql_variant

set @v=0.1242311

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

这将返回7


我试图使上述查询与float列一起工作,但无法按预期工作。 它仅适用于sql_variant列,如您在此处所见: http : sql_variant /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

该线程也在使用 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 可以有 6 个小数位,3.000000,只是所有的小数位都为零。

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

另请注意,最多 6 位小数的原因是第七位不精确,因此显示转换不会提交到第七位小数位值。

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

所以重点是,对于浮点值有多少个小数位真的没有意义。 如果您转换为字符串(例如使用 CAST),您可以计算小数位。 对于您正在尝试做的事情,这确实是最好的方法。

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

将 pi 视为

(a) 3.141592653590

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

(b) 3.1415926535897932

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

(c) 3.141592739105224609375

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

(d) 3.141592502593994140625

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

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

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

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

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

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

我发现的另一种方法是

SELECT 1.110000 , LEN(PARSENAME(Cast(1.110000 as float),1)) AS Count_AFTER_DECIMAL

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

所以改进它:

Case When (SomeNumber = Cast(SomeNumber As Integer)) Then 0 Else LEN(PARSENAME(Cast(SomeNumber as float),1)) End

这是另一个 Oracle 示例。 正如我总是在非 Oracle 用户开始对我尖叫和投反对票等之前警告他们...... SUBSTRING 和 INSTRING 是 ANSI SQL 标准函数,可以在任何 SQL 中使用。 Dual table 可以替换为任何其他 table 或创建。 这是我从以下位置复制双表代码的 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

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

这个问题询问常规 SQL,但我需要SQLite的解决方案。 SQLite 既没有 log10 函数,也没有内置的反向字符串函数,所以这里的大多数答案都不起作用。 我的解决方案类似于Art 的答案,事实上,类似于 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

数据库视图显示两列;第一个称为“Temp”,具有温度值。第二个称为“Temp-precision”,具有“Temp”行的每个小数位的计数

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

希望这对某人有用:)

暂无
暂无

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

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