SELECT vs UPDATE,使用ABS功能时出现意外舍入

Dav*_*vid 6 sql sql-server floating-point numbers

附件是在SQL中运行的代码示例.这似乎是SQL Server的意外行为.应该发生的是从数字中删除负数,但是当在更新命令下使用相同的函数时,它会执行绝对值并对数字进行舍入.为什么是这样?

DECLARE @TEST TABLE (TEST varchar(2048));

INSERT INTO @TEST VALUES ('  -29972.95');

SELECT TEST FROM @TEST;

SELECT ABS(TEST) FROM @TEST;

UPDATE @TEST SET TEST = ABS(TEST);

SELECT TEST FROM @TEST;
Run Code Online (Sandbox Code Playgroud)

以下是该代码的结果.

  -29972.95
29972.95
29973
Run Code Online (Sandbox Code Playgroud)

Jas*_*n W 3

这似乎更像是函数的“功能” ,而不是与orCONVERT相关的任何内容(它不同的唯一原因是因为隐式地将back返回的值转换为)。SELECTUPDATEUPDATEFLOAT(8)ABS(...)VARCHAR

更新计划中的计算标量包含表达式

[Expr1003] = Scalar Operator(CONVERT_IMPLICIT(varchar(2048),
                                              abs(CONVERT_IMPLICIT(float(53),[TEST],0))
                                              ,0) /*<-- style used for convert from float*/
                            )
Run Code Online (Sandbox Code Playgroud)

值 - 输出

0(默认)- 最多 6 位数字。适当时使用科学记数法。

1 - 始终为 8 位数字。始终使用科学记数法。

2 - 始终为 16 位数字。始终使用科学记数法。

来自 MSDN:https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql? view=sql-server-2017

这可以在下面的示例中看到:

SELECT
    [# Digits],
    CONVERT(FLOAT(8), CONVERT(VARCHAR(20), N)) AS [FLOAT(VARCHAR(N))],
    CONVERT(FLOAT(8), CONVERT(VARCHAR(20), N, 0)) AS [FLOAT(VARCHAR(N, 0))],
    CONVERT(FLOAT(8), CONVERT(VARCHAR(20), N, 1)) AS [FLOAT(VARCHAR(N, 1))]
FROM (SELECT '6 digits', ABS('9972.95') UNION ALL SELECT '7 digits', ABS('29972.95')) T ([# Digits], N)
Run Code Online (Sandbox Code Playgroud)

这将返回以下结果:

# Digits FLOAT(VARCHAR(N)) FLOAT(VARCHAR(N, 0)) FLOAT(VARCHAR(N, 1))
-------- ----------------- -------------------- --------------------
6 digits 9972.95           9972.95              9972.95
7 digits 29973             29973                29972.95
Run Code Online (Sandbox Code Playgroud)

这证明UPDATE使用CONVERT(VARCHAR, ABS(...))默认样式“0”是有效的。这将 限制FLOATABS6 位数字。去掉 1 个字符,以免隐式转换溢出,在此场景中您保留实际值。

回到OP:

  • 在本例中,函数ABS返回 a FLOAT(8)
  • 然后UPDATE导致隐式转换,实际上是“CONVERT(VARCHAR(2048), ABS(...), 0)”,然后溢出了默认样式的最大位数。
  • 要解决此行为(如果这与实际问题相关),您需要指定 1 或 2(甚至 3 以获得 17 位数字)的样式以避免这种截断(但请务必处理自此以来使用的科学记数法)现在在这种情况下总是返回)