2012-03-10 34 views
16

Tôi mới đến máy chủ sql. Tôi cần tạo các ngày ngẫu nhiên được chọn từ một phạm vi ngày cụ thể. Giống như ngày làm việc của một nhân viên nên ở bất cứ đâu giữa 2011-01-012011-12-31. Các ngày tạo ra sẽ được chèn vào một bảng hàng 1000 ngẫu nhiên.Làm thế nào để chèn 1000 ngày ngẫu nhiên giữa một phạm vi nhất định?

Có thể bất kỳ ai hướng dẫn tôi truy vấn của tôi không?

Trả lời

5

Tôi có viết thư cho bạn chức năng này đơn giản mà trả về một ngày ngẫu nhiên giữa phạm vi ngày:

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 

để gọi hàm:

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

bạn có thể kết hợp chức năng với một máy phát điện hàng:

;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 

CHỈNH SỬA

Để tạo số ngẫu nhiên sử dụng:

RAND(CHECKSUM(NEWID())) 

thay vì RAND()

EDITED II 'sử dụng không hợp lệ của một nhà điều hành phụ ảnh hưởng '

Chức năng lợi nhuận rand' vòng một lỗi chức năng '. Điều này là bởi vì chúng ta không thể sử dụng các hàm không xác định như RAND() hoặc NEWID().

Một cách giải quyết là để create a view like:

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

và sau đó sử dụng nó trong chức năng:

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

hoặc đơn giản không sử dụng các chức năng và viết expresion trên chọn. Tôi đã viết một chức năng chỉ yo giải thích từng bước các solucion.

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 

Bạn có thể test here this query.

+1

Phiên bản nào của SQL Server để bạn sử dụng? Tôi đã thử nghiệm trong SQL Server 2012 và có 'Sử dụng không hợp lệ toán tử tác dụng phụ 'rand' trong một hàm.'. –

+0

Cảm ơn @MikaelEriksson, tôi đã sửa lỗi truy vấn. Trân trọng. – danihp

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

Vâng, tôi biết rằng đây là một câu hỏi cũ, nhưng nó đã được liên kết từ một phiên bản mới hơn như vậy ... Dưới đây là 2 xu của tôi:

  1. bảng cơ sở dữ liệu đang được phân loại bởi thiên nhiên.
  2. Chỉ có 365 ngày có thể trong một năm nhất định, 366 nếu đó là năm nhuận.
  3. Dữ liệu trùng lặp là dấu hiệu của thiết kế kém.

Dựa trên những cơ sở này, tôi tin rằng thực sự không cần lưu trữ 1000 ngày ngẫu nhiên trong bảng, khi chỉ có thể lưu trữ ngày có liên quan và chỉ cần chọn số hàng nhu cầu.

Trước tiên, lưu trữ dữ liệu bên trong bảng. bạn có thể sử dụng một số Tally table để tạo phạm vi ngày có liên quan.
Bảng Tally là một bảng chứa một dãy số. vì lợi ích của đối số, giả sử bạn đã tạo bảng kiểm đếm các số từ 0 đến 1.000.000.
You can check this link cho là cách tốt nhất để tạo ra một, cá nhân tôi thích phương pháp này:

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

Bây giờ bạn có bảng Tally, nó khá đơn giản để tạo ra một lịch:

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) 
) 

Bây giờ bạn có lịch và bảng kiểm đếm, khá đơn giản để sử dụng cả hai để có được bất kỳ số lượng bản ghi nào theo bất kỳ thứ tự nào bạn muốn. Một nghìn ngày được sắp xếp ngẫu nhiên? không có vấn đề:

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

Full kịch bản, bao gồm việc tạo và thả các bảng tổng sắp mất ít hơn một giây để thực hiện:

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

Dude, có 365 ngày trong một năm, không phải 356: D – Yura

+0

@Yura corret. hơi khó hiểu ... –

+0

Meh! Có rất chắc chắn 8 ngày trong tuần của tôi, hoặc vì vậy ông chủ của tôi sẽ cho tôi tin ... – Paul

Các vấn đề liên quan