Ответ 1
declare @FromDate date = '2011-01-01'
declare @ToDate date = '2011-12-31'
select dateadd(day,
rand(checksum(newid()))*(1+datediff(day, @FromDate, @ToDate)),
@FromDate)
Я новичок в sql-сервере. Мне нужно создать случайные даты, выбранные из заданного диапазона дат.
Как и дата найма сотрудника, он должен находиться где-то между 2011-01-01
и 2011-12-31
. Сгенерированные даты следует вставлять в таблицу 1000 строк случайным образом.
Может ли кто-нибудь помочь мне с моим запросом?
declare @FromDate date = '2011-01-01'
declare @ToDate date = '2011-12-31'
select dateadd(day,
rand(checksum(newid()))*(1+datediff(day, @FromDate, @ToDate)),
@FromDate)
Вы можете просто использовать этот запрос.
DATEADD(DAY, ABS(CHECKSUM(NEWID()) % 364 ), '2011-01-01')
Если вы хотите добавить даты из другой временной шкалы, вы можете изменить 01-01-2011
и 364
. 364
равно дням, которые вы хотите добавить. В этом случае это между 01-01-2011
и 31-12-2011
.
(31-12-2011
также включен.)
Например, допустим, вы хотите добавить случайную дату между 2018-01-01
и 2018-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
Я пишу вам эту простую функцию, которая возвращает случайную дату между диапазоном дат:
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 view myRandomNumber as
select cast( RAND(CHECKSUM(NEWID()))*1000 as int) as new_rand
а затем используйте его в функции:
...
select @days_rand = new_rand % @days_between from myRandomNumber
...
или просто не использовать функцию и писать выражение при выборе. Я написал функцию только для объяснения шаг за шагом решения.
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
Вы можете проверить здесь этот запрос.
Ну, я знаю, что это старый вопрос, но он был связан с более новым, так что... Вот мои 2 цента:
Основываясь на этих предпосылках, я считаю, что на самом деле нет необходимости хранить 1000 случайных дат в таблице, когда возможно сохранить только соответствующую дату и просто выбрать, сколько строк и в любом порядке вам нужно.
Сначала сохраните данные внутри таблицы. вы можете использовать таблицу Tally, чтобы создать соответствующий диапазон дат.
Таблица Tally - это таблица, содержащая последовательность чисел. ради аргумента, предположим, что вы уже создали свою таблицу подсчета чисел от 0 до 1 000 000.
Вы можете проверить эту ссылку, чтобы наилучшим образом ее создать, лично мне нравится этот метод:
-- 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()
Полный script, включая создание и отбрасывание таблицы таллинга, занял меньше секунды, чтобы выполнить:
-- 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