创建0到1之间的可重现随机数(SQL Server 2008)

时间:2014-01-29 18:36:03

标签: sql sql-server sql-server-2008 random

我正在试图弄清楚如何在我的一个表中为每个记录(行)分配一个在SQL Server 2008中0到1之间的唯一编号(值)。我已经查看了rand(校验和(newid()) )类型方法,这似乎是合适的,除了我需要我的一组值是可重现的(即如果我多次运行相同的查询,我会得到相同的随机值)。

知道如何解决这个问题吗?

3 个答案:

答案 0 :(得分:1)

就像在评论中已经提到过的那样,你可以获得随机数或你得到的“某些”数字,这些数字看起来是随机的,但每次都可以重新创建。

如果你只需要0或1,你可以做这样的事情。

SELECT ABS(CONVERT(BIGINT, HASHBYTES('SHA1', name)) % 2)
FROM sys.objects

通过使用Mudolo %函数,您将只获得0,1,-1。比你用ABS绝对值包装它只得到1和0.

我希望这会让你朝着正确的方向前进。您可以在此处了解HASHBYTES此处http://technet.microsoft.com/en-us/library/ms174415.aspx,您可以尝试使用不同的可用算法。

答案 1 :(得分:1)

您需要一次循环一行,以获得每行的不同随机值。为了确保每次都是相同的随机序列,选择一个固定的种子,然后用该种子调用RAND(种子)一次。之后对RAND()的每次调用(在同一个会话中)将为您提供该种子的序列号,并且将始终为给定的种子生成相同的序列。

有不同的循环方式(例如使用光标),但这里有一个让你入门。

create table RandomValues
(
    Id  int,
    RandomValue float
)
go

-- Pick a value and always use the same one to get reproducible random numbers
declare @FixedSeed int
set @FixedSeed = 100

declare @Id int
declare @MaxId int

select @MaxId = MAX(Id), @Id = MIN(Id) from OriginalData

-- You don't need this value for anything, you just need a call to rand(@FixedSeed) 
-- to start the sequence with the fixed seed
declare @dummyseed float
set @dummyseed = rand(@FixedSeed)

while (@Id <= @MaxId)
  begin
    insert RandomValues
    select Id, rand()
    from   OriginalData
    where   Id = @Id

    -- Get the next Id from the original table
    select  @Id = MIN(Id)
    from    OriginalData
    where   Id > @Id
end

select od.*, rv.RandomValue 
from RandomValues rv
join OriginalData od on rv.Id = od.Id

答案 2 :(得分:0)

正如许多人已经建议的那样,随机数的查找表怎么样。如果主表具有整数键,则可以使用以下代码生成合适的查找表;

;with t as (
   select 1 as i 
   union all 
   select i + 1 
   from t 
   where i < 1000) -- adjust accordingly
select 
   i, 
   cast(abs(checksum(newid())) / 2147483647.0 as float) as r -- the RAND function returns a float.
into dbo.RandomNumbers
from 
   t 
option(maxrecursion 0)

如果您不想沿着查找路线走下去,那么您需要一个能够返回可重复随机数的函数。我尝试了一些不同的东西并提出了rand(checksum(i,1.0/i))。它仍然需要一个整数键。

;with t as (
   select 1 as i 
   union all 
   select i+1 
   from t 
   where i<1000) -- adjust accordingly
select 
   i, 
   rand(checksum(i,1.0/i)) as r
from 
   t 
option(maxrecursion 0)

请注意,上述两个想法都没有解决您问题的独特方面,我没有分析数字的分布情况,但这些数字的重要程度取决于您的工作。

里斯