SQL 服务器模函数似乎 return 值超出预期范围
SQL Server Modulo function appears to return values outside of expected range
在 case 语句中 运行 取模函数时,很多时候会 return 计算超出预期范围的值。
SELECT CASE WHEN ABS(CheckSUM(NewId())) % 5 IN (0,1,2,3,4) then NULL
ELSE 'What Happened?' END
如果您 运行 这个脚本几次,您会发现有时结果似乎超出了 0,1,2,3,4 的范围。我的想法是,这在某种程度上 return 在 case 语句中使用非整数值导致模数成为按大小写排序的无效方法。
有人可以解释一下这些情况下发生了什么,以便我将来可以解决这个问题吗?
注意:如果我 运行 代码模函数本身(在 case 语句之外)和 return 结果所有值都在 0,1,2,3,4 范围内不出所料。
我知道这不是答案,但我把它放在这里是为了正确格式化代码。
当我运行 OP的代码时,我第三次得到了"What Happened?"。我想看看发生这种情况时返回了什么 Modulo,看看它可能提供什么洞察力,但要做到这一点,我需要一个不动的 NewID(),所以我 t运行 提出了他的查询:
DECLARE @NewID UNIQUEIDENTIFIER = NEWID();
SELECT CASE WHEN ABS(CheckSUM(@NewID)) % 5 IN (0,1,2,3,4) then NULL
ELSE 'What Happened?' END
而且我没有看到任何 "What Happened?"。
我最好的猜测是 SQL 引擎试图以某种方式使操作顺序变得可爱,有时最终会在非数字分子上进行模运算。
但是如果不能在 t运行 提出的查询上重现行为,就不可能 "catch it in the act"。
为了使这个成为一个实际的答案,我想将来要解决这个问题,如果可能的话,你应该用 NEWID() 填充一个变量而不是将它内嵌在你的查询中。
其他形式的 "un-nesting" 这些操作也可能有效。
这是我在执行 Mikael 的查询时看到的执行计划:
将您的声明更改为
SELECT top(1)
CASE WHEN ABS(CheckSUM(NewId())) % 5 IN (0,1,2,3,4) then NULL
ELSE 'What Happened?' END
并查看实际的执行计划。
案例中的IN
部分展开为。
CASE WHEN abs(checksum(newid()))%(5)=(4) OR
abs(checksum(newid()))%(5)=(3) OR
abs(checksum(newid()))%(5)=(2) OR
abs(checksum(newid()))%(5)=(1) OR
abs(checksum(newid()))%(5)=(0)
THEN NULL
ELSE 'What Happened?'
END
abs(checksum(newid()))%(5)
对 in 子句中的每个值执行一次。
在 case 语句中 运行 取模函数时,很多时候会 return 计算超出预期范围的值。
SELECT CASE WHEN ABS(CheckSUM(NewId())) % 5 IN (0,1,2,3,4) then NULL
ELSE 'What Happened?' END
如果您 运行 这个脚本几次,您会发现有时结果似乎超出了 0,1,2,3,4 的范围。我的想法是,这在某种程度上 return 在 case 语句中使用非整数值导致模数成为按大小写排序的无效方法。
有人可以解释一下这些情况下发生了什么,以便我将来可以解决这个问题吗?
注意:如果我 运行 代码模函数本身(在 case 语句之外)和 return 结果所有值都在 0,1,2,3,4 范围内不出所料。
我知道这不是答案,但我把它放在这里是为了正确格式化代码。
当我运行 OP的代码时,我第三次得到了"What Happened?"。我想看看发生这种情况时返回了什么 Modulo,看看它可能提供什么洞察力,但要做到这一点,我需要一个不动的 NewID(),所以我 t运行 提出了他的查询:
DECLARE @NewID UNIQUEIDENTIFIER = NEWID();
SELECT CASE WHEN ABS(CheckSUM(@NewID)) % 5 IN (0,1,2,3,4) then NULL
ELSE 'What Happened?' END
而且我没有看到任何 "What Happened?"。
我最好的猜测是 SQL 引擎试图以某种方式使操作顺序变得可爱,有时最终会在非数字分子上进行模运算。
但是如果不能在 t运行 提出的查询上重现行为,就不可能 "catch it in the act"。
为了使这个成为一个实际的答案,我想将来要解决这个问题,如果可能的话,你应该用 NEWID() 填充一个变量而不是将它内嵌在你的查询中。
其他形式的 "un-nesting" 这些操作也可能有效。
这是我在执行 Mikael 的查询时看到的执行计划:
将您的声明更改为
SELECT top(1)
CASE WHEN ABS(CheckSUM(NewId())) % 5 IN (0,1,2,3,4) then NULL
ELSE 'What Happened?' END
并查看实际的执行计划。
案例中的IN
部分展开为。
CASE WHEN abs(checksum(newid()))%(5)=(4) OR
abs(checksum(newid()))%(5)=(3) OR
abs(checksum(newid()))%(5)=(2) OR
abs(checksum(newid()))%(5)=(1) OR
abs(checksum(newid()))%(5)=(0)
THEN NULL
ELSE 'What Happened?'
END
abs(checksum(newid()))%(5)
对 in 子句中的每个值执行一次。