2012-03-10 71 views
16

我是新來的sql服務器。我需要生成從給定日期範圍中選擇的隨機日期。 像僱員的僱用日期應該在2011-01-012011-12-31之間的任何地方。生成的日期應該隨機地插入1000行的表中。如何在給定範圍之間插入1000個隨機日期?

任何人都可以引導我與我的查詢?

回答

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()或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 
... 

或簡單的不使用的功能和選擇寫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

+1

你用什麼版本的SQL Server?我在SQL Server 2012中進行了測試,並在函數中得到'無效的副作用運算符'rand'。「。 – 2012-03-10 10:21:13

+0

謝謝@MikaelEriksson,我已修復查詢。問候。 – danihp 2012-08-02 16:15:34

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

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

嗯,我知道這是一個老問題,但它是從一個較新的一個鏈接所以...這裏是我的2美分:

  1. 數據庫表的性質不排序。
  2. 某一年只有365個可能的日期,如果是閏年,則只有366個可能的日期。
  3. 重複的數據是設計不佳的標誌。

基於這些前提,我相信實際上並不需要在表中存儲1000個隨機日期,但只能存儲相關日期並只選擇多少行以及以任何順序需要。

首先,將數據存儲在表格中。您可以使用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 

現在,你有帳簿桌,這是相當簡單的創建日曆:

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 
+0

哥們,一年有365天,不是356:D – Yura 2016-02-15 19:30:09

+0

@Yura校正。有輕微的偏方... – 2016-02-16 08:49:16

+0

呃!我一週肯定有8天,或者老闆會讓我相信...... – Paul 2017-08-02 10:15:16

相關問題