我表中的每一行都需要一个不同的随机数。以下看似显而易见的代码为每行使用了相同的随机值。
故事的其余部分是我将使用此随机数来创建相对于已知日期的随机日期偏移量,例如从开始日期起偏移1-14天。

这是用于Microsoft SQL Server2000。

评论

有没有不使用NEWID()的解决方案吗?我希望能够为给定的种子生成相同的随机数序列。

@Rory询问作为新问题,它将得到更多关注。 (我的答案是使用固定的随机数表,例如。例如,这个著名的随机数标准集:rand.org/pubs/monograph_reports/MR1418/index.html)

外观@ RAND(Transact-SQL)

RAND于2005年推出,2009年问这个问题,哪些组织仍在使用SQL 2000,因为那是第一个足以永久使用的版本。

Rory MacLeod问:“是否有不使用NEWID()的解决方案?我希望能够为给定种子生成相同的随机数序列。”答案是肯定的,但是有点令人费解。 1.创建一个返回select rand()的视图。2.创建一个从视图中选择值的UDF。 3.在选择数据之前,请为rand()函数设置种子。 4.在您的select语句中使用UDF。我将在下面发布完整示例

#1 楼

请看一下SQL Server-基于集合的随机数,其中有非常详细的解释。

总而言之,以下代码生成一个0到13之间(含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类型的实际范围要大得多……以至于在大多数情况下,几乎无法检测到偏差。但是,如果您发现自己这样做是为了获得严格的安全代码,这是要知道的。

评论


此链接页面具有解决方案:ABS(CHECKSUM(NewId()))%14

–马修·马丁(MatthewMartin)
09年6月25日在17:35

%14将返回0到13之间的数字

– CoderDennis
09年6月25日在17:39

@丹尼斯·帕尔默(Dennis Palmer),只需添加1

–KM。
09年6月25日在17:48

我们刚刚发现了一个天才的错误。因为校验和返回一个int,并且int的范围是-2 ^ 31(-2,147,483,648)到2 ^ 31-1(2,147,483,647),所以abs()函数可以返回溢出错误(如果结果恰好是-2,147,483,648) !机会显然很低,大约为40亿分之一,但是我们每天在〜1.8b的行表上运行它,所以它大约每周发生一次!解决的方法是在abs之前将校验和转换为bigint。

– EvilPuppetMaster
16年1月29日在1:11



我认为这应该说是“均匀分布”而不是“归一化分布”,每个数字都具有同等的可能性,而不是钟形曲线。“归一化”具有特定的数学含义。

–otherParker
17年5月20日在6:56



#2 楼

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

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

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


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

编辑以获取1到14之间的随机整数。

评论


您如何从GUID或VARBINARY中获得一个数字?我将更新问题以表明我希望输入一个整数。

–马修·马丁(MatthewMartin)
09年6月25日在17:26

您可以将其乘以一个数字并将其底数:),因此,如果要五位数,请乘以100000,然后转换为整数。丑陋,但足够简单。

–杰里米·史密斯(Jeremy Smyth)
09年6月25日在17:27

作为进一步的附录-您最多可以输入五位数字-如果要对其进行零填充,则必须使用char数据类型,并使用复制将零位填充至最多5位数字。

–杰里米·史密斯(Jeremy Smyth)
09年6月25日在17:28

如果使用天花板功能而不是地板,则不必添加1。

– PopeDarren
18-09-24在16:24

即使使用此方法,有时RAND()总是给我相同的结果。甚至更陌生,根据我使用它的次数,有时它会从正确的行为跳到错误的行为。我正在尝试实现一个RANNER INNER JOIN,并且如果我要求超过19(!!!)行,它将开始给我始终相同的结果...

–约翰内斯·温图(Johannes Wentu)
19年5月2日在14:18

#3 楼

RAND(CHECKSUM(NEWID()))


上面的代码将生成一个介于0和1之间(排除)的(伪)随机数。如果在选择中使用,由于种子值会针对每一行而变化,因此它将为每一行生成一个新的随机数(但是,不能保证每行都会生成一个唯一的数)。

结合上限10(产生数字1-10):

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


Transact-SQL文档:



CAST():https://docs.microsoft.com/zh-cn/sql/t-sql/functions/cast-and-convert-transact-sql


RAND(): http://msdn.microsoft.com/zh-CN/library/ms177610.aspx


CHECKSUM():http://msdn.microsoft.com/zh-cn/library/ms189788 .aspx


NEWID():https://docs.microsoft.com/zh-cn/sql/t-sql/functions/newid-transact-sql

>

#4 楼

在1000和9999之间(包括1000和9999)的随机数生成:

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


“ +1”-包括上限值(前面的示例为9999)

评论


上限是此方法所独有的,因此,如果要包括顶部数字,则需要执行FLOOR(RAND(CHECKSUM(NEWID()))*(10000-1000)+1000)

–vaindil
18年7月23日在15:36

#5 楼

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

SQL Server 2008中引入了一个新功能,使用CryptoAPI生成具有加密强度的随机数的CRYPT_GEN_RANDOM(8),返回为VARBINARY(8000)。这是文档页面:https://docs.microsoft.com/zh-cn/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


评论


很好,实际上,当您担心NEWID()会变低或在语义上不合适时,或者只是需要ABS(CAST(CRYPT_GEN_RANDOM(4)AS INT))中的正整数。

–dakab
20-10-15在6:47

#6 楼

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

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


从这里获取信息,可以很好地说明问题。

#7 楼

您是否可以在每行中都有一个整数值,可以将其作为种子传递给RAND函数?

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

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


评论


从理论上讲,这是可行的,但是在实践中,我发现RAND()对于的细微变化似乎并不是很随机。例如,我做了一个快速测试:我让为184380、184383、184386,相应的RAND()值为:0.14912、0.14917、0.14923。

– ImaginaryHuman072889
19-10-21在11:53

也许要获得更多“看似”随机结果,请尝试以下操作:RAND()* 100000)-FLOOR(RAND()* 100000)

– ImaginaryHuman072889
19-10-21在12:01

#8 楼

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

1。创建一个返回选择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


#9 楼

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

评论


最简单!尽管这些值看起来更分散,但使用中间的数字,例如RIGHT(CONVERT(BIGINT,RAND(RecNo)* 1000000000000),2)(注意:我看到RIGHT将BIGINT隐式转换为CHAR,但是为严格起见,您将需要在其中进行另一个转换)。

–Doug_Ivison
2015年11月11日17:06



#10 楼

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

SELECT table_name, newid() magic_number 
FROM information_schema.tables


#11 楼

您需要为每一行调用RAND()。这是一个很好的例子

https://web.archive.org/web/20090216200320/http://dotnet.org.za/calmyourself/archive/2007/04/13/sql-rand -trap-same-value-per-row.aspx

评论


无效链接:(是否可以将所有副本包​​含在答案中?

– jocull
14-10-15在18:14

他将RAND()放入视图中,将该视图的SELECT放入函数中,然后从任何地方调用该函数。聪明。

–Doug_Ivison
2015年11月11日在16:55



我发布了一种解决方案,该解决方案与链接文章中所述的解决方案完全相同,但是在此博客中,五个帖子之前直接作为答案!没人叫我聪明嫉妒的脸呵呵

– Mitselplik
16年6月5日在3:57

#12 楼

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


这里的随机数在20到30之间。
round的最大值为两位小数。

如果您想使用负数,可以这样做使用

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


,则最小值将为-60,最大值将为-50。

#13 楼

就像这样简单:

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


#14 楼

有时,与选定的“答案”有关的问题是分布并不总是均匀的。如果您需要在许多行之间非常均匀地分配随机数1-14,则可以执行以下操作(我的数据库有511个表,因此可以使用。如果行数少于随机数跨度,则不起作用很好):

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


这种方法与正常随机解法相反,它可以保持数字顺序并随机化另一列。

请记住,我的数据库中有511个表(仅与我们从information_schema中选择的b / c有关)。如果我接受上一个查询并将其放在临时表#X中,然后对所得数据运行此查询:

我的随机数非常均匀地分布在许多行中:



#15 楼

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


一直为我工作

#16 楼

使用newid()

select newid()


或可能使用此

select binary_checksum(newid())


#17 楼

    DROP VIEW IF EXISTS vwGetNewNumber;
    GO
    Create View vwGetNewNumber
    as
    Select CAST(RAND(CHECKSUM(NEWID())) * 62 as INT) + 1 as NextID,
    'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'as alpha_num;

    ---------------CTDE_GENERATE_PUBLIC_KEY -----------------
    DROP FUNCTION IF EXISTS CTDE_GENERATE_PUBLIC_KEY;  
    GO
    create function CTDE_GENERATE_PUBLIC_KEY()
    RETURNS NVARCHAR(32)
    AS 
    BEGIN
        DECLARE @private_key NVARCHAR(32);
        set @private_key = dbo.CTDE_GENERATE_32_BIT_KEY();
        return @private_key;
    END;
    go

---------------CTDE_GENERATE_32_BIT_KEY -----------------
DROP FUNCTION IF EXISTS CTDE_GENERATE_32_BIT_KEY;  
GO
CREATE function CTDE_GENERATE_32_BIT_KEY()
RETURNS NVARCHAR(32)
AS 
BEGIN
    DECLARE @public_key NVARCHAR(32);
    DECLARE @alpha_num NVARCHAR(62);
    DECLARE @start_index INT = 0;
    DECLARE @i INT = 0;
    select top 1 @alpha_num = alpha_num from vwGetNewNumber;
        WHILE @i < 32
        BEGIN
          select top 1 @start_index = NextID from vwGetNewNumber;
          set @public_key = concat (substring(@alpha_num,@start_index,1),@public_key);
          set @i = @i + 1;
        END;
    return @public_key;
END;
    select dbo.CTDE_GENERATE_PUBLIC_KEY() public_key;


评论


对不起@arnt,如果我没有很好地解释,

– ichak khoury
18年6月28日在7:02

抱歉@arnt,我们这里有两个函数CTDE_GENERATE_32_BIT_KEY生成一个32位的字母数字密钥(可以扩展为更多或更少),另一个函数叫CTDE_GENERATE_PUBLIC_KEY,它调用第一个函数并返回32位的公钥,或者您可以返回16位的私钥...您只需要调用select dbo.CTDE_GENERATE_PUBLIC_KEY()作为公钥;背后的逻辑是,我们从字母数字字符列表中选择32个字符,然后将它们连接在一起以获得随机的字母数字键。经过研究。

– ichak khoury
18年6月28日在7:13

真好这种解释使其成为更好的答案。 (有人将其标记为删除;我投票决定将其保留为打开状态,并为您保留该评论。)

–arnt
18年6月28日在7:15

#18 楼

Update my_table set my_field = CEILING((RAND(CAST(NEWID() AS varbinary)) * 10))


1到10之间的数字。

#19 楼

试试这个:

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


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

评论


您能否在回答问题时变得更加清晰?

–尤努斯·特穆伦克(Yunus Temurlenk)
20-2-12在13:18