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

发布于 2024-07-25 00:51:59 字数 290 浏览 3 评论 0原文

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

SELECT table_name, RAND() magic_number 
FROM information_schema.tables 

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

这是针对 Microsoft SQL Server 2000 的。

I need a different random number for each row in my table. The following seemingly obvious code uses the same random value for each row.

SELECT table_name, RAND() magic_number 
FROM information_schema.tables 

I'd like to get an INT or a FLOAT out of this. The rest of the story is I'm going to use this random number to create a random date offset from a known date, e.g. 1-14 days offset from a start date.

This is for Microsoft SQL Server 2000.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(21

醉南桥 2024-08-01 00:52:00

每行中是否有一个整数值可以作为种子传递给 RAND 函数?

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

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

Do you have an integer value in each row that you could pass as a seed to the RAND function?

To get an integer between 1 and 14 I believe this would work:

FLOOR( RAND(<yourseed>) * 14) + 1
浪漫之都 2024-08-01 00:52:00
select round(rand(checksum(newid()))*(10)+20,2)

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

如果你想要负数,你可以这样做

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

然后最小值将是-60,最大值将是-50。

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

Here the random number will come in between 20 and 30.
round will give two decimal place maximum.

If you want negative numbers you can do it with

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

Then the min value will be -60 and max will be -50.

夜吻♂芭芘 2024-08-01 00:52:00

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

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

If you need to preserve your seed so that it generates the "same" random data every time, you can do the following:

1. Create a view that returns 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. Create a UDF that selects the value from the view.

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. Before selecting your data, seed the rand() function, and then use the UDF in your select statement.

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
以酷 2024-08-01 00:52:00

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

try using a seed value in the RAND(seedInt). RAND() will only execute once per statement that is why you see the same number each time.

娇妻 2024-08-01 00:52:00

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

SELECT table_name, newid() magic_number 
FROM information_schema.tables

If you don't need it to be an integer, but any random unique identifier, you can use newid()

SELECT table_name, newid() magic_number 
FROM information_schema.tables
戏舞 2024-08-01 00:52:00

我有时对所选“答案”遇到的问题是分布并不总是均匀的。 如果您需要在很多行中非常均匀地分布随机 1 - 14,您可以执行类似的操作(我的数据库有 511 个表,因此这有效。如果您的行数少于随机数范围,则这不起作用好):

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

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

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

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

我得到此结果,显示我的随机数非常均匀地分布在许多行中:

在此处输入图像描述

The problem I sometimes have with the selected "Answer" is that the distribution isn't always even. If you need a very even distribution of random 1 - 14 among lots of rows, you can do something like this (my database has 511 tables, so this works. If you have less rows than you do random number span, this does not work well):

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

This kind of does the opposite of normal random solutions in the sense that it keeps the numbers sequenced and randomizes the other column.

Remember, I have 511 tables in my database (which is pertinent only b/c we're selecting from the information_schema). If I take the previous query and put it into a temp table #X, and then run this query on the resulting data:

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

I get this result, showing me that my random number is VERY evenly distributed among the many rows:

enter image description here

故事还在继续 2024-08-01 00:52:00

这很简单:

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

It's as easy as:

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

And this will put a random number between 0-99 into a table:

CREATE TABLE R
(
    Number int
)

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

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

SELECT * FROM R
悍妇囚夫 2024-08-01 00:52:00
select ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) as [Randomizer]

一直对我有用

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

has always worked for me

倾城泪 2024-08-01 00:52:00

使用 newid()

select newid()

或可能这

select binary_checksum(newid())

Use newid()

select newid()

or possibly this

select binary_checksum(newid())
未央 2024-08-01 00:52:00

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

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

或者

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

If you want to generate a random number between 1 and 14 inclusive.

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

OR

SELECT ABS(CHECKSUM(NewId())) % (14 -1) + 1
蓝色星空 2024-08-01 00:52:00
    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;
    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;
£烟消云散 2024-08-01 00:52:00
Update my_table set my_field = CEILING((RAND(CAST(NEWID() AS varbinary)) * 10))

1 到 10 之间的数字。

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

Number between 1 and 10.

菊凝晚露 2024-08-01 00:52:00

试试这个:

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

其中 a 是较小的数字,b 是较大的数字

Try this:

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

Where a is the lower number and b is the upper number

束缚m 2024-08-01 00:52:00

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

;WITH A AS (
        SELECT 1 X, RAND() R
    UNION ALL
        SELECT X + 1, RAND(R*100000) --Change the seed
        FROM A
        WHERE X < 1000 --How many random numbers you need
    )
SELECT
    X
    , RAND_BETWEEN_1_AND_14 = FLOOR(R * 14 + 1)
FROM A
OPTION (MAXRECURSION 0) --If you need more than 100 numbers

If you need a specific number of random number you can use recursive CTE:

;WITH A AS (
        SELECT 1 X, RAND() R
    UNION ALL
        SELECT X + 1, RAND(R*100000) --Change the seed
        FROM A
        WHERE X < 1000 --How many random numbers you need
    )
SELECT
    X
    , RAND_BETWEEN_1_AND_14 = FLOOR(R * 14 + 1)
FROM A
OPTION (MAXRECURSION 0) --If you need more than 100 numbers
爺獨霸怡葒院 2024-08-01 00:51:59

看看 SQL Server - 基于随机数的设置,其中有非常详细的解释。

总而言之,以下代码生成一个 0 到 13 之间(含)的均匀分布随机数:

ABS(CHECKSUM(NewId())) % 14

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

对房间里的数学迷的一个小警告:这段代码中有一个非常轻微的偏差。 CHECKSUM() 产生的数字在 sql Int 数据类型的整个范围内是统一的,或者至少与我(编辑器)测试所显示的接近。 但是,当 CHECKSUM() 生成位于该范围最顶端的数字时,将会出现一些偏差。 每当您获得最大可能整数和最大整数之前所需范围大小的最后一个精确倍数(在本例中为 14)之间的数字时,这些结果都会优先于无法生成的范围的剩余部分最后一个是 14 的倍数。

举个例子,假设 Int 类型的整个范围只有 19。19 是您可以容纳的最大整数。 当 CHECKSUM() 结果为 14-19 时,这些对应于结果 0-5。 这些数字比 6-13 更受青睐,因为 CHECKSUM() 生成它们的可能性是 6-13 的两倍。 从视觉上证明这一点更容易。 下面是我们的假想整数范围的整个可能结果集:

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 类型的实际范围要大得多……以至于在大多数情况下偏差几乎无法检测到。 但是,如果您发现自己为严格的安全代码这样做,则需要注意这一点。

Take a look at SQL Server - Set based random numbers which has a very detailed explanation.

To summarize, the following code generates a random number between 0 and 13 inclusive with a uniform distribution:

ABS(CHECKSUM(NewId())) % 14

To change your range, just change the number at the end of the expression. Be extra careful if you need a range that includes both positive and negative numbers. If you do it wrong, it's possible to double-count the number 0.

A small warning for the math nuts in the room: there is a very slight bias in this code. CHECKSUM() results in numbers that are uniform across the entire range of the sql Int datatype, or at least as near so as my (the editor) testing can show. However, there will be some bias when CHECKSUM() produces a number at the very top end of that range. Any time you get a number between the maximum possible integer and the last exact multiple of the size of your desired range (14 in this case) before that maximum integer, those results are favored over the remaining portion of your range that cannot be produced from that last multiple of 14.

As an example, imagine the entire range of the Int type is only 19. 19 is the largest possible integer you can hold. When CHECKSUM() results in 14-19, these correspond to results 0-5. Those numbers would be heavily favored over 6-13, because CHECKSUM() is twice as likely to generate them. It's easier to demonstrate this visually. Below is the entire possible set of results for our imaginary integer range:

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

You can see here that there are more chances to produce some numbers than others: bias. Thankfully, the actual range of the Int type is much larger... so much so that in most cases the bias is nearly undetectable. However, it is something to be aware of if you ever find yourself doing this for serious security code.

超可爱的懒熊 2024-08-01 00:51:59

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

我建议使用 Convert(varbinary,newid()) 作为种子参数:

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

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

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

When called multiple times in a single batch, rand() returns the same number.

I'd suggest using convert(varbinary,newid()) as the seed argument:

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

newid() is guaranteed to return a different value each time it's called, even within the same batch, so using it as a seed will prompt rand() to give a different value each time.

Edited to get a random whole number from 1 to 14.

霓裳挽歌倾城醉 2024-08-01 00:51:59
RAND(CHECKSUM(NEWID()))

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

与上限 10 组合时的示例(生成数字 1 - 10):

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

Transact-SQL 文档:

  1. CAST()https://learn.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://learn.microsoft.com /en-us/sql/t-sql/functions/newid-transact-sql
RAND(CHECKSUM(NEWID()))

The above will generate a (pseudo-) random number between 0 and 1, exclusive. If used in a select, because the seed value changes for each row, it will generate a new random number for each row (it is not guaranteed to generate a unique number per row however).

Example when combined with an upper limit of 10 (produces numbers 1 - 10):

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

Transact-SQL Documentation:

  1. CAST(): https://learn.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://learn.microsoft.com/en-us/sql/t-sql/functions/newid-transact-sql
还给你自由 2024-08-01 00:51:59

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

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

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

Random number generation between 1000 and 9999 inclusive:

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

"+1" - to include upper bound values(9999 for previous example)

心在旅行 2024-08-01 00:51:59

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

SQL Server 2008 中引入了一个新函数 CRYPT_GEN_RANDOM(8)​​,它使用 CryptoAPI 生成加密的强随机数,返回为 VARBINARY(8000)。 这是文档页面:https: //learn.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

Answering the old question, but this answer has not been provided previously, and hopefully this will be useful for someone finding this results through a search engine.

With SQL Server 2008, a new function has been introduced, CRYPT_GEN_RANDOM(8), which uses CryptoAPI to produce a cryptographically strong random number, returned as VARBINARY(8000). Here's the documentation page: https://learn.microsoft.com/en-us/sql/t-sql/functions/crypt-gen-random-transact-sql

So to get a random number, you can simply call the function and cast it to the necessary type:

select CAST(CRYPT_GEN_RANDOM(8) AS bigint)

or to get a float between -1 and +1, you could do something like this:

select CAST(CRYPT_GEN_RANDOM(8) AS bigint) % 1000000000 / 1000000000.0
绝不放开 2024-08-01 00:51:59

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

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

获取信息这里很好地解释了这个问题。

The Rand() function will generate the same random number, if used in a table SELECT query. Same applies if you use a seed to the Rand function. An alternative way to do it, is using this:

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

Got the information from here, which explains the problem very well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文