我正在编写一个过程,其中每次调用都需要获得一个随机数。此过程从我们的.net web服务调用。
我尝试使用rand()实现此功能。然而,当我在毫秒内多次调用存储过程时,我得到了许多冲突,因为生成的是相同的随机数。如果在随后的调用之间有大约20或30毫秒的间隔,则看起来工作正常。
看起来,SqlServer在每次调用存储过程时都会对rand()进行补种。据我所知,这是一个问题,因为人们应该对随机数生成器进行一次播种,如果每次对rand调用都重新播种,就不会得到良好的伪随机数序列。此外,在1或2毫秒内对同一sp的呼叫似乎会被植入相同的值。
下面是存储过程中的语句本身。
DECLARE @randomNumber char(9)
SET @randomNumber = RIGHT('00000' + CAST(CAST(rand()*100000 AS INT) AS VARCHAR(5)),5)
+ RIGHT('00000' + CAST(CAST(rand()*10000 AS INT) AS VARCHAR(4)),4)
有没有人有解决这个问题的建议?
我是否必须编写自己的随机数生成器,该生成器只需播种一次,并在调用之间将其状态保存在一个表中?SQL Server种子rand()是如何实现的?它是否真的是随机的,或者如果您在不同的连接上在1或2毫秒内调用sp,它是否会被播种相同的种子,从而导致冲突?
发布于 2009-11-02 01:03:38
如果您使用的是SQL Server2008,那么可以使用CRYPT_GEN_RANDOM()函数。这将使每一行的数据随机化,即使您试图在一次查询执行中计算数百万个随机数,并且没有任何种子问题:
SELECT CAST(RIGHT(CAST(CAST(CRYPT_GEN_RANDOM(1) AS INT) AS VARCHAR(100)), 1) AS INT)
以下是BOL文章的链接:
http://msdn.microsoft.com/en-us/library/cc627408.aspx
发布于 2009-11-02 00:00:59
在您的示例中,将rand()*10000
替换为ABS(CHECKSUM(NEWID())) % 9999
但是,对于char(9):
SELECT RIGHT('000000000' + CAST(ABS(CHECKSUM(NEWID()) % 999999999) AS char(9), 9)
随机播种兰德。
RAND(CHECKSUM(NEWID()))
编辑:
请注意,RAND在SQL Server中的实现很糟糕。不要用它。
发布于 2009-11-02 00:01:22
RAND() function有一个可选的种子参数,您可以为此使用该参数。如果将上一次生成的随机值作为种子传递给下一次调用rand(),则可以保证获得一个新的随机数。
感谢gbn指出种子是一个整数,而rand()返回一个浮点数。有了这些知识,下面是一个有效的示例!首先创建一个表:
create table RandomNumber (number float)
insert into RandomNumber values (rand())
然后抓取一个随机数并将新数存储在事务中:
declare @new float
begin transaction
select @new = rand(-2147483648 + 4294967295 * number)
from RandomNumber with (updlock, holdlock)
update RandomNumber set number = @new
commit transaction
print 'Next bingo number is: ' + cast(cast(@new*100 as int) as varchar)
SQL Server整数在-2147483648和2147483647之间变化,随机数是介于0.0和1.0之间的浮点数。因此,-2147483648 + 4294967295 * number
应该涵盖所有可用的整数。
该事务确保一次只有一个连接读取和存储新号码。因此,即使在不同的SQL Server连接上,这些数字也是随机的。(顺便说一句,我投票支持gbn的答案,似乎容易多了。)
https://stackoverflow.com/questions/1657474
复制相似问题