如何在给定范围之间插入1000个随机日期?

时间:2012-03-10 09:26:49

标签: sql sql-server-2008

我是sql server的新手。我需要生成从给定日期范围中选择的随机日期。 与雇员的雇佣日期一样,应该在2011-01-012011-12-31之间的任何地方。生成的日期应随机插入1000行表中。

任何人都能指导我查询吗?

4 个答案:

答案 0 :(得分:38)

declare @FromDate date = '2011-01-01'
declare @ToDate date = '2011-12-31'

select dateadd(day, 
               rand(checksum(newid()))*(1+datediff(day, @FromDate, @ToDate)), 
               @FromDate)

答案 1 :(得分:6)

您可以简单地使用此查询。

DATEADD(DAY, ABS(CHECKSUM(NEWID()) % 364 ), '2011-01-01')

如果您要添加其他时间轴的日期,可以更改01-01-2011364364等于您要添加的天数。在这种情况下,它介于01-01-201131-12-2011之间 (31-12-2011也包括在内。)

例如,假设您要在2018-01-012018-01-31之间添加随机日期,您可以像这样更改查询。

DATEADD(DAY, ABS(CHECKSUM(NEWID()) % 31), '2018-01-01')

要插入(一行/日期),只需使用此...

DECLARE @rdate DATE = DATEADD(DAY, ABS(CHECKSUM(NEWID()) % 31), '2018-01-01')

INSERT INTO TableName ([DateColumn])
VALUES (@rdate);

输出

+-----+------------+
| ID  | DateColumn |
+-----+------------+
| 01  | 2018-01-21 |
+-----+------------+

在线演示:SQLFiddle.com

一次插入1000行......

DECLARE @rdate DATE
DECLARE @startLoopID INT = 1
DECLARE @endLoopID INT = 1000 -- Rows you want to add

WHILE @startLoopID <= @endLoopID
BEGIN
    SET @rdate = DATEADD(DAY, ABS(CHECKSUM(NEWID()) % 364 ), '2011-01-01');
    SET @startLoopID = @startLoopID + 1;

    INSERT INTO TableName ([DateColumn])
    VALUES (@rdate);
END

输出

+--------+------------+
|  ID    | DateColumn |
+--------+------------+
| 10000  | 2010-04-07 |
| 10001  | 2010-07-29 |
| 10002  | 2010-11-18 |
| 10003  | 2010-05-27 |
| 10004  | 2010-01-31 |
| 10005  | 2010-08-26 |
|   ˅    |     ˅      |
| 20000  | 2010-06-26 |
+--------+------------+

在线演示:SQLFiddle.com

更新现有行...

UPDATE TableName
SET [DateColumn] = DATEADD(DAY, ABS(CHECKSUM(NEWID()) % 364 ), '2011-01-01')
WHERE condition;

在线演示:SQLFiddle.com

答案 2 :(得分:5)

我已经写了这个简单的函数,它返回日期范围之间的随机日期:

create function date_rand ( @fromDate date, @toDate date) returns date
as
begin

 declare @days_between int
 declare @days_rand int

 set @days_between = datediff(day,@fromDate,@toDate)
 set @days_rand  = cast(RAND()*10000 as int)  % @days_between

 return dateadd( day, @days_rand, @fromDate )
end

调用函数:

select dbo.date_rand( '1/1/2001', '10/1/2001' )

您可以将功能与行生成器结合使用:

;WITH Nbrs_3( n ) AS ( SELECT 1 UNION SELECT 0 ),
Nbrs_2( n ) AS ( SELECT 1 FROM Nbrs_3 n1 CROSS JOIN Nbrs_3 n2 ),
Nbrs_1( n ) AS ( SELECT 1 FROM Nbrs_2 n1 CROSS JOIN Nbrs_2 n2 ),
Nbrs_0( n ) AS ( SELECT 1 FROM Nbrs_1 n1 CROSS JOIN Nbrs_1 n2 ),
Nbrs ( n ) AS ( SELECT 1 FROM Nbrs_0 n1 CROSS JOIN Nbrs_0 n2 )
SELECT dbo.date_rand( '1/1/2001', '10/1/2001' )
FROM ( SELECT ROW_NUMBER() OVER (ORDER BY n)
FROM Nbrs ) D ( n )
WHERE n <= 1000 

<强> EDITED

要生成随机数,请使用:

RAND(CHECKSUM(NEWID()))

而不是RAND()

EDITED II

函数返回'在函数'错误中无效使用副作用运算符'rand'。这是因为我们不能使用非确定性函数,如RAND()或NEWID()。

解决方法是create a view like

create view myRandomNumber as 
select cast( RAND(CHECKSUM(NEWID()))*1000 as int) as new_rand

然后在函数中使用它:

...
select @days_rand  = new_rand  % @days_between from myRandomNumber
...

或简单不要使用该函数并在select上写expresion。我只写了一个函数,你一步一步解释解决方案。

declare @fromdate date
declare @todate date
set @fromdate = '1/1/2001'
set @todate = '10/1/2001'
;WITH Nbrs_3( n ) AS ( SELECT 1 UNION SELECT 0 ),
Nbrs_2( n ) AS ( SELECT 1 FROM Nbrs_3 n1 CROSS JOIN Nbrs_3 n2 ),
Nbrs_1( n ) AS ( SELECT 1 FROM Nbrs_2 n1 CROSS JOIN Nbrs_2 n2 ),
Nbrs_0( n ) AS ( SELECT 1 FROM Nbrs_1 n1 CROSS JOIN Nbrs_1 n2 ),
Nbrs ( n ) AS ( SELECT 1 FROM Nbrs_0 n1 CROSS JOIN Nbrs_0 n2 )
SELECT 
   dateadd( day, 
            cast( RAND(CHECKSUM(NEWID()))*1000 as int) % 
                         datediff(day,@fromDate,@toDate), 
            @fromDate )
FROM ( SELECT ROW_NUMBER() OVER (ORDER BY n)
FROM Nbrs ) D ( n )
WHERE n <= 1000 

你可以test here this query

答案 3 :(得分:0)

嗯,我知道这是一个老问题,但它是从一个较新的问题链接所以...这是我的2美分:

  1. 数据库表本质上是未分类的。
  2. 某一年只有365个可能的日期,如果是闰年则为366个。
  3. 重复数据是设计不佳的标志。
  4. 基于这些前提,我认为实际上并不需要在表中存储1000个随机日期,而只能存储相关日期,只需选择行数和您需要的任何顺序。 / p>

    首先,将数据存储在表中。您可以使用Tally table创建相关的日期范围 Tally表是包含一系列数字的表。为了论证,让我们假设您已经创建了0到1,000,000之间的数字计数表 You can check this link创建一个人的最佳方式,我个人喜欢这种方法:

    -- create the tally table
    SELECT TOP 100000  IDENTITY (int ,0, 1) as num 
    INTO Tally 
    FROM sys.sysobjects 
    CROSS JOIN sys.all_columns
    

    现在您已拥有Tally表,创建日历非常简单:

    DECLARE @FromDate datetime = GETDATE(), 
            @ToDate datetime = DATEADD(YEAR, 1, GETDATE()) -- a year from now in my example
    
    ;With CalendarCTE AS
    (
    SELECT DATEADD(DAY, num, @FromDate) As caneldarDate 
    FROM Tally
    WHERE num < DATEDIFF(DAY, @FromDate, @ToDate) 
    )
    

    现在您已拥有日历和计数表,使用它们可以非常简单地获得您想要的任何顺序的任意数量的记录。 一千个随机排序的日期?没问题:

    SELECT TOP 1000 caneldarDate
    FROM CalendarCTE c
    CROSS JOIN Tally t 
    WHERE t.num < 1000
    ORDER BY NEWID()
    

    完整脚本,包括创建和删除计数表,执行时间不到一秒:

    -- create the tally table
    SELECT TOP 100000  IDENTITY (int ,0, 1) as num 
    INTO Tally 
    FROM sys.sysobjects 
    CROSS JOIN sys.all_columns
    
    -- crealte the calendar cte:
    DECLARE @FromDate datetime = GETDATE(), 
            @ToDate datetime = DATEADD(YEAR, 1, GETDATE())
    
    ;With CalendarCTE AS
    (
    SELECT DATEADD(DAY, num, @FromDate) As caneldarDate 
    FROM Tally
    WHERE num < DATEDIFF(DAY, @FromDate, @ToDate) 
    )
    
    -- select a 1000 random dates
    SELECT TOP 1000 caneldarDate
    FROM CalendarCTE c
    CROSS JOIN Tally t 
    WHERE t.num < 1000
    ORDER BY NEWID()
    
    -- cleanup
    DROP TABLE Tally