2016-01-19 4 views
-6

У меня проблема с точностью данных при хранении данных в переменных/столбцах.Проблема округления SQL Server

Рассмотрим следующий пример

DECLARE @w NUMERIC(38, 15) = 0.458441, 
     @a NUMERIC(38, 15) = 10.000000, 
     @p NUMERIC(38, 15) = 5.000000 

select (1+0.458441)*(1+ 10.000000/100)*(1+ 5.000000/100) 

Результат:1.68449935500000000000000000 (правильный)

SELECT (1 + @w) * (1 + @a/100.0) * (1 + @p/100.0) 

Результат:1.684499 (неверная)

Может кто-нибудь сказать, что является причиной аппроксимация при хранении va lues в переменной и как ее можно исправить?

+1

«как это можно исправить?» - прекратите запрашивать большие типы данных с большими требованиями к точности, если они вам не нужны/не нужны. –

+0

@Damien_The_Unbeliever - Это просто мои данные в реальном времени очень большие. –

ответ

5

сначала проверить типы данных:

SELECT '0.458441', system_type_name 
FROM sys.dm_exec_describe_first_result_set(N'SELECT 0.458441', NULL, 0) 
UNION ALL 
SELECT '10.000000', system_type_name 
FROM sys.dm_exec_describe_first_result_set(N'SELECT 10.000000', NULL, 0) 
UNION ALL 
SELECT '5.000000', system_type_name 
FROM sys.dm_exec_describe_first_result_set(N'SELECT 5.000000', NULL, 0); 

╔═══════════╦══════════════════╗ 
║ value ║ system_type_name ║ 
╠═══════════╬══════════════════╣ 
║ 0.458441 ║ numeric(6,6)  ║ 
║ 10.000000 ║ numeric(8,6)  ║ 
║ 5.000000 ║ numeric(7,6)  ║ 
╚═══════════╩══════════════════╝ 

Запрос 1:

SELECT (1+0.458441)*(1+10.000000/100)*(1+5.000000/100) 
-- 1.684499355 

Запрос 2:

SELECT (1 + @w) * (1 + @a/100.0) * (1 + @p/100.0) 
-- 1.684499 

После добавления литья:

SELECT (1 + CAST(@w AS NUMERIC(8,6))) * 
     (1 + CAST(@a AS NUMERIC(8,6))/100.0) * 
     (1 + CAST(@p AS NUMERIC(8,6))/100.0) 
-- 1.684499355 

LiveDemo

Почему это так: related article

+1

славный, я не знаю о sys.dm_exec_describe dmv.Thanks – TheGameiswar

+0

Спасибо, что помогли мне сейчас немного ясно с моей проблемой. В реальном времени любые значения могут прийти, это просто примеры. В этом случае, как я могу заставить его работать, есть что-то не так: 'numeric (38,15)' –

+1

Дело в том, что ** это не «неправильно» **, как вы его описываете. Таким образом, вычисление масштаба/точности работает в зависимости от типа данных частей выражения. См. Упомянутую ссылку. – lad2025

2

ОК, я знаю, что уже ответил на lad2025..but..only половине этого (для меня по крайней мере) .. только его ответьте, как исправить это не причина ..

Из-за моего любопытства, я делаю свое собственное исследование по этому вопросу. После чтения прогиб Precision, Scale, and Length и попробуйте SQL, я обнаружил, что NUMERIC (p, s) при умножении произведет новый числовые с новой точностью и шкалой:

p1 + p2 + 1 
s1 + s2 

приближение проблемой является произойти, когда P1 + P2 + 1 более 38, максимальный сервер точности SQL может иметь, точность установлена ​​на 38, но масштаб уменьшается на 1, как показано ниже

DECLARE 
    @a NUMERIC(20, 5) = 0.12345, 
    @b NUMERIC(20, 2) = 0.13, 
    @c NUMERIC(10, 5) = 0.12345, 
    @d NUMERIC(10, 2) = 0.13 

SELECT 0.12345 * 0.13 Result, @a * @b AxB, @c * @d CxD 

Результат:

+-----------+----------+-----------+ 
| Result | AxB | CxD | 
+-----------+----------+-----------+ 
| 0.0160485 | 0.016049 | 0.0160485 | 
+-----------+----------+-----------+ 

AxB дают неправильно привести их точность оригинал LY превышая 38 и Cxd дать правильный ответ с точностью 21 Далее проверьте с sys.dm_exec_describe_first_result_set

SELECT '@a * @b', system_type_name 
FROM sys.dm_exec_describe_first_result_set(
    N'DECLARE @c NUMERIC(20, 5) = 0.12345, @d NUMERIC(20, 2) = 0.13 
    SELECT @c * @d', NULL, 0) 
UNION ALL 
SELECT '@c * @d', system_type_name 
FROM sys.dm_exec_describe_first_result_set(
    N'DECLARE @c NUMERIC(10, 5) = 0.12345, @d NUMERIC(10, 2) = 0.13 
    SELECT @c * @d', NULL, 0) 

Результат:

+-----------+------------------+ 
| operation | system_type_name | 
+-----------+------------------+ 
| @a * @b | numeric(38,6) | 
| @c * @d | numeric(21,7) | 
+-----------+------------------+ 

В таблице показано уменьшение масштаба на @a * @b. Дело в том, что я не знаю, было ли это преднамеренным или ошибка.

Смежные вопросы