Многократные вставки SQL с RAND - как изменить значение RAND - PullRequest
0 голосов
/ 20 октября 2018

У меня есть оператор, который вставляет значения в таблицу на основе случайного значения и другого значения

INSERT INTO TRAINER_SYNC (Steps, TrainerId, SyncDate)
SELECT AverageSteps * (RAND()*(1.15-0.85)+0.85), Id, GETDATE()
FROM TRAINER

Это работает нормально, но всякий раз, когда два "Тренера" ​​имеют одинаковые "AverageSteps",число, вставленное в таблицу, всегда одинаково.

Например, если средние шаги всех тренеров равны 10000, здесь результат в таблице TRAINER_SYNC

Id  TrainerId   SyncDate                    Steps
10  1           2018-10-20 18:42:16.407     9482
11  2           2018-10-20 18:42:16.407     9482
12  3           2018-10-20 18:42:16.407     9482
13  4           2018-10-20 18:42:16.407     9482
14  5           2018-10-20 18:42:16.407     9482
15  6           2018-10-20 18:42:16.407     9482
16  7           2018-10-20 18:42:16.407     9482
17  8           2018-10-20 18:42:16.407     9482
18  9           2018-10-20 18:42:16.407     9482

Есть ли способ заставить RAND() в операторе вставки быть более ... "случайным"?Я не уверен, как он называется, но сбрасываю начальное начальное значение, чтобы каждая итерация вставки давала мне другое случайное значение?

Ответы [ 2 ]

0 голосов
/ 20 октября 2018

rand() - это особый класс функций, который оценивается ровно один раз для каждого вызова в операторе SQL.Это может быть очень запутанным, потому что:

select rand(), rand()

возвращает два разных значения.Однако

select rand(), rand()
from (values (1), (2), (3)) v(x)

возвращает три строки - с одинаковыми двумя значениями в каждой из строк.Это «особенность» оптимизации SQL Server.Я полагаю, что getdate() (и аналогичные функции даты / времени) являются единственными другими функциями с таким поведением.

Нормальным решением является заполнение генератора случайных чисел с помощью newid().Но типы возврата различны, поэтому checksum() используется для преобразования id в число:

INSERT INTO TRAINER_SYNC (Steps, TrainerId, SyncDate)
    SELECT AverageSteps * (RAND(CHECKSUM(NEWID()))*(1.15-0.85)+0.85), 
           Id, GETDATE()
    FROM TRAINER;

. Вы можете использовать другое начальное число, если оно доступно.Например, если на одного тренера идет только одна строка, вы можете использовать rand(id).Я должен отметить, что rand() не особенно "случайен" с семенами, поэтому смежные семена часто дают похожие числа.

Возможно, вам не следует устанавливать GETDATE() в INSERT.Вы можете создать таблицу с помощью:

SyncDate datetime default getdate()

Таким образом, значением по умолчанию является время вставки.

0 голосов
/ 20 октября 2018

вы можете использовать

1) RAND(CHECKSUM(NEWID()))

ИЛИ

2)

INSERT INTO TRAINER_SYNC (Steps, TrainerId, SyncDate)
    SELECT AverageSteps * (RAND(AverageSteps)*(1.15-0.85)+0.85), Id, GETDATE()
    FROM TRAINER
...