SQL Server 批处理和选择语句输出差异(以小数点为单位)



如果我在 SSMS 中执行,则遵循批处理语句,给我如下所示的结果

DECLARE @M_TUBE_VOLUME NUMERIC(38,10),
@M_TUBE_OD NUMERIC(38,10)=12.50000,
@M_TUBE_ID NUMERIC(38,10)=12.50000,
@M_TUBE_LEN NUMERIC(38,10)=4000.00000,
@M_TUBE_COUNT NUMERIC(38,10)=212.4215000,
@M_S_TUBE_LEN NUMERIC(38,10)=0.0000,
@M_S_TUBE_COUNT NUMERIC(38,10)=3587.000
SET @M_TUBE_VOLUME=(SELECT 3.141592 / 4 * @M_TUBE_OD * @M_TUBE_ID * ((@M_TUBE_LEN * @M_TUBE_COUNT) + (@M_S_TUBE_LEN * @M_S_TUBE_COUNT)));
SELECT @M_TUBE_VOLUME
RESULT -- 104272138.7104680000

如果我使用 select 语句在 SSMS 中执行同样的事情

SELECT 3.141592 / 4 * 12.50000 * 12.50000 * ((4000.00000 * 212.4215000) + (0.0000 * 3587.000))
RESULT -- 104272138.285625000000000000000

为什么两个结果不同,请帮助我

它与舍入有关。由于您的计算涉及带有小数位的数字。

请参阅文档精度、小数位数和长度 (Transact-SQL(

我在这里提取了相关部分

Operation  Result precision                        Result scale *
e1 * e2    p1 + p2 + 1                             s1 + s2
e1 / e2    p1 - s1 + s2 + max(6, s1 + p2 + 1)      max(6, s1 + p2 + 1)
  • 结果精度和小数位数的绝对最大值为 38。当结果精度大于 38 时,它将降低到 38,并且 相应的比例减小,以防止截断 结果的组成部分。在某些情况下,例如乘法或 除法,比例因子不会降低,以保持小数 精度,尽管可以提高溢出误差。

在第二个查询中,像3.141592这样的数字是numeric(7,6)12.50000numeric(7,5),在第一个查询中,所有这些都是numeric(38,10)

舍入发生在前 4 个表达式上。

我使用SELECT INTO临时表,然后查询临时表中列的数据类型

SELECT  f1 = 3.141592 / 4 * @M_TUBE_OD * @M_TUBE_OD, 
f2 = 3.141592 / 4 * 12.50000 * 12.50000
INTO    #t
select  c.name, t.name, c.precision, c.scale
from    tempdb.sys.columns c
inner join master.sys.systypes t    on  c.system_type_id    = t.xtype
where   object_id   = object_id('tempdb..#t')
name  name      percision   scale
f1    numeric   38           6
f2    numeric   25          18

您可以看到,对于您的第一个查询,结果scale减少到仅6。因此,对于第一个查询,前 4 个表达式的结果是122.718438(舍入为38(而不是122.7184375

你过度定义了你的numericprecision。减少它并尝试

在第二个版本中,您尚未显式定义数据类型,并且默认为 FLOAT。

可以通过将查询更改为

DECLARE @M_TUBE_VOLUME FLOAT,
@M_TUBE_OD FLOAT=12.50000,
@M_TUBE_ID FLOAT=12.50000,
@M_TUBE_LEN FLOAT=4000.00000,
@M_TUBE_COUNT FLOAT=212.4215000,
@M_S_TUBE_LEN FLOAT=0.0000,
@M_S_TUBE_COUNT FLOAT=3587.000
SET @M_TUBE_VOLUME=(SELECT 3.141592 / 4 * @M_TUBE_OD * @M_TUBE_ID * ((@M_TUBE_LEN * @M_TUBE_COUNT) + (@M_S_TUBE_LEN * @M_S_TUBE_COUNT)));
SELECT @M_TUBE_VOLUME

最新更新