Разница между @value и FLOOR(@value) равна 0 для типа DECIMAL.

Многие ответы здесь говорят об использовании

SELECT @value - FLOOR(@value)

чтобы получить десятичную часть числа. См. здесь или здесь для примера.

Я получаю то, что считаю странным поведением, когда делаю это.

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, как и ожидалось.

Я предполагаю, что это что-то с точностью десятичного типа, но единственная страница MSDN Я мог найти по этому вопросу очень мало.

Итак, что происходит? Почему я не получаю десятичную часть .05468800? И что я должен делать или использовать, чтобы получить это?


person Kris Harper    schedule 24.01.2012    source источник


Ответы (1)


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;

Обратите внимание, что средние 2 для gbntest - это decimal (38,0)

Однако с константами или decimal (28,8) это работает. Как и (29,8) и (30,8)

Но потом с (31,8) вы получите (38,7) обратно.

В документе MSDN "Точность, масштаб и длина" описано, почему

                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). Итак, я где-то обнулил свои расчеты :-), но надеюсь, вы поняли...

person gbn    schedule 24.01.2012
comment
Очень хорошо! Очевидно, я недостаточно глубоко вникал в точность поведения! - person mwigdahl; 24.01.2012
comment
Я понимаю. Ключом является сноска внизу страницы, на которую вы ссылаетесь. ... точность [имеет] абсолютный максимум 38. Когда точность результата больше 38, ... масштаб уменьшается. Итак, теперь мой вопрос: почему FLOOR не возвращает DECIMAL (38,8) в этом контексте? На странице MSDN указано, что тип результата должен быть таким же, как и ввод . - person Kris Harper; 25.01.2012