我有一个X列,其中包含小数位数的浮点数,范围从0(无小数)到6(最大值)。我可以指望没有小于6位小数的浮点数。鉴于此,我如何创建一个新列,它告诉我小数点后有多少位?
我看到一些线程暗示我使用CAST将float转换为字符串,然后解析字符串以计算小数点后字符串的长度。这是最好的方式吗?
答案 0 :(得分:18)
您可以使用以下内容:
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小提琴: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小提琴:http://sqlfiddle.com/#!6/10d54/11
答案 1 :(得分:3)
浮点数只表示实数。实数的小数位数没有意义。特别是实数3可以有六个小数位,即3.000000,只是所有小数位都为零。
您的显示转换可能没有显示十进制中最右边的零值。
另请注意,最多有6个小数位的原因是第七个是不精确的,因此显示转换不会提交到第七个小数位值。
还要注意浮点数以二进制形式存储,它们实际上在二进制点右侧有二进制位置。十进制显示是浮点存储中二进制有理数的近似值,它又是实数的近似值。
所以重点是,确实没有浮点值有多少小数位。如果转换为字符串(例如使用CAST),则可以计算小数位数。这真的是你想要做的最好的方法。
答案 2 :(得分:3)
这个帖子也在使用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 :(得分:1)
之前我回答过这个问题,但我可以从评论中看出它有点不清楚。随着时间的推移,我找到了一种更好的表达方式。
将pi视为
(a) 3.141592653590
这表示pi为小数点后11位。然而,这被舍入到12位小数,因为pi,到14位是
(b) 3.1415926535897932
计算机或数据库以二进制形式存储值。对于单精度浮点数,pi将存储为
(c) 3.141592739105224609375
这实际上是向上舍入到单个精度可以存储的最接近的值,就像我们在(a)中舍入一样。单个精度可以存储的下一个最小数字是
(d) 3.141592502593994140625
因此,当您尝试计算小数位数时,您试图找到多少小数位,之后所有剩余的小数将为零。但是,由于可能需要对数字进行舍入以存储它,因此它不代表正确的值。
当数学运算完成时,数字也会引入舍入误差,包括在输入数字时从十进制转换为二进制,以及在显示数值时从二进制转换为十进制。
您无法可靠地找到数据库中的数字所具有的小数位数,因为它近似于将其四舍五入以存储在有限的存储量中。实际值之间的差异,甚至数据库中的确切二进制值之间的差异将被舍入,以十进制表示。舍入时可能总会有更多的十进制数字,因此您不知道零之后何时不会有更多的非零数字。
答案 4 :(得分:1)
Oracle的解决方案,但你明白了。 trunc()删除Oracle中的小数部分。
select *
from your_table
where (your_field*1000000 - trunc(your_field*1000000)) <> 0;
查询的想法:在乘以1 000 000后,是否会留下任何小数。
答案 5 :(得分:1)
我注意到 Kshitij Manvelikar 的回答有一个错误。如果没有小数位,则不返回0,而是返回数字中的总字符数。
所以改进它:
Case When (SomeNumber = Cast(SomeNumber As Integer)) Then 0 Else LEN(PARSENAME(Cast(SomeNumber as float),1)) End
答案 6 :(得分:0)
这是另一个Oracle示例。因为我总是警告非Oracle用户,然后他们开始尖叫我和downvoting等... 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
你已经有关于施放等的答案和例子......
答案 7 :(得分:0)
我发现的另一种方法是
SELECT 1.110000 , LEN(PARSENAME(Cast(1.110000 as float),1)) AS Count_AFTER_DECIMAL