通过在T-SQL中设置种子,从均匀分布生成随机值

kak*_*sat 10 t-sql sql-server random random-seed

我想从均匀分布中生成随机值,其中对于T-SQL中给定数​​据表的每一行,mean = 0和标准devation = 1.另外,我想设置种子以确保分析的可重复性.以下是不起作用的想法:

  1. 使用RAND()具有声明数字的函数不能实现此目标:为数据集的每一行生成相同的随机值.

  2. 这样的解决方案:

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

由于它不可再现,因此无法解决问题.

编辑:

由于我的表有数亿条记录,因此性能很重要.

chr*_*uae 4

Rand() 函数可以在开始时通过向其传递一个整数种子值来进行播种。如果在生成任何随机数之前执行此操作一次,则随机数序列将是可重复的。单独生成值将确保 Rand() 函数按顺序返回数字。以下将产生n 个伪随机数的均匀分布,平均值 = 0,标准差 = 1:

    DECLARE @Mean    FLOAT = 0.0; 
    DECLARE @stDev   FLOAT = 1.0; 
    DECLARE @n   INT = 100000;   -- count of random numbers to generate
    DECLARE @U   TABLE(x FLOAT); -- table of random numbers

    DECLARE @SEED    INT = 123456;    -- seed to ensure list is reproducible
    SELECT RAND(@Seed);

    SET NOCOUNT ON;
    BEGIN TRAN
    DECLARE @x INT = 0; -- counter
    WHILE @x < @n
      BEGIN
      INSERT INTO @U (x)
        SELECT @Mean + (2 * SQRT(3) * @stDev) * (RAND() - 0.5)
      SET @x = @x + 1;
      END;
    COMMIT

-- Check the results    
    SELECT * from @U;

    SELECT AVG([@U].x) AS mean,
        STDEV([@U].x) AS stDev
        FROM @U;
Run Code Online (Sandbox Code Playgroud)

您可以使用游标循环遍历现有表中的记录并对每条记录执行更新,而不是在 while 循环中插入临时表。正如评论中提到的,性能可能是一个问题,但它满足“均值 = 0 且标准差 = 1 的均匀分布”“再现性”的要求。Rand() 函数的工作方式强制进行“1 by 1”更新。

下面是一个替代 Rand() 函数的替代方案,它具有更好的性能(应该在 2 秒内运行 100 万行)。这允许在单个记录中更新记录UPDATE,但依赖于ID表中的唯一数字字段并更新名为 的字段RandomNumber。Rand() 函数被替换为( (ID * @SEED ) % 1000 ) / 1000可能可以改进的函数。

DECLARE @Mean    FLOAT = 0.0; 
DECLARE @stDev   FLOAT = 1.0; 
DECLARE @SEED numeric(18,0)    = 1234567890.0;    -- seed to ensure list is reproducible

SET NOCOUNT ON;
BEGIN TRAN
UPDATE TestTable
   set Randomnumber = @Mean + (2 * SQRT(3) * @stDev) * (( (ID * @SEED ) % 1000 ) / 1000 - 0.5) 
COMMIT
-- Check the results    
SELECT AVG(RandomNumber) AS mean,
    STDEV(RandomNumber ) AS stDev
    FROM TestTable;
Run Code Online (Sandbox Code Playgroud)