SQL 服务器舍入问题
SQL Server Rounding issue
我在 variables/columns 中存储数据时出现数据准确性问题。
考虑以下示例
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
(不正确)
谁能告诉我在变量中存储值时出现近似值的原因是什么以及如何修复它?
首先检查数据类型:
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
为什么会这样:
好吧,我知道 lad2025 已经回答了..但是..只有一半(至少对我来说)..它只回答了如何解决它而不是原因..
出于好奇,我对此进行了自己的研究..阅读 Precision, Scale, and Length 并尝试了一些 SQL 我发现 NUMERIC(p,s) 相乘会产生新的数字具有新的精度和比例:
p1 + p2 + 1
s1 + s2
approximation问题是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给出错误的结果它们的精度原本超过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) |
+-----------+------------------+
table 显示@a * @b.. 上的比例缩减。
问题是我不知道这是故意的还是错误..
我在 variables/columns 中存储数据时出现数据准确性问题。
考虑以下示例
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
(不正确)
谁能告诉我在变量中存储值时出现近似值的原因是什么以及如何修复它?
首先检查数据类型:
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
为什么会这样:
好吧,我知道 lad2025 已经回答了..但是..只有一半(至少对我来说)..它只回答了如何解决它而不是原因..
出于好奇,我对此进行了自己的研究..阅读 Precision, Scale, and Length 并尝试了一些 SQL 我发现 NUMERIC(p,s) 相乘会产生新的数字具有新的精度和比例:
p1 + p2 + 1
s1 + s2
approximation问题是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给出错误的结果它们的精度原本超过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) |
+-----------+------------------+
table 显示@a * @b.. 上的比例缩减。 问题是我不知道这是故意的还是错误..