对于DECIMAL类型,@ value和FLOOR(@value)的差值为0

时间:2012-01-24 19:34:16

标签: sql sql-server decimal floor

这里有很多答案说使用

SELECT @value - FLOOR(@value)

获取数字的小数部分。有关示例,请参阅herehere

当我这样做时,我得到了我认为是奇怪的行为。

DECLARE @test DECIMAL(38, 8)
SET @test = 123.05468800

SELECT @test - FLOOR(@test)

Result: 0

我能做到

SELECT 123.05468800 - FLOOR(123.05468800)

Result: 0.05468800

我可以将@test的类型更改为FLOAT并且它可以正常工作。 FLOOR(@test)也按预期返回123

我认为这与十进制类型的精度有关,但主题上的the only MSDN page I could find实际上很稀疏。

那是怎么回事?为什么我没有得到小数部分.05468800?我应该做什么或使用什么来获得这个?

1 个答案:

答案 0 :(得分:4)

DECLARE @test DECIMAL(38, 8), @test2 DECIMAL(28, 8)
SET @test = 123.05468800
SET @test2 = 123.05468800

SELECT 
    @test as test, 
    FLOOR(@test) AS floortest, 
    @test-FLOOR(@test) AS broken, 
    @test - CAST(FLOOR(@test) AS DECIMAL(38, 8)) AS fixed
INTO gbntest;

SELECT 
    @test2 as test, 
    FLOOR(@test2) AS floortest, 
    @test-FLOOR(@test2) AS working
INTO gbntest2;

SELECT 
    123.05468800 as test,
    FLOOR(123.05468800) as floortest,
    123.05468800 - FLOOR(123.05468800) as working
INTO gbntest3;

SELECT * FROM INFORMATION_SCHEMA.COLUMNS C WHERE C.TABLE_NAME LIKE 'gbntest%';
DROP TABLE gbntest;
DROP TABLE gbntest2;
DROP TABLE gbntest3;

注意gbntest的中间2是decimal (38,0)

但是,使用常量或decimal (28,8)它可以正常工作。 (29,8)(30,8)

也是如此

然后使用(31,8),你会得到(38,7)

MSDN "Precision, Scale, and Length"描述了原因

                precision                                 scale
 ...
 e1 - e2        max(s1, s2) + max(p1-s1, p2-s2) + 1       max(s1, s2)

对于(31,8),你得到的精度为(40,8)

max(8,0) + max(31-8, 31-0) + 1 -> 8 + 31 + 1 -> 40
max(8,0) -> 8

(40,8) 调低至(38,6)。所以我在某处搞了我的计算:-)但是我希望你能得到这个想法......