如何为TSQL选择中的每一行生成随机数?

时间:2009-06-25 17:17:35

标签: sql-server tsql sql-server-2000

我的表中每行需要一个不同的随机数。以下看似明显的代码对每行使用相同的随机值。

SELECT table_name, RAND() magic_number 
FROM information_schema.tables 

我想从中获得INT或FLOAT。故事的其余部分是我将使用这个随机数来创建一个已知日期的随机日期偏移,例如从开始日期偏离1-14天。

这适用于Microsoft SQL Server 2000。

21 个答案:

答案 0 :(得分:453)

查看SQL Server - Set based random numbers,其中有一个非常详细的解释。

总而言之,以下代码生成0到13之间的随机数,包括规范化分布:

ABS(CHECKSUM(NewId())) % 14

要更改范围,只需更改表达式末尾的数字即可。如果您需要包含正数和负数的范围,请格外小心。如果你做错了,可以重复数字0。

房间里数学螺母的小警告:此代码中有一个非常小的偏差。 CHECKSUM()会导致整个sql Int数据类型范围内的数字一致,或者至少接近我的(编辑器)测试可以显示的数字。但是,当CHECKSUM()在该范围的最高端产生一个数字时,会有一些偏差。每次在最大可能整数和所需范围大小的最后一个精确倍数(在这种情况下为14)之间得到一个数字之前,这个结果优于你的范围的剩余部分,而不能从这是14的最后一个。

例如,假设Int类型的整个范围仅为19. 19是您可以容纳的最大可能整数。当CHECKSUM()得到14-19时,这些对应于结果0-5。这些数字将超过6-13 ,因为CHECKSUM()生成它们的可能性是其两倍。更直观地展示这一点。下面是我们想象的整数范围的整个可能结果集:

Checksum Integer: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Range Result:     0 1 2 3 4 5 6 7 8 9 10 11 12 13  0  1  2  3  4  5

你可以在这里看到,产生一些数字的机会比其他数字更多:偏见。值得庆幸的是,Int类型的实际范围很多更大......以至于在大多数情况下偏差几乎检测不到。但是,如果您发现自己为严肃的安全代码执行此操作,则需要注意这一点。

答案 1 :(得分:87)

当在一个批次中多次调用时,rand()返回相同的数字。

我建议使用convert(varbinarynewid())作为种子参数:

SELECT table_name, 1.0 + floor(14 * RAND(convert(varbinary, newid()))) magic_number 
FROM information_schema.tables

newid()保证每次调用时返回不同的值,即使在同一批次中也是如此,因此将其用作种子将提示rand()每次都给出不同的值。

编辑从1到14获得随机整数。

答案 2 :(得分:65)

RAND(CHECKSUM(NEWID()))

以上将生成0到1之间的(伪)随机数,不包括。如果在select中使用,因为每行的种子值发生变化,它将为每一行生成一个新的随机数(但不保证每行生成一个唯一的数字)。

当上限为10(产生数字1 - 10)时的示例:

CAST(RAND(CHECKSUM(NEWID())) * 10 as INT) + 1

Transact-SQL文档:

  1. CAST()https://docs.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql
  2. RAND()http://msdn.microsoft.com/en-us/library/ms177610.aspx
  3. CHECKSUM()http://msdn.microsoft.com/en-us/library/ms189788.aspx
  4. NEWID()https://docs.microsoft.com/en-us/sql/t-sql/functions/newid-transact-sql

答案 3 :(得分:34)

1000到9999之间的随机数生成:

FLOOR(RAND(CHECKSUM(NEWID()))*(9999-1000+1)+1000)

“+ 1” - 包括上限值(前一个例子为9999)

答案 4 :(得分:17)

回答旧问题,但之前没有提供此答案,希望这对通过搜索引擎找到此结果的人有用。

使用SQL Server 2008,引入了一个新功能CRYPT_GEN_RANDOM(8),它使用CryptoAPI生成加密强随机数,返回为VARBINARY(8000)。这是文档页面:https://docs.microsoft.com/en-us/sql/t-sql/functions/crypt-gen-random-transact-sql

因此,要获得一个随机数,您只需调用该函数并将其转换为必要的类型:

select CAST(CRYPT_GEN_RANDOM(8) AS bigint)

要获得介于-1和+1之间的float,您可以执行以下操作:

select CAST(CRYPT_GEN_RANDOM(8) AS bigint) % 1000000000 / 1000000000.0

答案 5 :(得分:11)

如果在表SELECT查询中使用,Rand()函数将生成相同的随机数。如果您将种子用于Rand函数,则同样适用。另一种方法是使用它:

SELECT ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) AS [RandomNumber]

here获取信息,这可以很好地解释问题。

答案 6 :(得分:5)

如果您需要保留种子以便每次都生成“相同”的随机数据,您可以执行以下操作:

<强> 1。创建一个返回select rand()

的视图
if object_id('cr_sample_randView') is not null
begin
    drop view cr_sample_randView
end
go

create view cr_sample_randView
as
select rand() as random_number
go

<强> 2。创建一个从视图中选择值的UDF。

if object_id('cr_sample_fnPerRowRand') is not null
begin
    drop function cr_sample_fnPerRowRand
end
go

create function cr_sample_fnPerRowRand()
returns float
as
begin
    declare @returnValue float
    select @returnValue = random_number from cr_sample_randView
    return @returnValue
end
go

第3。在选择数据之前,请为rand()函数设定种子,然后在select语句中使用UDF。

select rand(200);   -- see the rand() function
with cte(id) as
(select row_number() over(order by object_id) from sys.all_objects)
select 
    id,
    dbo.cr_sample_fnPerRowRand()
from cte
where id <= 1000    -- limit the results to 1000 random numbers

答案 7 :(得分:5)

您是否可以在每行中将整数值作为种子传递给RAND函数?

要获得1到14之间的整数,我相信这会起作用:

FLOOR( RAND(<yourseed>) * 14) + 1

答案 8 :(得分:4)

答案 9 :(得分:4)

如果您不需要它是整数,但任何随机唯一标识符,您可以使用newid()

SELECT table_name, newid() magic_number 
FROM information_schema.tables

答案 10 :(得分:4)

尝试在RAND(seedInt)中使用种子值。 RAND()每个语句只执行一次,这就是每次看到相同数字的原因。

答案 11 :(得分:4)

select round(rand(checksum(newid()))*(10)+20,2)

这里的随机数将在20到30之间。 round最多会给出两位小数。

如果您想要负数,可以使用

进行
select round(rand(checksum(newid()))*(10)-60,2)

然后最小值为-60,最大值为-50。

答案 12 :(得分:3)

如果你想生成一个 1 到 14 之间的随机数。

SELECT CONVERT(int, RAND() * (14 - 1) + 1)

SELECT ABS(CHECKSUM(NewId())) % (14 -1) + 1

答案 13 :(得分:2)

我选择的“答案”中有时遇到的问题是分布并不总是均匀。如果你需要在很多行中随机分配1到14个非常均匀的东西,你可以做这样的事情(我的数据库有511个表,所以这个工作。如果你的行数少于随机数跨度,这不起作用孔):

SELECT table_name, ntile(14) over(order by newId()) randomNumber 
FROM information_schema.tables

这种方法与正常的随机解决方案相反,它保持数字排序并随机化另一列。

请记住,我的数据库中有511个表(仅与我们从information_schema中选择的b / c相关)。如果我将之前的查询放入临时表#X中,然后对结果数据运行此查询:

select randomNumber, count(*) ct from #X
group by randomNumber

我得到了这个结果,告诉我我的随机数非常均匀地分布在很多行中:

enter image description here

答案 14 :(得分:2)

选择newid()

或者可能选择binary_checksum(newid())

答案 15 :(得分:2)

select ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) as [Randomizer]

一直对我有用

答案 16 :(得分:2)

这很容易:

DECLARE @rv FLOAT;
SELECT @rv = rand();

这会将一个0-99之间的随机数放入表格中:

CREATE TABLE R
(
    Number int
)

DECLARE @rv FLOAT;
SELECT @rv = rand();

INSERT INTO dbo.R
(Number)
    values((@rv * 100));

SELECT * FROM R

答案 17 :(得分:1)

|AusID|ProjectId|
+-----+----------
|529  |20124    |
|876  |20123    |
|521  |20234    |
|982  |21235    |

答案 18 :(得分:0)

更新my_table设置my_field = CEILING((RAND(CAST(NEWID()AS varbinary))* 10))

1到10之间的数字。

答案 19 :(得分:0)

尝试一下:

SELECT RAND(convert(varbinary, newid()))*(b-a)+a magic_number 

其中a是较低的数字,而b是较高的数字

答案 20 :(得分:0)

如果您需要特定数量的随机数,您可以使用递归 CTE:

StackLayout