【问题标题】:SQL Server random using seedSQL Server 随机使用种子
【发布时间】:2014-11-10 09:55:01
【问题描述】:

我想使用种子向我的表中添加一个带有随机数的列。 如果我使用兰德:

select *, RAND(5) as random_id from myTable

我在 random_id 列中得到所有行的相等值(例如 0.943597390424144)。我希望每一行的这个值都不同 - 并且每次我将传递 0.5 值(例如),它都会再次成为相同的值(因为种子应该可以工作......)。

我该怎么做?

( 比如在PostrgreSql中我可以写

SELECT setseed(0.5); SELECT t.* , random() as random_id FROM myTable t

我会在每一行中得到不同的值。 )


编辑:

在我看到这里的 cmets 之后,我设法以某种方式解决了这个问题 - 但它根本没有效率。 如果有人知道如何改进它 - 它会很棒。如果没有 - 我将不得不另谋出路。

我使用了here中示例的基本思想。

使用空白种子值创建临时表

select * into t_myTable  from (
select t.*, -1.00000000000000000 as seed
       from myTable t
       ) as temp

为每个种子值添加一个随机数,一次一行(这是不好的部分......):

USE CPatterns;
GO
DECLARE @seed float;
DECLARE @id int;
DECLARE VIEW_CURSOR CURSOR FOR
select id
from t_myTable t;
OPEN VIEW_CURSOR;
FETCH NEXT FROM VIEW_CURSOR
into @id;
set @seed = RAND(5);

WHILE @@FETCH_STATUS = 0
   BEGIN
      set @seed = RAND();
         update t_myTable set seed = @seed where id = @id

      FETCH NEXT FROM VIEW_CURSOR
         into @id;

   END;
CLOSE VIEW_CURSOR;
DEALLOCATE VIEW_CURSOR;
GO

创建视图使用种子值并按其排序

create view my_view AS 
select row_number() OVER (ORDER BY seed, id) AS  source_id ,t.*
       from t_myTable t

【问题讨论】:

  • AFIK 你不能模仿setseed 的行为,即始终产生相同的随机数,但要为每一行获得不同的随机数,而不是重复相同的随机数,你可以使用RAND(CHECKSUM(NEWID())) - 例如- SELECT RAND(CHECKSUM(NEWID())) FROM sys.all_objects
  • @GarethD,我必须始终如一地产生相同的随机数 - 所以我发布了更新,请看一下。
  • 我有点困惑。您的示例使用 rand(0.5),但在 SQL Server 中,rand() 仅采用整数种子。
  • @Gordon Linoff... 对不起,我试图与 PostgreSql 示例保持一致,因此我也更改了 SQL Server 的值。我已经编辑了问题。

标签: sql sql-server random random-seed


【解决方案1】:

有人建议使用 newid() 进行类似的查询,但我正在为您提供适合我的解决方案。

有一种解决方法涉及 newid() 而不是 rand,但它会给您相同的结果。您可以单独执行它,也可以将其作为一列中的一列执行。它将导致每行的随机值,而不是 select 语句中每一行的相同值。 如果您需要一个 0 - N 的随机数,只需将 100 更改为所需的数字即可。

SELECT TOP 10 [Flag forca]
,1+ABS(CHECKSUM(NEWID())) % 100 AS RANDOM_NEWID
,RAND() AS  RANDOM_RAND
FROM PAGSEGURO_WORK.dbo.jobSTM248_tmp_leitores_iso

【讨论】:

    【解决方案2】:

    你可以从种子中转换一个随机数:

    rand(row_number over (order by ___, ___,___))
    

    然后将其转换为 varchar , 然后使用最后 3 个字符作为另一个种子。 这会给你一个很好的随机值:

    rand(right(cast(rand(row_number() over(x,y,x)) as varchar(15)), 3)
    

    【讨论】:

      【解决方案3】:

      所以,万一有一天有人会这样做,这就是我最终所做的。

      我在服务器端生成随机种子值(在我的例子中是 Java),然后创建一个包含两列的表:id 和生成的 random_id。 现在我将视图创建为表和原始数据之间的inner join

      生成的 SQL 如下所示:

      CREATE TABLE SEED_DATA(source_id INT PRIMARY KEY, random_id float NOT NULL);
      select Rand(5); 
      insert into SEED_DATA values(1,Rand());
      insert into SEED_DATA values(2, Rand());
      insert into SEED_DATA values(3, Rand());
      .
      .
      .
      insert into SEED_DATA values(1000000, Rand());
      

      CREATE VIEW DATA_VIEW
      as  
          SELECT row_number() OVER (ORDER BY random_id, id) AS source_id,column1,column2,...
          FROM 
              ( select * from SEED_DATA tmp 
                inner join my_table i on tmp.source_id = i.id) TEMP 
      

      另外,我分批创建随机数,每批10,000个左右(可能更高),所以它不会对服务器端造成太大影响,并且对于每批我将它插入到单独的表中执行。

      所有这一切都是因为我找不到纯粹在 SQL 中做我想做的事的好方法。逐行更新确实效率不高。

      我自己从这个故事中得出的结论是,SQL Server 有时真的很烦人......

      【讨论】:

        【解决方案4】:

        我认为在表中获取可重复随机 id 的最简单方法是在每一行上使用row_number() 或固定的id。假设您有一个名为 id 的列,每行的值不同。

        这个想法只是将其用作种子:

        select rand(id*1), as random_id
        from mytable;
        

        请注意,id 的种子是整数而不是浮点数。如果你想要一个浮点种子,你可以使用checksum()

        select rand(checksum(id*0.5)) as random_id
        . . .
        

        如果您这样做是为了采样(例如,对于 10% 的样本,您会说 random_id < 0.1,那么我经常在 row_number() 上使用模运算:

        with t as (
              select t.* row_number() over (order by id) as seqnum
              from mytable t
             )
        select *
        from t
        where ((seqnum * 17 + 71) % 101) < 0.1
        

        这会返回大约 10% 的数字(好吧,真的是 10/101)。您可以通过摆弄常量来调整样本。

        【讨论】:

        • 嗨,问题是我想使用种子/随机数进行排序。我试过select rand(id*1), as random_id from mytable;。但它对订购没有帮助 - 因为看起来 RAND(1)
        • @yishaiz 。 . .我不知道 SQL Server 以这种方式被破坏了。非常感谢您指出这一点。至少,伪随机生成器应该可以工作。
        • 伪随机发生器对我来说不够用,所以我发布了更新,请看一下。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-09
        • 1970-01-01
        • 1970-01-01
        • 2021-07-28
        • 2016-08-12
        • 2016-10-07
        相关资源
        最近更新 更多