意外的rand()行为?

时间:2015-10-21 22:02:45

标签: sql sql-server tsql

下面的TSQL应该随机生成20行,其中包含递增ID和星期几。 See this in action here

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

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

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

我错过了什么?

1 个答案:

答案 0 :(得分:7)

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

隐藏在documentation中的是这个说明:

  
      
  • 评估input_expression,然后按照指定的顺序,为每个WHEN子句计算input_expression = when_expression。
  •   

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

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;