TSQL难题,为什么我的更新不是随机的?

时间:2009-01-16 04:26:42

标签: sql-server tsql

我正在查看postgres问题并且它要求使用随机值更新表。

我只是注意到它在回答之后就是以postgres为目标,但在回答它时我发现了一个谜。

以下是我的问题示例代码:

create table #Buildings([Use] varchar(50), n int)

insert #Buildings
select null,null from sysobjects 

update #Buildings
set [Use] = 
        case (ABS(CAST(CAST(NEWID() AS VARBINARY) AS int)) % 6)
            when 0 then null
            when 1 then 'warehouse'
            when 2 then 'office'
            when 3 then 'market'
            when 4 then 'retail'
            when 5 then 'workshop'
            else 'HOW IS THIS POSSIBLE'
        end,
    n = ABS(CAST(CAST(NEWID() AS VARBINARY) AS int)) % 6

select [Use], count(*) from
#Buildings
group by [Use] 

select n, count(*) from
#Buildings
group by n 

它返回一个非常奇怪的结果集:

Use                                                
-------------------------------------------------- -----------
workshop                                           128
HOW IS THIS POSSIBLE                               633
NULL                                               287
retail                                             140
warehouse                                          258
market                                             177
office                                             209

第二个完全合理的结果集:

n           
----------- -----------
0           292
3           300
1           313
4           277
5           311
2           339

两个结果集的数据都在同一个更新语句中生成。

所以我的问题是为什么一个超出0-5范围的数字命中我的案例陈述?这个数字是多少?为什么我直接更新int是正确分配的东西?

3 个答案:

答案 0 :(得分:5)

我有个主意:

也许在每个when语句上计算值,如果它到达第一个,计算一个非0的值,它到第二个,然后计算一个非1的值,然后是下一个,依此类推,如果它使它达到5,然后计算5以外的数字,那么它就转到了其他地方。

这也可以解释为什么还有比其他更多的“如何可能”,当当前位置和该位置产生的随机数匹配时,其他的会增加。

你的想法?

编辑:我也在sql server express 2008中进行了测试,结果相同。

答案 1 :(得分:1)

create table #Buildings([Use] varchar(50), n int)    
insert #Buildings
select null,null from sysobjects 




declare @i int

update #Buildings
set 
    @i = (ABS(CAST(CAST(NEWID() AS VARBINARY) AS int)) % 6),
    [Use] = 
        case @i -- if the expression is evaluated on-the-fly for each WHEN, MSSQL variable-in-SQL capability will alleviate this problem
                when 0 then null
                when 1 then 'warehouse'
                when 2 then 'office'
                when 3 then 'market'
                when 4 then 'retail'
                when 5 then 'workshop'
                else 'HOW IS THIS POSSIBLE'
        end,
    n = @i

select [Use], count(*) from
#Buildings
group by [Use] 

select n, count(*) from
#Buildings
group by n

答案 2 :(得分:0)

约翰可能是对的...虽然担心“什么时候”会如此低效。

另请注意,NewId()函数每次调用时都会返回一个新值。你打电话给它两次(不计算“什么时候”的怪癖)。以下更稳定: 删除表#Buildings 去

create table #Buildings([Use] varchar(50),n int)

插入#Buildings 从sysobjects中选择null,null

将@nid声明为uniqueidentifier

更新#Buildings 设置@nid = newid(),     [使用] =         case(ABS(CAST(CAST(NewId()AS VARBINARY)AS int))%6)                 当0然后为null                 当1然后'仓库'                 当2然后'办公室'                 当3然后'市场'                 当4然后'零售'                 当5然后'工作坊'                 别的'这怎么可能'         结束,     n = ABS(CAST(CAST(NewId()AS VARBINARY)AS int))%6

中选择[使用],计数(*)

建筑物

按[使用]分组

中选择n,count(*)

建筑物

分组n