意外的rand()行为?

Mat*_*son 3 sql t-sql sql-server

下面的TSQL应该随机生成20行,其中包含递增ID和星期几. 在这里看到这个.

注意:我知道这段代码已经存在缺陷我只是在想一个想法.

declare @loop int = 1;
if OBJECT_ID('tempdb..#temp') is not null drop table #temp;
create table #temp(id int, dayofweek varchar(10))

while @loop < 21
begin
    insert into #temp
    values(@loop, case ceiling(rand()*7)
                    when 1 then 'Monday'
                    when 2 then 'Tuesday'
                    when 3 then 'Wednesday'
                    when 4 then 'Thursday'
                    when 5 then 'Friday'
                    when 6 then 'Saturday'
                    when 7 then 'Sunday'
                end)
    set @loop += 1
end
Run Code Online (Sandbox Code Playgroud)

如果我这样做select * from #temp,我在'dayofweek'列的查询结果中得到一些NULL值.任何人都可以解释为什么会这样吗?我已经查看了返回结果,ceiling(rand()*7)据我所知,它只返回1到7之间的结果.

我错过了什么?

Gor*_*off 7

这非常微妙.问题是每次比较都会对case表达式进行一次评估.因此,有时所有的比较都会失败,因为它们使用不同的数字.

文件中埋藏的是这个说明:

  • 计算input_expression,然后按指定的顺序计算每个WHEN子句的input_expression = when_expression.

这是更加令人惊讶,因为rand()通常不会评估多次(一个在select,setwhere条款至少).在这种情况下,似乎是.幸运的是,有一个简单的解决方案:

declare @loop int = 1;
declare @dow int;
if OBJECT_ID('tempdb..#temp') is not null drop table #temp;
create table #temp(id int, dayofweek varchar(10))

while @loop < 21
begin
    set @dow = ceiling(rand()*7);

    insert into #temp
    values(@loop, case dow
                    when 1 then 'Monday'
                    when 2 then 'Tuesday'
                    when 3 then 'Wednesday'
                    when 4 then 'Thursday'
                    when 5 then 'Friday'
                    when 6 then 'Saturday'
                    when 7 then 'Sunday'
                end)
    set @loop += 1;
end;
Run Code Online (Sandbox Code Playgroud)