案例陈述未正确匹配预期值

时间:2015-10-02 23:39:48

标签: sql-server tsql sql-server-2012

我正在尝试生成一些随机数据,并且我一直在使用newid()来播种函数,因为它为每一行调用一次并保证每次都返回不同的结果。但是,我经常得到的值在某种程度上不等于预期范围内的任何整数。

我尝试了一些变体,包括highly upvoted one,但它们都会导致同样的问题。我把它放到一个显示问题的脚本中:

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。然后我想也许有一个奇怪的空值爬行,但是在我的case语句中,null将返回为-1,并且没有。

我运行了这两个不同的SQL Server 2012 SP1实例,两者都给出了相同的结果。

1 个答案:

答案 0 :(得分:2)

在第四列中,isnull(floor(rand(checksum(newid())) * 4), -1)每行最多评估五次。一次针对案件的每个分支。在每次调用时,值可以不同。所以它可以返回2,不匹配1,3不匹配2,1不匹配3,3不匹配4落入其他并返回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