我正在尝试生成一些随机数据,并且一直在使用newid()作为函数的种子,因为它对每一行都调用一次,并且保证每次都返回不同的结果。但是,我经常得到的值在某种程度上不等于预期范围内的任何整数。
我已经尝试了几种变体,其中包括一个被高度推崇的变体,但是它们都导致了相同的问题。我将其放入显示问题的脚本中:
declare @test table (id uniqueidentifier)
insert into @test
select newid() from sys.objects
select
floor(rand(checksum(id)) * 4),
case isnull(floor(rand(checksum(id)) * 4), -1)
when 0 then 0
when 1 then 1
when 2 then 2
when 3 then 3
when -1 then -1
else 999
end,
floor(rand(checksum(newid())) * 4),
case isnull(floor(rand(checksum(newid())) * 4), -1)
when 0 then 0
when 1 then 1
when 2 then 2
when 3 then 3
when -1 then -1
else 999
end
from @test
我希望所有四列的结果始终在0到3的范围内。从表中检索唯一标识符时,结果始终是正确的(前两列)。类似地,当它们即时输出时,它们也是正确的(第三列)。到case语句中的整数时,它通常会返回超出预期范围的值。
这是一个示例,这些是我刚才运行它时的前20行。如您所见,最后一列中不应该存在“ 999”个实例:
0 0 3 1
3 3 3 1
0 0 3 3
3 3 2 999
1 1 2 999
3 3 2 1
2 2 0 999
0 0 0 0
3 3 2 0
1 1 3 999
3 3 0 999
2 2 2 2
1 1 3 0
2 2 3 0
3 3 1 999
0 0 1 999
3 3 1 1
0 0 0 3
3 3 0 999
0 0 1 0
起初我以为强制类型可能与我预期的不同,并且rand()* int的结果是浮点数而不是int。因此,我将其全部包裹在地板上以强制其成为一个int。然后,我想也许会有一个奇怪的null值传入,但是对于我的case语句,一个null将返回为-1,而没有一个。
我已经运行了这两个不同的SQL Server 2012 SP1实例,它们都给出相同的结果。
在第四列中,每一行isnull(floor(rand(checksum(newid())) * 4), -1)
最多被评估五次。对于该案例的每个分支,一次。在每次通话中,值可以不同。因此它可以返回2,不匹配1,3不匹配2,1不匹配3,3不匹配4落到else并返回999。
如果您获得执行计划,并查看XML,则可以看到一行[添加了空白。]:
<ScalarOperator ScalarString="
CASE WHEN isnull(floor(rand(checksum(newid()))*(4.000000000000000e+000)),(-1.000000000000000e+000))=(0.000000000000000e+000) THEN (0)
ELSE CASE WHEN isnull(floor(rand(checksum(newid()))*(4.000000000000000e+000)),(-1.000000000000000e+000))=(1.000000000000000e+000) THEN (1)
ELSE CASE WHEN isnull(floor(rand(checksum(newid()))*(4.000000000000000e+000)),(-1.000000000000000e+000))=(2.000000000000000e+000) THEN (2)
ELSE CASE WHEN isnull(floor(rand(checksum(newid()))*(4.000000000000000e+000)),(-1.000000000000000e+000))=(3.000000000000000e+000) THEN (3)
ELSE CASE WHEN isnull(floor(rand(checksum(newid()))*(4.000000000000000e+000)),(-1.000000000000000e+000))=(-1.000000000000000e+000) THEN (-1)
ELSE (999)
END
END
END
END
END
">
将表达式放在CTE中似乎可以防止重新计算的发生:
; WITH T AS (SELECT isnull(floor(rand(checksum(newid())) * 4), -1) AS C FROM @Test)
SELECT CASE C
when 0 then 0
when 1 then 1
when 2 then 2
when 3 then 3
when -1 then -1
else 999 END
FROM T
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句