2011-04-01 83 views
10

如何在特定的包含范围内选择随机日期,比方说SQL Server的'1950-01-01'和'1999-12-31'?在特定范围内选择一个随机日期

+0

您是否试图在同一时间为多行生成数据,或者只是一个日期?我只是想知道你是否试图建立一些测试数据插入到表中。 – Jeff 2011-04-01 22:34:39

+0

嗨,杰夫。我需要一个范围内的随机日期,以便运行一个循环,并随机生成一个测试表。 :) – 2011-04-01 22:37:06

+0

你需要多少行数据? – 2011-04-01 22:39:19

回答

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 

注意:此答案最初使用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.*/ 

所以,除非你需要加密安全PRNG它可能最好避免!

+0

嗨马丁。非常感谢你。看起来,如果我想甚至'1992-12-31',我必须将@ d2声明为'2000-01-01',否则查询不包含最后一天。 – 2011-04-01 22:40:04

+0

@nick - 我已将其更改为“1 + DATEDIFF(DAY,@ D1,@ D2)”以解决该问题。 – 2011-04-01 22:43:25

+0

你简直太棒了:)谢谢你一直奉献我的时间。对此,我真的非常感激。再次感谢马丁。 – 2011-04-01 22:45:06

15
select DateAdd(d, ROUND(DateDiff(d, '1950-01-01', '1999-12-31') * RAND(), 0), '1950-01-01') 

编辑

如果这是要为返回多行或更新的一部分,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' 
+0

这似乎是随机选择1/1/1950或12/31/1999,但不是在两者之间的任何日期。 – JustinStolle 2011-04-01 22:36:25

+0

嗨。感谢您的回复。我试过了你的查询,但它总是返回已经写入的那两个值中的一个。 – 2011-04-01 22:41:21

+0

+1现在效果很好。谢谢;) – 2011-04-02 00:00:47

相关问题