选择特定范围内的随机日期

Nic*_*ssu 10 sql-server sql-server-2008

如何在特定的包含范围内选择一个随机日期,让我们用SQL Server说"1950-01-01"和"1999-12-31"?

ami*_*t_g 15

select DateAdd(d, ROUND(DateDiff(d, '1950-01-01', '1999-12-31') * RAND(), 0), '1950-01-01')
Run Code Online (Sandbox Code Playgroud)

编辑

如果要将其作为返回多行的语句的一部分执行或作为更新的一部分执行,则RAND()将返回整个结果集的单个值.对于这种情况,可以使用RAND(CHECKSUM(NEWID())).

select DateAdd(d, ROUND(DateDiff(d, '1950-01-01', '1999-12-31') * RAND(), 0), '1950-01-01'),
       DateAdd(d, ROUND(DateDiff(d, '1950-01-01', '1999-12-31') * RAND(CHECKSUM(NEWID())), 0), '1950-01-01')
from master..spt_values where type = 'P'
Run Code Online (Sandbox Code Playgroud)


Mar*_*ith 12

这将为您提供1000行要插入的数据.

DECLARE @D1 DATE = '19500101'
DECLARE @D2 DATE = '19991231'

   ;WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
        E02(N) AS (SELECT 1 FROM E00 a, E00 b),
        E04(N) AS (SELECT 1 FROM E02 a, E02 b),
        E08(N) AS (SELECT 1 FROM E04 a, E04 b),
        E16(N) AS (SELECT 1 FROM E08 a, E08 b),
        E32(N) AS (SELECT 1 FROM E16 a, E16 b),
   cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY N) FROM E32)
   SELECT TOP 1000
    DATEADD(DAY,ABS(CHECKSUM(NEWID())) % (1+DATEDIFF(DAY,@D1,@D2)),@D1)
   FROM  cteTally
Run Code Online (Sandbox Code Playgroud)

注意:这个答案最初用于ABS(CAST(CRYPT_GEN_RANDOM(4) AS INT))生成随机数.与RAND()每个语句仅评估一次相比,每行评估一次,因此可以工作.

但是,查询优化器似乎没有意识到这一点并将其视为常量.为了生成随机数据,这可能无关紧要(除非您填充受外键约束的列)

但我刚刚测试了替代方案ABS(CHECKSUM(NEWID())),看看是否有任何性能优势.

使用上面的数字表生成1,000,000行的典型速度并选择MAX值(以避免将所有这些行返回给客户端的开销)

ABS(CAST(CRYPT_GEN_RANDOM(4) AS INT))
/*CPU time = 4180 ms,  elapsed time = 4395 ms.*/

ABS(CHECKSUM(NEWID()))
/*CPU time = 953 ms,  elapsed time = 1163 ms.*/

(SELECT 1) /*A constant value just to get a baseline*/
/*CPU time = 499 ms,  elapsed time = 457 ms.*/
Run Code Online (Sandbox Code Playgroud)

因此,除非您需要加密安全的PRNG,否则最好避免!