How can I select a random date from a date range in SQL server. I basically want to do RandRange() for dates in sql? Does that make sense?
I have to admit, this one totally stumped me at first. I rarely work with random data in SQL. If I need random data I usually just build a query in ColdFusion. I tried looking up random methods for SQL, but it turns out that things like RAND() are only called once per table, NOT per row. I got some great ideas from Jon Galloway over at http://weblogs.asp.net/jgalloway/archive/2004/03/18/92498.aspx. He supplied the way to come up with a random date:
- cast( getdate() as int )
- -5 * rand( cast( cast( newid() as binary(8) ) as int ) )
- as datetime
I am not exactly sure what the casting of the UUID to a binary(8) does, but I see that it converts to an integer.
After some experimentation, I see that casting UUIDs to binary can result in either a negative or positive number. For a date range, I needed to work with a positive number. Therefor I use ABS() to force a positive outcome. Once we have that, all we need is the date range part. That's where our old friend date-math comes in. You can think of a random date from a date range as adding a random number of days to the start date (>= 0) such that the resultant date does not exceed the end range date.
Once you think about it that way, we have all the pieces we need:
- -- First, let's declare the date range. I am declaring this
- -- here for the demo, but this could be done anyway you like.
- DECLARE @date_from DATETIME;
- DECLARE @date_to DATETIME;
- -- Set the start and date dates. In this case, we are using
- -- the month of october, 2006.
- SET @date_from = '2006-10-01';
- SET @date_to = '2006-10-30';
- -- Select random dates.
- -- Remember, we want to add a random number to the
- -- start date. In SQL we can add days (as integers)
- -- to a date to increase the actually date/time
- -- object value.
- @date_from +
- -- This will force our random number to be GTE 0.
- -- This will give us a HUGE random number that
- -- might be negative or positive.
- CAST( NewID() AS BINARY(8) )
- AS INT
- -- Our random number might be HUGE. We can't have
- -- exceed the date range that we are given.
- -- Therefore, we have to take the modulus of the
- -- date range difference. This will give us between
- -- zero and one less than the date range.
- -- To get the number of days in the date range, we
- -- can simply substrate the start date from the
- -- end date. At this point though, we have to cast
- -- to INT as SQL will not make any automatic
- -- conversions for us.
- (@date_to - @date_from)
- AS INT
Hope that helps.
Looking For A New Job?
- Full Time ColdFusion Developer Needed at the Beach at InterCoastal Net Designs
- Senior Coldfusion Developer at The Toolkit Group
- Senior Application Developer (Coldfusion) at American Access Casualty Company
- Front end engineer - AngularJS focus at Corbis
- Senior Web Application Developer at SiteVision, Inc.
Just wanted to say thanks for this post, it was exactly what I was after!
Glad to help.
Great post. Thanks a lot!
Hey how about including a random time in that date time as well?
This works as well.
select DATEADD(second, rand()*86400, DATEADD(d, rand()*(CAST((@date_to - @date_from) AS INT )), @date_from))
86400, being the number of seconds in a day.
Thanks! This script helped me a lot in trying to generate a buncha test data where we're tracking stats based on unique datetimes.
Nice code and great explanation.
Thank you for that.
Here's a slightly modified version... selecting a random time during an 8hr period during a particular day. (28800 is the number of seconds in 8 hours.) I send the NEWID() through RAND() to guarantee a unique timestamp for each row.
DECLARE @date_from DATETIME;
DECLARE @date_to DATETIME;
SET @date_from = '2009-06-29 08:00:00.000';
SET @date_to = '2009-06-29 16:00:00.000';
SELECT DATEADD(second, RAND(ABS(CAST(CAST(NewID() AS BINARY(8)) AS INT)))*28800, DATEADD(d, RAND(ABS(CAST(CAST(NewID() AS BINARY(8)) AS INT)))*(CAST((@date_to - @date_from) AS INT )), @date_from))
That's a cool idea. A bit hard to read here, but I think I get the point.
How would I add random seconds to each row in MS Access
Very good code. It worked fine, the only thing that I have to check is the Date Format, as my SQL Server 2005 is in Portuguese I had to change the format to YYYY-DD-MM
I did it like that
random date betweem 1-9-2009 to 29-1-2010
(between 0 to 150 days)
DECLARE @RandomNumber float
DECLARE @RandomDayF int
DECLARE @MaxDay int
DECLARE @MinDay int
SET @MaxDay = 150
SET @MinDay = 0
-- random the number of days to add
SELECT @RandomNumber = RAND()
set @randomDayF = ((@MaxDay + 1) - @MinDay) * @RandomNumber + @MinDay
-- add the days
Set @FromDate = (select DATEADD(d, @randomDayF,(SELECT convert(datetime, '1-9-2009',105)))) -- dd-mm-yyyy
--to reduce days
-- @randomDayF = @randomDayF * -1
Wow- awesome work guys , it has helped me alot..
thank you very much!!
I used this sample to generate random number from 1 to 1000000000
amazingly it produce 9-digit most of the time
I want it to generate more like 1,2,3,..9-digit
actually I need it in a lottery app
any other suggestion I'll appreciate it