首页 文章

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

提问于
浏览
269

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

SELECT table_name, RAND() magic_number 
FROM information_schema.tables

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

这适用于Microsoft SQL Server 2000 .

17 回答

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

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

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

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

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

  • 11

    看看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

    在单个批处理中多次调用时,rand()返回相同的数字 .

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

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

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

    编辑从1到14得到一个随机整数 .

  • 61
    RAND(CHECKSUM(NEWID()))
    

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

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

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

    Transact-SQL文档:

  • 5

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

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

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

  • 2

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

    在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
    
  • 27

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

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

    here获得了信息,这很好地解释了问题 .

  • 1

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

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

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

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

    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
    
  • 85

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

  • 1

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

    SELECT table_name, newid() magic_number 
    FROM information_schema.tables
    
  • 2

    选择newid()

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

  • 3

    我选择的“答案”有时会遇到的问题是分布并不总是均匀 . 如果你需要在很多行之间非常均匀地分配随机的1 - 14,你可以做这样的事情(我的数据库有511个表,所以这很有用 . 如果你的行数少于你的随机数 Span ,这不起作用好):

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

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

    记住,我的数据库中有511个表(只有b / c才能从information_schema中选择) . 如果我将上一个查询放入临时表#X中,然后对结果数据运行此查询:

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

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

    enter image description here

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

    一直为我工作

  • 4
    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;
    
  • 14

    它很简单:

    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
    

相关问题