案例陈述与期望值不正确匹配

里克

我正在尝试生成一些随机数据,并且一直在使用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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章